Move bottom state to the View state
This commit is contained in:
parent
b3648c1d18
commit
d86430d56a
6 changed files with 58 additions and 38 deletions
|
|
@ -16,5 +16,8 @@ sealed interface MediaViewerEvents {
|
||||||
data object RetryLoading : MediaViewerEvents
|
data object RetryLoading : MediaViewerEvents
|
||||||
data object ClearLoadingError : MediaViewerEvents
|
data object ClearLoadingError : MediaViewerEvents
|
||||||
data class ViewInTimeline(val eventId: EventId) : 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
|
data class Delete(val eventId: EventId) : MediaViewerEvents
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,11 +11,9 @@ import android.content.ActivityNotFoundException
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.collectAsState
|
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.produceState
|
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
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.MediaViewerEntryPoint
|
||||||
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
||||||
import io.element.android.libraries.mediaviewer.api.local.LocalMediaFactory
|
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.mediaviewer.impl.local.LocalMediaActions
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
|
@ -78,15 +77,7 @@ class MediaViewerPresenter @AssistedInject constructor(
|
||||||
mediaFile.value?.close()
|
mediaFile.value?.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
var mediaBottomSheetState by remember { mutableStateOf<MediaBottomSheetState>(MediaBottomSheetState.Hidden) }
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun handleEvents(mediaViewerEvents: MediaViewerEvents) {
|
fun handleEvents(mediaViewerEvents: MediaViewerEvents) {
|
||||||
when (mediaViewerEvents) {
|
when (mediaViewerEvents) {
|
||||||
|
|
@ -95,10 +86,36 @@ class MediaViewerPresenter @AssistedInject constructor(
|
||||||
MediaViewerEvents.SaveOnDisk -> coroutineScope.saveOnDisk(localMedia.value)
|
MediaViewerEvents.SaveOnDisk -> coroutineScope.saveOnDisk(localMedia.value)
|
||||||
MediaViewerEvents.Share -> coroutineScope.share(localMedia.value)
|
MediaViewerEvents.Share -> coroutineScope.share(localMedia.value)
|
||||||
MediaViewerEvents.OpenWith -> coroutineScope.open(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 -> {
|
is MediaViewerEvents.ViewInTimeline -> {
|
||||||
|
mediaBottomSheetState = MediaBottomSheetState.Hidden
|
||||||
navigator.onViewInTimelineClick(mediaViewerEvents.eventId)
|
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,
|
canShowInfo = inputs.canShowInfo,
|
||||||
canDownload = inputs.canDownload,
|
canDownload = inputs.canDownload,
|
||||||
canShare = inputs.canShare,
|
canShare = inputs.canShare,
|
||||||
canDelete = canDelete,
|
mediaBottomSheetState = mediaBottomSheetState,
|
||||||
eventSink = ::handleEvents
|
eventSink = ::handleEvents
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.matrix.api.media.MediaSource
|
||||||
import io.element.android.libraries.mediaviewer.api.MediaInfo
|
import io.element.android.libraries.mediaviewer.api.MediaInfo
|
||||||
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
||||||
|
import io.element.android.libraries.mediaviewer.impl.details.MediaBottomSheetState
|
||||||
|
|
||||||
data class MediaViewerState(
|
data class MediaViewerState(
|
||||||
val eventId: EventId?,
|
val eventId: EventId?,
|
||||||
|
|
@ -23,6 +24,6 @@ data class MediaViewerState(
|
||||||
val canShowInfo: Boolean,
|
val canShowInfo: Boolean,
|
||||||
val canDownload: Boolean,
|
val canDownload: Boolean,
|
||||||
val canShare: Boolean,
|
val canShare: Boolean,
|
||||||
val canDelete: Boolean,
|
val mediaBottomSheetState: MediaBottomSheetState,
|
||||||
val eventSink: (MediaViewerEvents) -> Unit,
|
val eventSink: (MediaViewerEvents) -> Unit,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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.anAudioMediaInfo
|
||||||
import io.element.android.libraries.mediaviewer.api.anImageMediaInfo
|
import io.element.android.libraries.mediaviewer.api.anImageMediaInfo
|
||||||
import io.element.android.libraries.mediaviewer.api.local.LocalMedia
|
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> {
|
open class MediaViewerStateProvider : PreviewParameterProvider<MediaViewerState> {
|
||||||
override val values: Sequence<MediaViewerState>
|
override val values: Sequence<MediaViewerState>
|
||||||
|
|
@ -91,6 +94,12 @@ open class MediaViewerStateProvider : PreviewParameterProvider<MediaViewerState>
|
||||||
canShare = false,
|
canShare = false,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
aMediaViewerState(
|
||||||
|
mediaBottomSheetState = aMediaDetailsBottomSheetState(),
|
||||||
|
),
|
||||||
|
aMediaViewerState(
|
||||||
|
mediaBottomSheetState = aMediaDeleteConfirmationState(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,6 +109,7 @@ fun aMediaViewerState(
|
||||||
canShowInfo: Boolean = true,
|
canShowInfo: Boolean = true,
|
||||||
canDownload: Boolean = true,
|
canDownload: Boolean = true,
|
||||||
canShare: Boolean = true,
|
canShare: Boolean = true,
|
||||||
|
mediaBottomSheetState: MediaBottomSheetState = MediaBottomSheetState.Hidden,
|
||||||
eventSink: (MediaViewerEvents) -> Unit = {},
|
eventSink: (MediaViewerEvents) -> Unit = {},
|
||||||
) = MediaViewerState(
|
) = MediaViewerState(
|
||||||
eventId = null,
|
eventId = null,
|
||||||
|
|
@ -110,6 +120,6 @@ fun aMediaViewerState(
|
||||||
canShowInfo = canShowInfo,
|
canShowInfo = canShowInfo,
|
||||||
canDownload = canDownload,
|
canDownload = canDownload,
|
||||||
canShare = canShare,
|
canShare = canShare,
|
||||||
canDelete = true,
|
mediaBottomSheetState = mediaBottomSheetState,
|
||||||
eventSink = eventSink,
|
eventSink = eventSink,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,6 @@ fun MediaViewerView(
|
||||||
val defaultBottomPaddingInPixels = if (LocalInspectionMode.current) 303 else 0
|
val defaultBottomPaddingInPixels = if (LocalInspectionMode.current) 303 else 0
|
||||||
var bottomPaddingInPixels by remember { mutableIntStateOf(defaultBottomPaddingInPixels) }
|
var bottomPaddingInPixels by remember { mutableIntStateOf(defaultBottomPaddingInPixels) }
|
||||||
BackHandler { onBackClick() }
|
BackHandler { onBackClick() }
|
||||||
var mediaBottomSheetState by remember { mutableStateOf<MediaBottomSheetState>(MediaBottomSheetState.Hidden) }
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier,
|
modifier,
|
||||||
containerColor = Color.Transparent,
|
containerColor = Color.Transparent,
|
||||||
|
|
@ -128,12 +127,7 @@ fun MediaViewerView(
|
||||||
canShowInfo = state.canShowInfo,
|
canShowInfo = state.canShowInfo,
|
||||||
onBackClick = onBackClick,
|
onBackClick = onBackClick,
|
||||||
onInfoClick = {
|
onInfoClick = {
|
||||||
mediaBottomSheetState = MediaBottomSheetState.MediaDetailsBottomSheetState(
|
state.eventSink(MediaViewerEvents.OpenInfo)
|
||||||
eventId = state.eventId,
|
|
||||||
canDelete = state.canDelete,
|
|
||||||
mediaInfo = state.mediaInfo,
|
|
||||||
thumbnailSource = state.thumbnailSource,
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
eventSink = state.eventSink
|
eventSink = state.eventSink
|
||||||
)
|
)
|
||||||
|
|
@ -146,24 +140,19 @@ fun MediaViewerView(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
when (val bottomSheetState = mediaBottomSheetState) {
|
when (val bottomSheetState = state.mediaBottomSheetState) {
|
||||||
MediaBottomSheetState.Hidden -> Unit
|
MediaBottomSheetState.Hidden -> Unit
|
||||||
is MediaBottomSheetState.MediaDetailsBottomSheetState -> {
|
is MediaBottomSheetState.MediaDetailsBottomSheetState -> {
|
||||||
MediaDetailsBottomSheet(
|
MediaDetailsBottomSheet(
|
||||||
state = bottomSheetState,
|
state = bottomSheetState,
|
||||||
onViewInTimeline = {
|
onViewInTimeline = {
|
||||||
mediaBottomSheetState = MediaBottomSheetState.Hidden
|
|
||||||
state.eventSink(MediaViewerEvents.ViewInTimeline(it))
|
state.eventSink(MediaViewerEvents.ViewInTimeline(it))
|
||||||
},
|
},
|
||||||
onDelete = { eventId ->
|
onDelete = { eventId ->
|
||||||
mediaBottomSheetState = MediaBottomSheetState.MediaDeleteConfirmationState(
|
state.eventSink(MediaViewerEvents.ConfirmDelete(eventId))
|
||||||
eventId = eventId,
|
|
||||||
mediaInfo = state.mediaInfo,
|
|
||||||
thumbnailSource = state.thumbnailSource,
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
onDismiss = {
|
onDismiss = {
|
||||||
mediaBottomSheetState = MediaBottomSheetState.Hidden
|
state.eventSink(MediaViewerEvents.CloseBottomSheet)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -171,11 +160,10 @@ fun MediaViewerView(
|
||||||
MediaDeleteConfirmationBottomSheet(
|
MediaDeleteConfirmationBottomSheet(
|
||||||
state = bottomSheetState,
|
state = bottomSheetState,
|
||||||
onDelete = {
|
onDelete = {
|
||||||
mediaBottomSheetState = MediaBottomSheetState.Hidden
|
|
||||||
state.eventSink(MediaViewerEvents.Delete(it))
|
state.eventSink(MediaViewerEvents.Delete(it))
|
||||||
},
|
},
|
||||||
onDismiss = {
|
onDismiss = {
|
||||||
mediaBottomSheetState = MediaBottomSheetState.Hidden
|
state.eventSink(MediaViewerEvents.CloseBottomSheet)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.matrix.test.timeline.FakeTimeline
|
||||||
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
|
import io.element.android.libraries.mediaviewer.api.MediaViewerEntryPoint
|
||||||
import io.element.android.libraries.mediaviewer.api.anApkMediaInfo
|
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.FakeLocalMediaActions
|
||||||
import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory
|
import io.element.android.libraries.mediaviewer.test.FakeLocalMediaFactory
|
||||||
import io.element.android.tests.testutils.WarmUpRule
|
import io.element.android.tests.testutils.WarmUpRule
|
||||||
|
|
@ -67,7 +68,7 @@ class MediaViewerPresenterTest {
|
||||||
assertThat(initialState.canShowInfo).isTrue()
|
assertThat(initialState.canShowInfo).isTrue()
|
||||||
assertThat(initialState.canDownload).isTrue()
|
assertThat(initialState.canDownload).isTrue()
|
||||||
assertThat(initialState.canShare).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.canShowInfo).isFalse()
|
||||||
assertThat(initialState.canDownload).isTrue()
|
assertThat(initialState.canDownload).isTrue()
|
||||||
assertThat(initialState.canShare).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.canShowInfo).isTrue()
|
||||||
assertThat(initialState.canDownload).isTrue()
|
assertThat(initialState.canDownload).isTrue()
|
||||||
assertThat(initialState.canShare).isFalse()
|
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.canShowInfo).isTrue()
|
||||||
assertThat(initialState.canDownload).isFalse()
|
assertThat(initialState.canDownload).isFalse()
|
||||||
assertThat(initialState.canShare).isTrue()
|
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.canShowInfo).isTrue()
|
||||||
assertThat(initialState.canDownload).isTrue()
|
assertThat(initialState.canDownload).isTrue()
|
||||||
assertThat(initialState.canShare).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.canShowInfo).isTrue()
|
||||||
assertThat(initialState.canDownload).isTrue()
|
assertThat(initialState.canDownload).isTrue()
|
||||||
assertThat(initialState.canShare).isTrue()
|
assertThat(initialState.canShare).isTrue()
|
||||||
assertThat(initialState.canDelete).isFalse()
|
assertThat(initialState.mediaBottomSheetState).isEqualTo(MediaBottomSheetState.Hidden)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue