Fix back behavior after deselecting all items in the gallery.

This commit is contained in:
Alex Hart
2026-08-10 16:32:55 -04:00
committed by Greyson Parrelli
parent 32aa72febe
commit 5fb3cae92c
5 changed files with 29 additions and 0 deletions
@@ -25,4 +25,5 @@ internal sealed interface MediaSendFlowEvent {
data class NavigateToFiles(val mediaFolder: MediaFolder) : MediaSendFlowEvent
data object NavigateToEdit : MediaSendFlowEvent
data object NavigateToCamera : MediaSendFlowEvent
data object NavigateBack : MediaSendFlowEvent
}
@@ -256,6 +256,25 @@ class MediaSendFlowViewModel(
is MediaSendFlowEvent.NavigateToFiles -> backStack.goToFiles(event.mediaFolder)
MediaSendFlowEvent.NavigateToEdit -> backStack.goToEdit()
MediaSendFlowEvent.NavigateToCamera -> backStack.goToCamera()
MediaSendFlowEvent.NavigateBack -> onPopFromSelect()
}
}
/**
* Backs out of a select screen while nothing is selected, stepping over an editor that would have nothing to edit
* and no toolbar to leave by. Decided here rather than when the selection empties, so that re-selecting something
* still returns the user to their editor.
*/
private fun onPopFromSelect() {
val destination = backStack.dropLast(1).dropLastWhile { it == MediaSendRoute.Edit }
if (destination.isEmpty()) {
sendHudCommand(MediaSendFlowHudCommand.CloseScreen)
return
}
while (backStack.size > destination.size) {
backStack.pop()
}
}
@@ -5,6 +5,7 @@
package org.signal.mediasend.screens.select
import androidx.activity.compose.BackHandler
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateDpAsState
@@ -129,6 +130,12 @@ internal fun MediaSelectScreen(
val gridState = rememberLazyGridState()
val dragToSelectState = rememberDragToSelectMediaState(state, onEvent, gridState)
// Only an empty selection can leave an editor with nothing to edit behind us. Every other back press is left to the
// navigation default, which keeps its predictive-back gesture.
BackHandler(enabled = state.selectedMedia.isEmpty()) {
onEvent(MediaSelectScreenEvents.NavigateBack)
}
// Once the selection starts refusing items there is nothing left for the drag to do, and letting it run on would
// raise a refusal for every further tile it crosses.
LaunchedEffect(state.isSelectionRejected) {
@@ -34,6 +34,7 @@ sealed interface MediaSelectScreenEvents {
data class ReorderSelectedMedia(val fromIndex: Int, val toIndex: Int) : MediaSelectScreenEvents
data object NavigateToEdit : MediaSelectScreenEvents
data object NavigateToCamera : MediaSelectScreenEvents
data object NavigateBack : MediaSelectScreenEvents
/** Re-read the gallery and the current permission level, e.g. after coming back from app settings. */
data object Refresh : MediaSelectScreenEvents
@@ -92,6 +92,7 @@ internal class MediaSelectViewModel(
is MediaSelectScreenEvents.ReorderSelectedMedia -> parentEventEmitter(MediaSendFlowEvent.ReorderSelectedMedia(event.fromIndex, event.toIndex))
MediaSelectScreenEvents.NavigateToEdit -> parentEventEmitter(MediaSendFlowEvent.NavigateToEdit)
MediaSelectScreenEvents.NavigateToCamera -> parentEventEmitter(MediaSendFlowEvent.NavigateToCamera)
MediaSelectScreenEvents.NavigateBack -> parentEventEmitter(MediaSendFlowEvent.NavigateBack)
MediaSelectScreenEvents.Refresh -> refresh()
MediaSelectScreenEvents.RequestMediaPermissions -> requestReadMediaPermissions(reportDenial = true)
MediaSelectScreenEvents.SelectMorePhotos -> requestReadMediaPermissions(reportDenial = false)