@@ -13,133 +13,67 @@ import androidx.compose.material.icons.filled.CheckCircle
1313import androidx.compose.material.icons.filled.Warning
1414import androidx.compose.material3.*
1515import androidx.compose.runtime.*
16- import androidx.compose.runtime.getValue
17- import androidx.compose.runtime.saveable.rememberSaveable
1816import androidx.compose.ui.Alignment
1917import androidx.compose.ui.Modifier
2018import androidx.compose.ui.draw.alpha
2119import androidx.compose.ui.graphics.Color
2220import androidx.compose.ui.graphics.ImageBitmap
23- import androidx.compose.ui.graphics.Shape
2421import androidx.compose.ui.graphics.asImageBitmap
2522import androidx.compose.ui.layout.ContentScale
2623import androidx.compose.ui.platform.LocalContext
2724import androidx.compose.ui.res.stringResource
2825import androidx.compose.ui.unit.dp
26+ import androidx.lifecycle.compose.collectAsStateWithLifecycle
2927import androidx.navigation.NavController
3028import com.darkrockstudios.app.securecamera.ConfirmDeletePhotoDialog
3129import com.darkrockstudios.app.securecamera.R
3230import com.darkrockstudios.app.securecamera.camera.PhotoDef
3331import com.darkrockstudios.app.securecamera.camera.SecureImageManager
3432import com.darkrockstudios.app.securecamera.navigation.AppDestinations
35- import com.darkrockstudios.app.securecamera.preferences.AppPreferencesManager
36- import com.darkrockstudios.app.securecamera.sharePhotosData
37- import kotlinx.coroutines.*
33+ import com.darkrockstudios.app.securecamera.ui.HandleUiEvents
34+ import kotlinx.coroutines.CoroutineDispatcher
35+ import kotlinx.coroutines.CoroutineScope
36+ import kotlinx.coroutines.Dispatchers
37+ import kotlinx.coroutines.launch
38+ import org.koin.androidx.compose.koinViewModel
3839import org.koin.compose.koinInject
3940
4041@OptIn(ExperimentalMaterial3Api ::class )
4142@Composable
4243fun GalleryContent (
4344 modifier : Modifier = Modifier ,
4445 navController : NavController ,
45- paddingValues : PaddingValues
46+ paddingValues : PaddingValues ,
47+ snackbarHostState : SnackbarHostState = remember { SnackbarHostState () }
4648) {
47- val imageManager = koinInject<SecureImageManager >()
48- val preferencesManager = koinInject<AppPreferencesManager >()
49- var photos by remember { mutableStateOf<List <PhotoDef >>(emptyList()) }
50- var isLoading by rememberSaveable { mutableStateOf(true ) }
5149 val context = LocalContext .current
52- val scope = rememberCoroutineScope()
53-
54- // Selection state
55- var isSelectionMode by rememberSaveable { mutableStateOf(false ) }
56- var selectedPhotos by rememberSaveable { mutableStateOf<Set <String >>(emptySet()) }
57- var showDeleteConfirmation by rememberSaveable { mutableStateOf(false ) }
58-
59- val sanitizeFileName by
60- preferencesManager.sanitizeFileName.collectAsState(preferencesManager.sanitizeFileNameDefault)
61- val sanitizeMetadata by
62- preferencesManager.sanitizeMetadata.collectAsState(preferencesManager.sanitizeMetadataDefault)
63-
64- // Function to toggle selection of a photo
65- val togglePhotoSelection = { photoName: String ->
66- selectedPhotos = if (selectedPhotos.contains(photoName)) {
67- selectedPhotos - photoName
68- } else {
69- selectedPhotos + photoName
70- }
50+ val viewModel: GalleryViewModel = koinViewModel()
51+ val uiState by viewModel.uiState.collectAsStateWithLifecycle()
7152
72- // If no photos are selected, exit selection mode
73- if (selectedPhotos.isEmpty()) {
74- isSelectionMode = false
75- }
76- }
77-
78- val startSelectionMode = { photoName: String ->
79- isSelectionMode = true
80- selectedPhotos = setOf (photoName)
53+ val startSelectionWithVibration = { photoName: String ->
54+ viewModel.startSelectionMode(photoName)
8155 vibrateDevice(context)
8256 }
8357
84- val clearSelection = {
85- isSelectionMode = false
86- selectedPhotos = emptySet()
87- }
88-
89- val handleDelete = {
90- showDeleteConfirmation = true
91- }
92-
93- val performDelete = {
94- val photoDefs = selectedPhotos.mapNotNull { imageManager.getPhotoByName(it) }
95- imageManager.deleteImages(photoDefs)
96- clearSelection()
97- photos = photos.filter { it !in photoDefs }
98- showDeleteConfirmation = false
99- }
100-
101- val handleShare = {
102- val photoDefs = selectedPhotos.mapNotNull { imageManager.getPhotoByName(it) }
103- if (photoDefs.isNotEmpty()) {
104- scope.launch(Dispatchers .IO ) {
105- sharePhotosData(
106- photos = photoDefs,
107- sanitizeName = sanitizeFileName,
108- sanitizeMetadata = sanitizeMetadata,
109- imageManager = imageManager,
110- context = context
111- )
112- withContext(Dispatchers .Main ) {
113- clearSelection()
114- }
115- }
116- }
117- }
118-
119- LaunchedEffect (Unit ) {
120- photos = imageManager.getPhotos().sortedByDescending { it.dateTaken() }
121- isLoading = false
122- }
123-
12458 Column (
12559 modifier = modifier
12660 .fillMaxSize()
12761 .background(MaterialTheme .colorScheme.background)
12862 ) {
12963 GalleryTopNav (
13064 navController = navController,
131- onDeleteClick = handleDelete ,
132- onShareClick = handleShare ,
133- isSelectionMode = isSelectionMode,
134- selectedCount = selectedPhotos.size,
135- onCancelSelection = clearSelection
65+ onDeleteClick = { viewModel.showDeleteConfirmation() } ,
66+ onShareClick = { viewModel.shareSelectedPhotos(context) } ,
67+ isSelectionMode = uiState. isSelectionMode,
68+ selectedCount = uiState. selectedPhotos.size,
69+ onCancelSelection = { viewModel. clearSelection() }
13670 )
13771
138- if (showDeleteConfirmation) {
72+ if (uiState. showDeleteConfirmation) {
13973 ConfirmDeletePhotoDialog (
140- selectedCount = selectedPhotos.size,
141- onConfirm = performDelete ,
142- onDismiss = { showDeleteConfirmation = false }
74+ selectedCount = uiState. selectedPhotos.size,
75+ onConfirm = { viewModel.deleteSelectedPhotos() } ,
76+ onDismiss = { viewModel.dismissDeleteConfirmation() }
14377 )
14478 }
14579
@@ -154,19 +88,18 @@ fun GalleryContent(
15488 .fillMaxSize(),
15589 contentAlignment = Alignment .Center
15690 ) {
157- if (isLoading) {
158- // Show a loading indicator or placeholder
91+ if (uiState.isLoading) {
15992 Text (text = stringResource(id = R .string.gallery_loading))
160- } else if (photos.isEmpty()) {
93+ } else if (uiState. photos.isEmpty()) {
16194 Text (text = stringResource(id = R .string.gallery_empty))
16295 } else {
16396 PhotoGrid (
164- photos = photos,
165- selectedPhotoNames = selectedPhotos,
166- onPhotoLongClick = startSelectionMode ,
97+ photos = uiState. photos,
98+ selectedPhotoNames = uiState. selectedPhotos,
99+ onPhotoLongClick = startSelectionWithVibration ,
167100 onPhotoClick = { photoName ->
168- if (isSelectionMode) {
169- togglePhotoSelection(photoName)
101+ if (uiState. isSelectionMode) {
102+ viewModel. togglePhotoSelection(photoName)
170103 } else {
171104 navController.navigate(AppDestinations .createViewPhotoRoute(photoName))
172105 }
@@ -175,6 +108,8 @@ fun GalleryContent(
175108 }
176109 }
177110 }
111+
112+ HandleUiEvents (viewModel.events, snackbarHostState, navController)
178113}
179114
180115@Composable
@@ -267,7 +202,9 @@ private fun PhotoItem(
267202 photo.photoName
268203 ),
269204 contentScale = ContentScale .Crop ,
270- modifier = Modifier .fillMaxSize().alpha(imageAlpha)
205+ modifier = Modifier
206+ .fillMaxSize()
207+ .alpha(imageAlpha)
271208 )
272209 } ? : run {
273210 Box (modifier = Modifier .fillMaxSize()) {
0 commit comments