Make GalleryUiState derivations lazy and drop dead sorts
copy() ran on every state update (each drag-select step included) and eagerly recomputed five derived properties: two unused O(N log N) sorts, an O(N) selection filter, an O(N) selectable-URI set and its containsAll check. - Remove sortedPhotos/sortedSubfolders: never read (the screen sorts with its own remember() calls) - selectedPhotos/selectablePhotoUris/allPhotosSelected become by lazy: computed at most once per instance, only when actually read; body delegates stay out of generated copy()/equals(), @Immutable semantics hold - Memoize selectablePhotoUris across drag-select steps in the ViewModel keyed by photos list identity, so a drag step no longer recomputes the O(N) set
This commit is contained in:
1 parent
c2ddfdf89d
commit
76ea8ba9a0
1 file changed
+27
-15
@@ -95,22 +95,20 @@ data class GalleryUiState(
|
||||
val error: String? = null,
|
||||
) {
|
||||
val isSelectionMode: Boolean = selectedPhotoUris.isNotEmpty()
|
||||
val selectedPhotos: List<Photo> = photos.filter { it.uri.toString() in selectedPhotoUris }
|
||||
val sortedSubfolders: List<FolderNode> = if (sortAscending) {
|
||||
subfolders.sortedBy { it.name.lowercase() }
|
||||
} else {
|
||||
subfolders.sortedByDescending { it.name.lowercase() }
|
||||
|
||||
val selectedPhotos: List<Photo> by lazy {
|
||||
photos.filter { it.uri.toString() in selectedPhotoUris }
|
||||
}
|
||||
val sortedPhotos: List<Photo> = if (sortAscending) {
|
||||
photos.sortedBy { it.name.lowercase() }
|
||||
} else {
|
||||
photos.sortedByDescending { it.name.lowercase() }
|
||||
}
|
||||
val selectablePhotoUris: Set<String> = photos
|
||||
|
||||
val selectablePhotoUris: Set<String> by lazy {
|
||||
photos.asSequence()
|
||||
.filter { it.kind == GalleryFileKind.Photo }
|
||||
.map { it.uri.toString() }
|
||||
.toSet()
|
||||
val allPhotosSelected: Boolean = selectablePhotoUris.isNotEmpty() && selectedPhotoUris.containsAll(selectablePhotoUris)
|
||||
.mapTo(HashSet()) { it.uri.toString() }
|
||||
}
|
||||
|
||||
val allPhotosSelected: Boolean by lazy {
|
||||
selectablePhotoUris.isNotEmpty() && selectedPhotoUris.containsAll(selectablePhotoUris)
|
||||
}
|
||||
}
|
||||
|
||||
@HiltViewModel
|
||||
@@ -342,18 +340,31 @@ class GalleryViewModel @Inject constructor(
|
||||
|
||||
fun clearSelection() {
|
||||
dragSelectionBaseline = emptySet()
|
||||
dragSelectableCache = null
|
||||
uiState.value = uiState.value.copy(selectedPhotoUris = emptySet())
|
||||
}
|
||||
|
||||
private var dragSelectionBaseline: Set<String> = emptySet()
|
||||
|
||||
private var dragSelectableCache: Pair<List<Photo>, Set<String>>? = null
|
||||
|
||||
private fun currentSelectablePhotoUris(): Set<String> {
|
||||
val photos = uiState.value.photos
|
||||
dragSelectableCache?.let { (cachedPhotos, uris) ->
|
||||
if (cachedPhotos === photos) return uris
|
||||
}
|
||||
val uris = uiState.value.selectablePhotoUris
|
||||
dragSelectableCache = photos to uris
|
||||
return uris
|
||||
}
|
||||
|
||||
fun beginDragSelection(anchorUri: String) {
|
||||
dragSelectionBaseline = uiState.value.selectedPhotoUris + anchorUri
|
||||
uiState.value = uiState.value.copy(selectedPhotoUris = dragSelectionBaseline)
|
||||
}
|
||||
|
||||
fun updateDragSelection(rangeUris: Set<String>) {
|
||||
val selectable = uiState.value.selectablePhotoUris
|
||||
val selectable = currentSelectablePhotoUris()
|
||||
uiState.value = uiState.value.copy(
|
||||
selectedPhotoUris = dragSelectionBaseline + rangeUris.intersect(selectable),
|
||||
)
|
||||
@@ -361,6 +372,7 @@ class GalleryViewModel @Inject constructor(
|
||||
|
||||
fun endDragSelection() {
|
||||
dragSelectionBaseline = emptySet()
|
||||
dragSelectableCache = null
|
||||
}
|
||||
|
||||
fun zipSelectedPhotosAndShare() {
|
||||
|
||||
Reference in new issue
Block a user