Move bottom state to the View state

This commit is contained in:
Benoit Marty 2024-12-10 13:34:44 +01:00
parent db0bca9721
commit 36eceb75e8
6 changed files with 58 additions and 38 deletions

View file

@ -16,5 +16,8 @@ sealed interface MediaViewerEvents {
data object RetryLoading : MediaViewerEvents
data object ClearLoadingError : MediaViewerEvents
data class ViewInTimeline(val eventId: EventId) : MediaViewerEvents
data object OpenInfo : MediaViewerEvents
data class ConfirmDelete(val eventId: EventId) : MediaViewerEvents
data object CloseBottomSheet : MediaViewerEvents
data class Delete(val eventId: EventId) : MediaViewerEvents
}

View file

@ -11,11 +11,9 @@ import android.content.ActivityNotFoundException
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
@ -37,6 +35,7 @@ import io.element.android.libraries.matrix.api.timeline.item.event.toEventOrTran
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory
import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState
import io.element.android.libraries.mediaviewer.impl.local.LocalMediaActions
import io.element.android.libraries.ui.strings.CommonStrings
import kotlinx.coroutines.CoroutineScope
@ -78,15 +77,7 @@ class MediaViewerPresenter @AssistedInject constructor(
mediaFile.value?.close()
}
}
val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
val canDelete by produceState(false, syncUpdateFlow.value) {
value = when (inputs.mediaInfo.senderId) {
null -> false
room.sessionId -> room.canRedactOwn().getOrElse { false } && inputs.eventId != null
else -> room.canRedactOther().getOrElse { false } && inputs.eventId != null
}
}
var mediaBottomSheetState by remember { mutableStateOf<MediaBottomSheetState>(MediaBottomSheetState.Hidden) }
fun handleEvents(mediaViewerEvents: MediaViewerEvents) {
when (mediaViewerEvents) {
@ -95,10 +86,36 @@ class MediaViewerPresenter @AssistedInject constructor(
MediaViewerEvents.SaveOnDisk -> coroutineScope.saveOnDisk(localMedia.value)
MediaViewerEvents.Share -> coroutineScope.share(localMedia.value)
MediaViewerEvents.OpenWith -> coroutineScope.open(localMedia.value)
is MediaViewerEvents.Delete -> coroutineScope.delete(mediaViewerEvents.eventId)
is MediaViewerEvents.Delete -> {
mediaBottomSheetState = MediaBottomSheetState.Hidden
coroutineScope.delete(mediaViewerEvents.eventId)
}
is MediaViewerEvents.ViewInTimeline -> {
mediaBottomSheetState = MediaBottomSheetState.Hidden
navigator.onViewInTimelineClick(mediaViewerEvents.eventId)
}
MediaViewerEvents.OpenInfo -> coroutineScope.launch {
mediaBottomSheetState = MediaBottomSheetState.MediaDetailsBottomSheetState(
eventId = inputs.eventId,
canDelete = when (inputs.mediaInfo.senderId) {
null -> false
room.sessionId -> room.canRedactOwn().getOrElse { false } && inputs.eventId != null
else -> room.canRedactOther().getOrElse { false } && inputs.eventId != null
},
mediaInfo = inputs.mediaInfo,
thumbnailSource = inputs.thumbnailSource,
)
}
is MediaViewerEvents.ConfirmDelete -> {
mediaBottomSheetState = MediaBottomSheetState.MediaDeleteConfirmationState(
eventId = mediaViewerEvents.eventId,
mediaInfo = inputs.mediaInfo,
thumbnailSource = inputs.thumbnailSource ?: inputs.mediaSource,
)
}
MediaViewerEvents.CloseBottomSheet -> {
mediaBottomSheetState = MediaBottomSheetState.Hidden
}
}
}
@ -111,7 +128,7 @@ class MediaViewerPresenter @AssistedInject constructor(
canShowInfo = inputs.canShowInfo,
canDownload = inputs.canDownload,
canShare = inputs.canShare,
canDelete = canDelete,
mediaBottomSheetState = mediaBottomSheetState,
eventSink = ::handleEvents
)
}

View file

@ -13,6 +13,7 @@ import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.mediaviewer.api.MediaInfo
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState
data class MediaViewerState(
val eventId: EventId?,
@ -23,6 +24,6 @@ data class MediaViewerState(
val canShowInfo: Boolean,
val canDownload: Boolean,
val canShare: Boolean,
val canDelete: Boolean,
val mediaBottomSheetState: MediaBottomSheetState,
val eventSink: (MediaViewerEvents) -> Unit,
)

View file

@ -17,6 +17,9 @@ import io.element.android.libraries.mediaviewer.api.anApkMediaInfo
import io.element.android.libraries.mediaviewer.api.anAudioMediaInfo
import io.element.android.libraries.mediaviewer.api.anImageMediaInfo
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState
import io.element.android.libraries.mediaviewer.impl.details.aMediaDeleteConfirmationState
import io.element.android.libraries.mediaviewer.impl.details.aMediaDetailsBottomSheetState
open class MediaViewerStateProvider : PreviewParameterProvider<MediaViewerState> {
override val values: Sequence<MediaViewerState>
@ -91,6 +94,12 @@ open class MediaViewerStateProvider : PreviewParameterProvider<MediaViewerState>
canShare = false,
)
},
aMediaViewerState(
mediaBottomSheetState = aMediaDetailsBottomSheetState(),
),
aMediaViewerState(
mediaBottomSheetState = aMediaDeleteConfirmationState(),
),
)
}
@ -100,6 +109,7 @@ fun aMediaViewerState(
canShowInfo: Boolean = true,
canDownload: Boolean = true,
canShare: Boolean = true,
mediaBottomSheetState: MediaBottomSheetState = MediaBottomSheetState.Hidden,
eventSink: (MediaViewerEvents) -> Unit = {},
) = MediaViewerState(
eventId = null,
@ -110,6 +120,6 @@ fun aMediaViewerState(
canShowInfo = canShowInfo,
canDownload = canDownload,
canShare = canShare,
canDelete = true,
mediaBottomSheetState = mediaBottomSheetState,
eventSink = eventSink,
)

View file

@ -95,7 +95,6 @@ fun MediaViewerView(
val defaultBottomPaddingInPixels = if (LocalInspectionMode.current) 303 else 0
var bottomPaddingInPixels by remember { mutableIntStateOf(defaultBottomPaddingInPixels) }
BackHandler { onBackClick() }
var mediaBottomSheetState by remember { mutableStateOf<MediaBottomSheetState>(MediaBottomSheetState.Hidden) }
Scaffold(
modifier,
containerColor = Color.Transparent,
@ -128,12 +127,7 @@ fun MediaViewerView(
canShowInfo = state.canShowInfo,
onBackClick = onBackClick,
onInfoClick = {
mediaBottomSheetState = MediaBottomSheetState.MediaDetailsBottomSheetState(
eventId = state.eventId,
canDelete = state.canDelete,
mediaInfo = state.mediaInfo,
thumbnailSource = state.thumbnailSource,
)
state.eventSink(MediaViewerEvents.OpenInfo)
},
eventSink = state.eventSink
)
@ -146,24 +140,19 @@ fun MediaViewerView(
}
}
}
when (val bottomSheetState = mediaBottomSheetState) {
when (val bottomSheetState = state.mediaBottomSheetState) {
MediaBottomSheetState.Hidden -> Unit
is MediaBottomSheetState.MediaDetailsBottomSheetState -> {
MediaDetailsBottomSheet(
state = bottomSheetState,
onViewInTimeline = {
mediaBottomSheetState = MediaBottomSheetState.Hidden
state.eventSink(MediaViewerEvents.ViewInTimeline(it))
},
onDelete = { eventId ->
mediaBottomSheetState = MediaBottomSheetState.MediaDeleteConfirmationState(
eventId = eventId,
mediaInfo = state.mediaInfo,
thumbnailSource = state.thumbnailSource,
)
state.eventSink(MediaViewerEvents.ConfirmDelete(eventId))
},
onDismiss = {
mediaBottomSheetState = MediaBottomSheetState.Hidden
state.eventSink(MediaViewerEvents.CloseBottomSheet)
},
)
}
@ -171,11 +160,10 @@ fun MediaViewerView(
MediaDeleteConfirmationBottomSheet(
state = bottomSheetState,
onDelete = {
mediaBottomSheetState = MediaBottomSheetState.Hidden
state.eventSink(MediaViewerEvents.Delete(it))
},
onDismiss = {
mediaBottomSheetState = MediaBottomSheetState.Hidden
state.eventSink(MediaViewerEvents.CloseBottomSheet)
},
)
}

View file

@ -29,6 +29,7 @@ import io.element.android.libraries.matrix.test.room.FakeMatrixRoom
import io.element.android.libraries.matrix.test.timeline.FakeTimeline
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
import io.element.android.libraries.mediaviewer.api.anApkMediaInfo
import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState
import io.element.android.libraries.mediaviewer.test.FakeLocalMediaActions
import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory
import io.element.android.tests.testutils.WarmUpRule
@ -67,7 +68,7 @@ class MediaViewerPresenterTest {
assertThat(initialState.canShowInfo).isTrue()
assertThat(initialState.canDownload).isTrue()
assertThat(initialState.canShare).isTrue()
assertThat(initialState.canDelete).isFalse()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}
@ -87,7 +88,7 @@ class MediaViewerPresenterTest {
assertThat(initialState.canShowInfo).isFalse()
assertThat(initialState.canDownload).isTrue()
assertThat(initialState.canShare).isTrue()
assertThat(initialState.canDelete).isFalse()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}
@ -107,7 +108,7 @@ class MediaViewerPresenterTest {
assertThat(initialState.canShowInfo).isTrue()
assertThat(initialState.canDownload).isTrue()
assertThat(initialState.canShare).isFalse()
assertThat(initialState.canDelete).isFalse()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}
@ -127,7 +128,7 @@ class MediaViewerPresenterTest {
assertThat(initialState.canShowInfo).isTrue()
assertThat(initialState.canDownload).isFalse()
assertThat(initialState.canShare).isTrue()
assertThat(initialState.canDelete).isFalse()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}
@ -147,7 +148,7 @@ class MediaViewerPresenterTest {
assertThat(initialState.canShowInfo).isTrue()
assertThat(initialState.canDownload).isTrue()
assertThat(initialState.canShare).isTrue()
assertThat(initialState.canDelete).isTrue()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}
@ -168,7 +169,7 @@ class MediaViewerPresenterTest {
assertThat(initialState.canShowInfo).isTrue()
assertThat(initialState.canDownload).isTrue()
assertThat(initialState.canShare).isTrue()
assertThat(initialState.canDelete).isFalse()
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
}
}