Timeline: clean up and fix some ui glitches
This commit is contained in:
parent
3d25464bdc
commit
13bbcc6e26
3 changed files with 81 additions and 42 deletions
|
|
@ -1,4 +1,8 @@
|
|||
@file:OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class)
|
||||
@file:OptIn(
|
||||
ExperimentalMaterial3Api::class,
|
||||
ExperimentalMaterialApi::class,
|
||||
ExperimentalComposeUiApi::class
|
||||
)
|
||||
|
||||
package io.element.android.x.features.messages
|
||||
|
||||
|
|
@ -21,8 +25,10 @@ import androidx.compose.runtime.*
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Alignment.Companion.End
|
||||
import androidx.compose.ui.Alignment.Companion.Start
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.layout.LastBaseline
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -48,8 +54,6 @@ import kotlinx.coroutines.launch
|
|||
import timber.log.Timber
|
||||
import java.lang.Math.random
|
||||
|
||||
private val COMPOSER_HEIGHT = 112.dp
|
||||
|
||||
@Composable
|
||||
fun MessagesScreen(
|
||||
roomId: String,
|
||||
|
|
@ -64,10 +68,12 @@ fun MessagesScreen(
|
|||
}
|
||||
|
||||
LogCompositions(tag = "MessagesScreen", msg = "Root")
|
||||
val actionsSheetState = rememberModalBottomSheetState(
|
||||
val itemActionsBottomSheetState = rememberModalBottomSheetState(
|
||||
initialValue = ModalBottomSheetValue.Hidden,
|
||||
)
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
val focusManager = LocalFocusManager.current
|
||||
val roomTitle by viewModel.collectAsState(MessagesViewState::roomName)
|
||||
val roomAvatar by viewModel.collectAsState(MessagesViewState::roomAvatar)
|
||||
val timelineItems by viewModel.collectAsState(MessagesViewState::timelineItems)
|
||||
|
|
@ -78,7 +84,7 @@ fun MessagesScreen(
|
|||
val composerFullScreen by composerViewModel.collectAsState(MessageComposerViewState::isFullScreen)
|
||||
val composerCanSendMessage by composerViewModel.collectAsState(MessageComposerViewState::isSendButtonVisible)
|
||||
val composerText by composerViewModel.collectAsState(MessageComposerViewState::text)
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
MessagesScreenContent(
|
||||
roomTitle = roomTitle,
|
||||
roomAvatar = roomAvatar,
|
||||
|
|
@ -99,33 +105,18 @@ fun MessagesScreen(
|
|||
Timber.v("onClick on timeline item: ${it.id}")
|
||||
},
|
||||
onLongClick = {
|
||||
focusManager.clearFocus(force = true)
|
||||
viewModel.computeActionsSheetState(it)
|
||||
coroutineScope.launch {
|
||||
actionsSheetState.show()
|
||||
itemActionsBottomSheetState.show()
|
||||
}
|
||||
},
|
||||
snackbarHostState = snackbarHostState,
|
||||
)
|
||||
val itemActionsSheetState by viewModel.collectAsState(prop1 = MessagesViewState::itemActionsSheetState)
|
||||
TimelineItemActionsScreen(
|
||||
sheetState = actionsSheetState,
|
||||
actionsSheetState = itemActionsSheetState(),
|
||||
onActionClicked = {
|
||||
viewModel.handleItemAction(it)
|
||||
coroutineScope.launch {
|
||||
val targetEvent = viewModel.getTargetEvent()
|
||||
when (it) {
|
||||
is MessagesItemAction.Edit -> {
|
||||
// Entering Edit mode, update the text in the composer.
|
||||
val newComposerText =
|
||||
(targetEvent?.content as? MessagesTimelineItemTextBasedContent)?.body.orEmpty()
|
||||
composerViewModel.updateText(newComposerText)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
actionsSheetState.hide()
|
||||
}
|
||||
}
|
||||
viewModel = viewModel,
|
||||
composerViewModel = composerViewModel,
|
||||
modalBottomSheetState = itemActionsBottomSheetState,
|
||||
)
|
||||
snackBarContent?.let {
|
||||
coroutineScope.launch {
|
||||
|
|
@ -185,7 +176,12 @@ fun MessagesScreenContent(
|
|||
composerText = composerText
|
||||
)
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
snackbarHost = {
|
||||
SnackbarHost(
|
||||
snackbarHostState,
|
||||
modifier = Modifier.navigationBarsPadding()
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package io.element.android.x.features.messages
|
|||
|
||||
import com.airbnb.mvrx.MavericksViewModel
|
||||
import com.airbnb.mvrx.MavericksViewModelFactory
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import io.element.android.x.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.x.designsystem.components.avatar.AvatarSize
|
||||
|
|
@ -92,12 +93,8 @@ class MessagesViewModel(
|
|||
return currentState.itemActionsSheetState.invoke()?.targetItem
|
||||
}
|
||||
|
||||
fun handleItemAction(action: MessagesItemAction) {
|
||||
fun handleItemAction(action: MessagesItemAction, targetEvent: MessagesTimelineItemState.MessageEvent) {
|
||||
viewModelScope.launch(Dispatchers.Default) {
|
||||
val currentState = awaitState()
|
||||
Timber.v("Handle $action for ${currentState.itemActionsSheetState}")
|
||||
val targetEvent = getTargetEvent()
|
||||
?: return@launch
|
||||
when (action) {
|
||||
MessagesItemAction.Copy -> notImplementedYet()
|
||||
MessagesItemAction.Forward -> notImplementedYet()
|
||||
|
|
@ -152,7 +149,11 @@ class MessagesViewModel(
|
|||
}
|
||||
}
|
||||
|
||||
fun computeActionsSheetState(messagesTimelineItemState: MessagesTimelineItemState.MessageEvent) {
|
||||
fun computeActionsSheetState(messagesTimelineItemState: MessagesTimelineItemState.MessageEvent?) {
|
||||
if (messagesTimelineItemState == null) {
|
||||
setState { copy(itemActionsSheetState = Uninitialized) }
|
||||
return
|
||||
}
|
||||
suspend {
|
||||
val actions =
|
||||
if (messagesTimelineItemState.content is MessagesTimelineItemRedactedContent) {
|
||||
|
|
|
|||
|
|
@ -7,29 +7,71 @@ import androidx.compose.foundation.layout.*
|
|||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.airbnb.mvrx.compose.collectAsState
|
||||
import io.element.android.x.designsystem.components.VectorIcon
|
||||
import io.element.android.x.features.messages.MessagesViewModel
|
||||
import io.element.android.x.features.messages.model.MessagesItemAction
|
||||
import io.element.android.x.features.messages.model.MessagesItemActionsSheetState
|
||||
import io.element.android.x.features.messages.model.MessagesTimelineItemState
|
||||
import io.element.android.x.features.messages.model.MessagesViewState
|
||||
import io.element.android.x.features.messages.model.content.MessagesTimelineItemTextBasedContent
|
||||
import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun TimelineItemActionsScreen(
|
||||
sheetState: ModalBottomSheetState,
|
||||
actionsSheetState: MessagesItemActionsSheetState?,
|
||||
onActionClicked: (MessagesItemAction) -> Unit,
|
||||
viewModel: MessagesViewModel,
|
||||
composerViewModel: MessageComposerViewModel,
|
||||
modalBottomSheetState: ModalBottomSheetState,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
LaunchedEffect(modalBottomSheetState) {
|
||||
snapshotFlow { modalBottomSheetState.currentValue }
|
||||
.filter { it == ModalBottomSheetValue.Hidden }
|
||||
.collect {
|
||||
viewModel.computeActionsSheetState(null)
|
||||
}
|
||||
}
|
||||
|
||||
val itemActionsSheetState by viewModel.collectAsState(MessagesViewState::itemActionsSheetState)
|
||||
|
||||
fun onItemActionClicked(
|
||||
itemAction: MessagesItemAction,
|
||||
targetItem: MessagesTimelineItemState.MessageEvent
|
||||
) {
|
||||
viewModel.handleItemAction(itemAction, targetItem)
|
||||
coroutineScope.launch {
|
||||
val targetEvent = viewModel.getTargetEvent()
|
||||
when (itemAction) {
|
||||
is MessagesItemAction.Edit -> {
|
||||
// Entering Edit mode, update the text in the composer.
|
||||
val newComposerText =
|
||||
(targetEvent?.content as? MessagesTimelineItemTextBasedContent)?.body.orEmpty()
|
||||
composerViewModel.updateText(newComposerText)
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
modalBottomSheetState.hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ModalBottomSheetLayout(
|
||||
modifier = modifier,
|
||||
sheetState = sheetState,
|
||||
sheetState = modalBottomSheetState,
|
||||
sheetContent = {
|
||||
SheetContent(
|
||||
actionsSheetState = actionsSheetState,
|
||||
onActionClicked = onActionClicked,
|
||||
modifier = Modifier.navigationBarsPadding()
|
||||
actionsSheetState = itemActionsSheetState(),
|
||||
onActionClicked = ::onItemActionClicked,
|
||||
modifier = Modifier.navigationBarsPadding().imePadding()
|
||||
)
|
||||
}
|
||||
) {}
|
||||
|
|
@ -39,7 +81,7 @@ fun TimelineItemActionsScreen(
|
|||
@Composable
|
||||
private fun SheetContent(
|
||||
actionsSheetState: MessagesItemActionsSheetState?,
|
||||
onActionClicked: (MessagesItemAction) -> Unit,
|
||||
onActionClicked: (MessagesItemAction, MessagesTimelineItemState.MessageEvent) -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
if (actionsSheetState == null || actionsSheetState.actions.isEmpty()) {
|
||||
|
|
@ -54,7 +96,7 @@ private fun SheetContent(
|
|||
items(actionsSheetState.actions) {
|
||||
ListItem(
|
||||
modifier = Modifier.clickable {
|
||||
onActionClicked(it)
|
||||
onActionClicked(it, actionsSheetState.targetItem)
|
||||
},
|
||||
text = {
|
||||
Text(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue