Skip to content

Commit

Permalink
feat: scroll bottom - jump to last message (WPB-4987) (WPB-3973) (#2343)
Browse files Browse the repository at this point in the history
  • Loading branch information
yamilmedina authored Oct 18, 2023
1 parent 22d380a commit e302061
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,29 @@
package com.wire.android.ui.home.conversations

import SwipeableSnackbar
import android.annotation.SuppressLint
import android.net.Uri
import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandIn
import androidx.compose.animation.shrinkOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallFloatingActionButton
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarResult
import androidx.compose.runtime.Composable
Expand Down Expand Up @@ -70,12 +83,14 @@ import com.wire.android.navigation.Navigator
import com.wire.android.ui.calling.common.MicrophoneBTPermissionsDeniedDialog
import com.wire.android.ui.common.bottomsheet.MenuModalSheetHeader
import com.wire.android.ui.common.bottomsheet.MenuModalSheetLayout
import com.wire.android.ui.common.colorsScheme
import com.wire.android.ui.common.dialogs.InvalidLinkDialog
import com.wire.android.ui.common.dialogs.VisitLinkDialog
import com.wire.android.ui.common.dialogs.calling.CallingFeatureUnavailableDialog
import com.wire.android.ui.common.dialogs.calling.ConfirmStartCallDialog
import com.wire.android.ui.common.dialogs.calling.JoinAnywayDialog
import com.wire.android.ui.common.dialogs.calling.OngoingActiveCallDialog
import com.wire.android.ui.common.dimensions
import com.wire.android.ui.common.error.CoreFailureErrorDialog
import com.wire.android.ui.common.snackbar.LocalSnackbarHostState
import com.wire.android.ui.destinations.ConversationScreenDestination
Expand Down Expand Up @@ -110,6 +125,7 @@ import com.wire.android.ui.home.messagecomposer.MessageComposer
import com.wire.android.ui.home.messagecomposer.state.MessageBundle
import com.wire.android.ui.home.messagecomposer.state.MessageComposerStateHolder
import com.wire.android.ui.home.messagecomposer.state.rememberMessageComposerStateHolder
import com.wire.android.ui.theme.wireColorScheme
import com.wire.android.util.extension.openAppInfoScreen
import com.wire.android.util.normalizeLink
import com.wire.android.util.ui.UIText
Expand Down Expand Up @@ -771,6 +787,7 @@ private fun SnackBarMessage(
}
}

@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@Composable
fun MessageList(
lazyPagingMessages: LazyPagingItems<UIMessage>,
Expand Down Expand Up @@ -815,59 +832,90 @@ fun MessageList(
}
}

LazyColumn(
state = lazyListState,
reverseLayout = true,
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
) {
itemsIndexed(lazyPagingMessages, key = { _, uiMessage ->
uiMessage.header.messageId
}) { index, message ->
if (message == null) {
// We can draw a placeholder here, as we fetch the next page of messages
return@itemsIndexed
}
val showAuthor by remember {
mutableStateOf(
AuthorHeaderHelper.shouldShowHeader(
index,
lazyPagingMessages.itemSnapshotList.items,
message
)
)
}
Scaffold(
floatingActionButton = { JumpToLastMessageButton(lazyListState = lazyListState) },
content = {
LazyColumn(
state = lazyListState,
reverseLayout = true,
modifier = Modifier
.fillMaxHeight()
.fillMaxWidth()
.background(color = colorsScheme().backgroundVariant)
) {
itemsIndexed(lazyPagingMessages, key = { _, uiMessage ->
uiMessage.header.messageId
}) { index, message ->
if (message == null) {
// We can draw a placeholder here, as we fetch the next page of messages
return@itemsIndexed
}
val showAuthor by remember {
mutableStateOf(
AuthorHeaderHelper.shouldShowHeader(
index,
lazyPagingMessages.itemSnapshotList.items,
message
)
)
}

when (message) {
is UIMessage.Regular -> {
MessageItem(
message = message,
conversationDetailsData = conversationDetailsData,
showAuthor = showAuthor,
audioMessagesState = audioMessagesState,
onAudioClick = onAudioItemClicked,
onChangeAudioPosition = onChangeAudioPosition,
onLongClicked = onShowEditingOption,
onAssetMessageClicked = onAssetItemClicked,
onImageMessageClicked = onImageFullScreenMode,
onOpenProfile = onOpenProfile,
onReactionClicked = onReactionClicked,
onResetSessionClicked = onResetSessionClicked,
onSelfDeletingMessageRead = onSelfDeletingMessageRead,
onFailedMessageCancelClicked = onFailedMessageCancelClicked,
onFailedMessageRetryClicked = onFailedMessageRetryClicked,
onLinkClick = onLinkClick
)
}
when (message) {
is UIMessage.Regular -> {
MessageItem(
message = message,
conversationDetailsData = conversationDetailsData,
showAuthor = showAuthor,
audioMessagesState = audioMessagesState,
onAudioClick = onAudioItemClicked,
onChangeAudioPosition = onChangeAudioPosition,
onLongClicked = onShowEditingOption,
onAssetMessageClicked = onAssetItemClicked,
onImageMessageClicked = onImageFullScreenMode,
onOpenProfile = onOpenProfile,
onReactionClicked = onReactionClicked,
onResetSessionClicked = onResetSessionClicked,
onSelfDeletingMessageRead = onSelfDeletingMessageRead,
onFailedMessageCancelClicked = onFailedMessageCancelClicked,
onFailedMessageRetryClicked = onFailedMessageRetryClicked,
onLinkClick = onLinkClick
)
}

is UIMessage.System -> SystemMessageItem(
message = message,
onFailedMessageCancelClicked = onFailedMessageCancelClicked,
onFailedMessageRetryClicked = onFailedMessageRetryClicked,
onSelfDeletingMessageRead = onSelfDeletingMessageRead
)
is UIMessage.System -> SystemMessageItem(
message = message,
onFailedMessageCancelClicked = onFailedMessageCancelClicked,
onFailedMessageRetryClicked = onFailedMessageRetryClicked,
onSelfDeletingMessageRead = onSelfDeletingMessageRead
)
}
}
}
})
}

@Composable
fun JumpToLastMessageButton(
coroutineScope: CoroutineScope = rememberCoroutineScope(),
lazyListState: LazyListState
) {
AnimatedVisibility(
visible = lazyListState.firstVisibleItemIndex > 0,
enter = expandIn { it },
exit = shrinkOut { it }
) {
SmallFloatingActionButton(
modifier = Modifier.offset(y = dimensions().spacing18x),
onClick = { coroutineScope.launch { lazyListState.animateScrollToItem(0) } },
containerColor = MaterialTheme.wireColorScheme.onSecondaryButtonDisabled,
contentColor = MaterialTheme.wireColorScheme.secondaryButtonDisabled,
shape = CircleShape,
) {
Icon(
imageVector = Icons.Default.KeyboardArrowDown,
contentDescription = stringResource(id = R.string.content_description_jump_to_last_message),
Modifier.size(dimensions().spacing32x)
)
}
}
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@
<string name="content_description_record_audio_button_send">Send Audio Message</string>
<string name="content_description_mls_certificate_valid">All devices of all participants have a valid MLS certificate</string>
<string name="content_description_proteus_certificate_valid">All of all participants are verified (Proteus)</string>
<string name="content_description_jump_to_last_message">Scroll down to last message, button</string>
<!-- Non translatable strings-->
<string name="url_support" translatable="false">https://support.wire.com</string>
<string name="url_decryption_failure_learn_more" translatable="false">https://support.wire.com/hc/articles/207948115-Why-was-I-notified-that-a-message-from-a-contact-was-not-received-</string>
Expand Down

0 comments on commit e302061

Please sign in to comment.