mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-08-06 05:14:50 +01:00
Add delete function for editor thumbs.
This commit is contained in:
@@ -5,9 +5,11 @@
|
||||
|
||||
package org.signal.mediasend
|
||||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
object MediaSendMetrics {
|
||||
val SelectedMediaPreviewSize = DpSize(44.dp, 44.dp)
|
||||
val SelectedMediaPreviewShape = RoundedCornerShape(8.dp)
|
||||
}
|
||||
|
||||
@@ -298,6 +298,10 @@ class MediaSendViewModel(
|
||||
MediaEditScreenEvent.ToggleMediaQuality -> {
|
||||
setSentMediaQuality(state.value.sentMediaQuality.next())
|
||||
}
|
||||
|
||||
is MediaEditScreenEvent.RemoveMedia -> {
|
||||
removeMedia(mediaEditScreenEvent.media)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -186,8 +186,7 @@ fun MediaEditScreen(
|
||||
.align(Alignment.BottomCenter)
|
||||
.then(if (isTextEditing) Modifier.imePadding() else Modifier)
|
||||
) {
|
||||
// A document is always the whole selection and has no thumbnail to show, so the rail stays hidden for it.
|
||||
if (state.selectedMedia.isNotEmpty() && !isInteracting && focusedEditorState !is EditorState.Document) {
|
||||
if (state.selectedMedia.size > 1 && !isInteracting) {
|
||||
ThumbnailRow(
|
||||
selectedMedia = state.selectedMedia,
|
||||
pagerState = pagerState,
|
||||
@@ -195,8 +194,12 @@ fun MediaEditScreen(
|
||||
onEvent(MediaEditScreenEvent.FocusedMediaChanged(it))
|
||||
},
|
||||
onThumbnailClick = { index ->
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(index)
|
||||
if (pagerState.currentPage == index) {
|
||||
onEvent(MediaEditScreenEvent.RemoveMedia(state.selectedMedia[index]))
|
||||
} else {
|
||||
scope.launch {
|
||||
pagerState.animateScrollToPage(index)
|
||||
}
|
||||
}
|
||||
},
|
||||
onReorder = { fromIndex, toIndex ->
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.signal.core.models.media.Media
|
||||
import org.signal.mediasend.edit.video.VideoTrimData
|
||||
|
||||
sealed interface MediaEditScreenEvent {
|
||||
data class RemoveMedia(val media: Media) : MediaEditScreenEvent
|
||||
data class FocusedMediaChanged(val media: Media) : MediaEditScreenEvent
|
||||
data class ReorderSelectedMedia(val fromIndex: Int, val toIndex: Int) : MediaEditScreenEvent
|
||||
data class AddMessageClick(val startWithEmojiKeyboard: Boolean = false) : MediaEditScreenEvent
|
||||
|
||||
+73
-26
@@ -22,7 +22,7 @@ import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.pager.PagerState
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
@@ -31,6 +31,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.rememberUpdatedState
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
@@ -47,6 +48,7 @@ import kotlinx.coroutines.launch
|
||||
import org.signal.core.models.media.Media
|
||||
import org.signal.core.ui.compose.DayNightPreviews
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.SignalIcons
|
||||
import org.signal.core.ui.compose.list.ReorderableItem
|
||||
import org.signal.core.ui.compose.list.rememberReorderBuffer
|
||||
import org.signal.core.ui.compose.list.rememberReorderableListState
|
||||
@@ -152,25 +154,27 @@ internal fun ThumbnailRow(
|
||||
}
|
||||
|
||||
BoxWithConstraints(
|
||||
modifier = Modifier.fillMaxWidth().draggable(
|
||||
state = draggableState,
|
||||
orientation = Orientation.Horizontal,
|
||||
enabled = !isReordering,
|
||||
onDragStopped = { velocity ->
|
||||
scope.launch {
|
||||
val targetPage = when {
|
||||
velocity > 500f -> (pagerState.currentPage - 1).coerceAtLeast(0)
|
||||
velocity < -500f -> (pagerState.currentPage + 1).coerceAtMost(selectedMedia.lastIndex)
|
||||
else -> pagerState.currentPage
|
||||
}
|
||||
pagerState.animateScrollToPage(targetPage)
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.draggable(
|
||||
state = draggableState,
|
||||
orientation = Orientation.Horizontal,
|
||||
enabled = !isReordering,
|
||||
onDragStopped = { velocity ->
|
||||
scope.launch {
|
||||
val targetPage = when {
|
||||
velocity > 500f -> (pagerState.currentPage - 1).coerceAtLeast(0)
|
||||
velocity < -500f -> (pagerState.currentPage + 1).coerceAtMost(selectedMedia.lastIndex)
|
||||
else -> pagerState.currentPage
|
||||
}
|
||||
pagerState.animateScrollToPage(targetPage)
|
||||
|
||||
if (targetPage in selectedMedia.indices) {
|
||||
onFocusedMediaChange(selectedMedia[targetPage])
|
||||
if (targetPage in selectedMedia.indices) {
|
||||
onFocusedMediaChange(selectedMedia[targetPage])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
) {
|
||||
val itemWidth = MediaSendMetrics.SelectedMediaPreviewSize.width
|
||||
|
||||
@@ -194,13 +198,21 @@ internal fun ThumbnailRow(
|
||||
}
|
||||
}
|
||||
|
||||
ReorderableItem(reorderableListState, index) {
|
||||
Thumbnail(
|
||||
media = media,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = padding)
|
||||
.clickable { onThumbnailClick(index) }
|
||||
)
|
||||
ReorderableItem(
|
||||
reorderableListState = reorderableListState,
|
||||
index = index,
|
||||
modifier = Modifier.clip(MediaSendMetrics.SelectedMediaPreviewShape)
|
||||
) {
|
||||
DeleteBox(
|
||||
enabled = pagerState.currentPage == index
|
||||
) {
|
||||
Thumbnail(
|
||||
media = media,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = padding)
|
||||
.clickable { onThumbnailClick(index) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -211,6 +223,29 @@ private fun lerp(start: Dp, stop: Dp, fraction: Float): Dp {
|
||||
return start + (stop - start) * fraction
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DeleteBox(
|
||||
enabled: Boolean,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
Box {
|
||||
content()
|
||||
|
||||
if (enabled) {
|
||||
Icon(
|
||||
imageVector = SignalIcons.Trash.imageVector,
|
||||
tint = Color.White,
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.background(color = Color.Black.copy(alpha = 0.32f), shape = MediaSendMetrics.SelectedMediaPreviewShape)
|
||||
.size(MediaSendMetrics.SelectedMediaPreviewSize)
|
||||
.padding(10.dp)
|
||||
.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Thumbnail(media: Media, modifier: Modifier = Modifier) {
|
||||
if (!LocalInspectionMode.current) {
|
||||
@@ -219,13 +254,13 @@ private fun Thumbnail(media: Media, modifier: Modifier = Modifier) {
|
||||
imageSize = MediaSendMetrics.SelectedMediaPreviewSize,
|
||||
modifier = modifier
|
||||
.size(MediaSendMetrics.SelectedMediaPreviewSize)
|
||||
.clip(shape = RoundedCornerShape(8.dp))
|
||||
.clip(shape = MediaSendMetrics.SelectedMediaPreviewShape)
|
||||
)
|
||||
} else {
|
||||
Box(
|
||||
modifier = modifier
|
||||
.size(MediaSendMetrics.SelectedMediaPreviewSize)
|
||||
.background(color = Color.Gray, shape = RoundedCornerShape(8.dp))
|
||||
.background(color = Color.Gray, shape = MediaSendMetrics.SelectedMediaPreviewShape)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -255,6 +290,18 @@ private fun ThumbnailPreview() {
|
||||
}
|
||||
}
|
||||
|
||||
@DayNightPreviews
|
||||
@Composable
|
||||
private fun DeleteBoxPreview() {
|
||||
Previews.Preview {
|
||||
DeleteBox(enabled = true) {
|
||||
Thumbnail(
|
||||
media = rememberPreviewMedia(1).first()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun rememberPreviewMedia(count: Int): List<Media> {
|
||||
return remember(count) {
|
||||
Reference in New Issue
Block a user