RoomList : invite row
This commit is contained in:
parent
9d87240f4c
commit
26eaed5ea4
12 changed files with 382 additions and 110 deletions
|
|
@ -214,7 +214,7 @@ class RoomListPresenter @Inject constructor(
|
|||
val initialState = RoomListState.ContextMenu.Shown(
|
||||
roomId = event.roomListRoomSummary.roomId,
|
||||
roomName = event.roomListRoomSummary.name,
|
||||
isDm = event.roomListRoomSummary.isDm,
|
||||
isDm = event.roomListRoomSummary.isDirect,
|
||||
isFavorite = event.roomListRoomSummary.isFavorite,
|
||||
markAsUnreadFeatureFlagEnabled = featureFlagService.isFeatureEnabled(FeatureFlags.MarkAsUnread),
|
||||
hasNewContent = event.roomListRoomSummary.hasNewContent
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import io.element.android.features.leaveroom.api.LeaveRoomState
|
|||
import io.element.android.features.leaveroom.api.aLeaveRoomState
|
||||
import io.element.android.features.roomlist.impl.filters.RoomListFiltersState
|
||||
import io.element.android.features.roomlist.impl.filters.aRoomListFiltersState
|
||||
import io.element.android.features.roomlist.impl.model.DisplayType
|
||||
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
|
||||
import io.element.android.features.roomlist.impl.model.aRoomListRoomSummary
|
||||
import io.element.android.features.roomlist.impl.search.RoomListSearchState
|
||||
|
|
@ -98,11 +99,11 @@ internal fun aRoomListRoomSummaryList(): ImmutableList<RoomListRoomSummary> {
|
|||
),
|
||||
aRoomListRoomSummary(
|
||||
id = "!roomId3:domain",
|
||||
isPlaceholder = true,
|
||||
displayType = DisplayType.PLACEHOLDER,
|
||||
),
|
||||
aRoomListRoomSummary(
|
||||
id = "!roomId4:domain",
|
||||
isPlaceholder = true,
|
||||
displayType = DisplayType.PLACEHOLDER,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ private fun RoomListScaffold(
|
|||
)
|
||||
}
|
||||
|
||||
internal fun RoomListRoomSummary.contentType() = isPlaceholder
|
||||
internal fun RoomListRoomSummary.contentType() = type.ordinal
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -20,15 +20,18 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
|||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -36,12 +39,15 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.roomlist.impl.model.DisplayType
|
||||
import io.element.android.features.roomlist.impl.model.InviteSender
|
||||
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
|
||||
import io.element.android.features.roomlist.impl.model.RoomListRoomSummaryProvider
|
||||
import io.element.android.libraries.core.extensions.orEmpty
|
||||
|
|
@ -49,13 +55,17 @@ import io.element.android.libraries.designsystem.atomic.atoms.UnreadIndicatorAto
|
|||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
import io.element.android.libraries.designsystem.theme.components.ButtonSize
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.roomListRoomMessage
|
||||
import io.element.android.libraries.designsystem.theme.roomListRoomMessageDate
|
||||
import io.element.android.libraries.designsystem.theme.roomListRoomName
|
||||
import io.element.android.libraries.designsystem.theme.unreadIndicator
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
internal val minHeight = 84.dp
|
||||
|
||||
|
|
@ -66,27 +76,53 @@ internal fun RoomSummaryRow(
|
|||
onLongClick: (RoomListRoomSummary) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
if (room.isPlaceholder) {
|
||||
RoomSummaryPlaceholderRow(
|
||||
modifier = modifier,
|
||||
)
|
||||
} else {
|
||||
RoomSummaryRealRow(
|
||||
room = room,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
modifier = modifier
|
||||
)
|
||||
when (room.type) {
|
||||
DisplayType.PLACEHOLDER -> {
|
||||
RoomSummaryPlaceholderRow(modifier = modifier)
|
||||
}
|
||||
DisplayType.INVITE -> {
|
||||
RoomSummaryScaffoldRow(
|
||||
room = room,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
modifier = modifier
|
||||
) {
|
||||
InviteNameAndIndicatorRow(name = room.name)
|
||||
InviteSubtitle(isDirect = room.isDirect, inviteSender = room.inviteSender, canonicalAlias = room.canonicalAlias)
|
||||
if (!room.isDirect && room.inviteSender != null) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
InviteSenderRow(sender = room.inviteSender)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
InviteButtonsRow(onAcceptClicked = { }, onDeclineClicked = { })
|
||||
}
|
||||
}
|
||||
DisplayType.ROOM -> {
|
||||
RoomSummaryScaffoldRow(
|
||||
room = room,
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
modifier = modifier
|
||||
) {
|
||||
NameAndTimestampRow(
|
||||
name = room.name,
|
||||
timestamp = room.timestamp,
|
||||
isHighlighted = room.isHighlighted
|
||||
)
|
||||
LastMessageAndIndicatorRow(room = room)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun RoomSummaryRealRow(
|
||||
private fun RoomSummaryScaffoldRow(
|
||||
room: RoomListRoomSummary,
|
||||
onClick: (RoomListRoomSummary) -> Unit,
|
||||
onLongClick: (RoomListRoomSummary) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable ColumnScope.() -> Unit
|
||||
) {
|
||||
val clickModifier = Modifier.combinedClickable(
|
||||
onClick = { onClick(room) },
|
||||
|
|
@ -97,97 +133,189 @@ private fun RoomSummaryRealRow(
|
|||
|
||||
Row(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.heightIn(min = minHeight)
|
||||
.then(clickModifier)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 11.dp)
|
||||
.height(IntrinsicSize.Min),
|
||||
) {
|
||||
Avatar(
|
||||
room
|
||||
.avatarData,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp)
|
||||
.heightIn(min = minHeight)
|
||||
.then(clickModifier)
|
||||
.padding(horizontal = 16.dp, vertical = 11.dp)
|
||||
.height(IntrinsicSize.Min),
|
||||
) {
|
||||
Avatar(room.avatarData)
|
||||
Spacer(modifier = Modifier.width(16.dp))
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NameAndTimestampRow(
|
||||
name: String,
|
||||
timestamp: String?,
|
||||
isHighlighted: Boolean,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
horizontalArrangement = spacedBy(16.dp)
|
||||
) {
|
||||
// Name
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
text = name,
|
||||
color = MaterialTheme.roomListRoomName(),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
// Timestamp
|
||||
Text(
|
||||
text = timestamp ?: "",
|
||||
style = ElementTheme.typography.fontBodySmMedium,
|
||||
color = if (isHighlighted) {
|
||||
ElementTheme.colors.unreadIndicator
|
||||
} else {
|
||||
MaterialTheme.roomListRoomMessageDate()
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InviteSubtitle(
|
||||
isDirect: Boolean,
|
||||
inviteSender: InviteSender?,
|
||||
canonicalAlias: String?,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val subtitle = if (isDirect) {
|
||||
inviteSender?.userId?.value
|
||||
} else {
|
||||
canonicalAlias
|
||||
}
|
||||
if (subtitle != null) {
|
||||
Text(
|
||||
text = subtitle,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = MaterialTheme.roomListRoomMessage(),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LastMessageAndIndicatorRow(
|
||||
room: RoomListRoomSummary,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
horizontalArrangement = spacedBy(28.dp)
|
||||
) {
|
||||
// Last Message
|
||||
val attributedLastMessage = room.lastMessage as? AnnotatedString
|
||||
?: AnnotatedString(room.lastMessage.orEmpty().toString())
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
text = attributedLastMessage,
|
||||
color = MaterialTheme.roomListRoomMessage(),
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
minLines = 2,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
// Call and unread
|
||||
Row(
|
||||
modifier = Modifier.height(16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
NameAndTimestampRow(room = room)
|
||||
val tint = if (room.isHighlighted) ElementTheme.colors.unreadIndicator else ElementTheme.colors.iconQuaternary
|
||||
if (room.hasRoomCall) {
|
||||
OnGoingCallIcon(
|
||||
color = tint,
|
||||
)
|
||||
}
|
||||
Row(modifier = Modifier.fillMaxWidth()) {
|
||||
LastMessageAndIndicatorRow(room = room)
|
||||
if (room.userDefinedNotificationMode == RoomNotificationMode.MUTE) {
|
||||
NotificationOffIndicatorAtom()
|
||||
} else if (room.numberOfUnreadMentions > 0) {
|
||||
MentionIndicatorAtom()
|
||||
}
|
||||
if (room.hasNewContent) {
|
||||
UnreadIndicatorAtom(
|
||||
color = tint
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RowScope.NameAndTimestampRow(room: RoomListRoomSummary) {
|
||||
// Name
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(end = 16.dp),
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
text = room.name,
|
||||
color = MaterialTheme.roomListRoomName(),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
// Timestamp
|
||||
Text(
|
||||
text = room.timestamp ?: "",
|
||||
style = ElementTheme.typography.fontBodySmMedium,
|
||||
color = if (room.isHighlighted) {
|
||||
ElementTheme.colors.unreadIndicator
|
||||
} else {
|
||||
MaterialTheme.roomListRoomMessageDate()
|
||||
},
|
||||
)
|
||||
private fun InviteNameAndIndicatorRow(
|
||||
name: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
horizontalArrangement = spacedBy(16.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.weight(1f),
|
||||
style = ElementTheme.typography.fontBodyLgMedium,
|
||||
text = name,
|
||||
color = MaterialTheme.roomListRoomName(),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
UnreadIndicatorAtom(
|
||||
color = ElementTheme.colors.unreadIndicator
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RowScope.LastMessageAndIndicatorRow(room: RoomListRoomSummary) {
|
||||
// Last Message
|
||||
val attributedLastMessage = room.lastMessage as? AnnotatedString
|
||||
?: AnnotatedString(room.lastMessage.orEmpty().toString())
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(end = 28.dp),
|
||||
text = attributedLastMessage,
|
||||
color = MaterialTheme.roomListRoomMessage(),
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
minLines = 2,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
// Call and unread
|
||||
private fun InviteSenderRow(
|
||||
sender: InviteSender,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.height(16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
) {
|
||||
val tint = if (room.isHighlighted) ElementTheme.colors.unreadIndicator else ElementTheme.colors.iconQuaternary
|
||||
if (room.hasRoomCall) {
|
||||
OnGoingCallIcon(
|
||||
color = tint,
|
||||
)
|
||||
}
|
||||
if (room.userDefinedNotificationMode == RoomNotificationMode.MUTE) {
|
||||
NotificationOffIndicatorAtom()
|
||||
} else if (room.numberOfUnreadMentions > 0) {
|
||||
MentionIndicatorAtom()
|
||||
}
|
||||
if (room.hasNewContent) {
|
||||
UnreadIndicatorAtom(
|
||||
color = tint
|
||||
)
|
||||
}
|
||||
Avatar(avatarData = sender.avatarData)
|
||||
Text(
|
||||
text = sender.annotatedString(),
|
||||
style = ElementTheme.typography.fontBodyMdRegular,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun InviteButtonsRow(
|
||||
onAcceptClicked: () -> Unit,
|
||||
onDeclineClicked: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.padding(),
|
||||
horizontalArrangement = spacedBy(12.dp)
|
||||
) {
|
||||
OutlinedButton(
|
||||
text = stringResource(CommonStrings.action_decline),
|
||||
onClick = onDeclineClicked,
|
||||
size = ButtonSize.Medium,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
Button(
|
||||
text = stringResource(CommonStrings.action_accept),
|
||||
onClick = onAcceptClicked,
|
||||
size = ButtonSize.Medium,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,13 +16,16 @@
|
|||
|
||||
package io.element.android.features.roomlist.impl.datasource
|
||||
|
||||
import io.element.android.features.roomlist.impl.model.InviteSender
|
||||
import io.element.android.features.roomlist.impl.model.RoomListRoomSummary
|
||||
import io.element.android.features.roomlist.impl.model.DisplayType
|
||||
import io.element.android.libraries.core.extensions.orEmpty
|
||||
import io.element.android.libraries.dateformatter.api.LastMessageTimestampFormatter
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.eventformatter.api.RoomLastMessageFormatter
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
|
||||
import io.element.android.libraries.matrix.api.roomlist.RoomSummary
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -35,7 +38,7 @@ class RoomListRoomSummaryFactory @Inject constructor(
|
|||
return RoomListRoomSummary(
|
||||
id = id,
|
||||
roomId = RoomId(id),
|
||||
isPlaceholder = true,
|
||||
type = DisplayType.PLACEHOLDER,
|
||||
name = "Short name",
|
||||
timestamp = "hh:mm",
|
||||
lastMessage = "Last message for placeholder",
|
||||
|
|
@ -46,8 +49,10 @@ class RoomListRoomSummaryFactory @Inject constructor(
|
|||
isMarkedUnread = false,
|
||||
userDefinedNotificationMode = null,
|
||||
hasRoomCall = false,
|
||||
isDm = false,
|
||||
isDirect = false,
|
||||
isFavorite = false,
|
||||
inviteSender = null,
|
||||
canonicalAlias = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -73,11 +78,28 @@ class RoomListRoomSummaryFactory @Inject constructor(
|
|||
roomLastMessageFormatter.format(message.event, roomSummary.details.isDirect)
|
||||
}.orEmpty(),
|
||||
avatarData = avatarData,
|
||||
isPlaceholder = false,
|
||||
userDefinedNotificationMode = roomSummary.details.userDefinedNotificationMode,
|
||||
hasRoomCall = roomSummary.details.hasRoomCall,
|
||||
isDm = roomSummary.details.isDm,
|
||||
isDirect = roomSummary.details.isDirect,
|
||||
isFavorite = roomSummary.details.isFavorite,
|
||||
inviteSender = roomSummary.details.inviter?.run {
|
||||
InviteSender(
|
||||
userId = userId,
|
||||
displayName = displayName ?: "",
|
||||
avatarData = AvatarData(
|
||||
id = userId.value,
|
||||
name = displayName,
|
||||
url = avatarUrl,
|
||||
size = AvatarSize.InviteSender,
|
||||
),
|
||||
)
|
||||
},
|
||||
canonicalAlias = roomSummary.details.canonicalAlias,
|
||||
type = if (roomSummary.details.currentUserMembership == CurrentUserMembership.INVITED) {
|
||||
DisplayType.INVITE
|
||||
} else {
|
||||
DisplayType.ROOM
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (c) 2024 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.roomlist.impl.model
|
||||
|
||||
/**
|
||||
* Represents the type of display for a room list item.
|
||||
*/
|
||||
enum class DisplayType {
|
||||
PLACEHOLDER,
|
||||
ROOM,
|
||||
INVITE
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2024 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.features.roomlist.impl.model
|
||||
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import io.element.android.features.roomlist.impl.R
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
|
||||
@Immutable
|
||||
data class InviteSender(
|
||||
val userId: UserId,
|
||||
val displayName: String,
|
||||
val avatarData: AvatarData,
|
||||
) {
|
||||
|
||||
@Composable
|
||||
fun annotatedString(): AnnotatedString {
|
||||
return stringResource(R.string.screen_invites_invited_you, displayName, userId.value).let { text ->
|
||||
val senderNameStart = LocalContext.current.getString(R.string.screen_invites_invited_you).indexOf("%1\$s")
|
||||
AnnotatedString(
|
||||
text = text,
|
||||
spanStyles = listOf(
|
||||
AnnotatedString.Range(
|
||||
SpanStyle(
|
||||
fontWeight = FontWeight.Medium,
|
||||
color = MaterialTheme.colorScheme.primary
|
||||
),
|
||||
start = senderNameStart,
|
||||
end = senderNameStart + displayName.length
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,8 +24,10 @@ import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
|||
@Immutable
|
||||
data class RoomListRoomSummary(
|
||||
val id: String,
|
||||
val type: DisplayType,
|
||||
val roomId: RoomId,
|
||||
val name: String,
|
||||
val canonicalAlias: String?,
|
||||
val numberOfUnreadMessages: Int,
|
||||
val numberOfUnreadMentions: Int,
|
||||
val numberOfUnreadNotifications: Int,
|
||||
|
|
@ -33,18 +35,21 @@ data class RoomListRoomSummary(
|
|||
val timestamp: String?,
|
||||
val lastMessage: CharSequence?,
|
||||
val avatarData: AvatarData,
|
||||
val isPlaceholder: Boolean,
|
||||
val userDefinedNotificationMode: RoomNotificationMode?,
|
||||
val hasRoomCall: Boolean,
|
||||
val isDm: Boolean,
|
||||
val isDirect: Boolean,
|
||||
val isFavorite: Boolean,
|
||||
) {
|
||||
val inviteSender: InviteSender?,
|
||||
|
||||
) {
|
||||
val isHighlighted = userDefinedNotificationMode != RoomNotificationMode.MUTE &&
|
||||
(numberOfUnreadNotifications > 0 || numberOfUnreadMentions > 0) ||
|
||||
isMarkedUnread
|
||||
isMarkedUnread ||
|
||||
type == DisplayType.INVITE
|
||||
|
||||
val hasNewContent = numberOfUnreadMessages > 0 ||
|
||||
numberOfUnreadMentions > 0 ||
|
||||
numberOfUnreadNotifications > 0 ||
|
||||
isMarkedUnread
|
||||
isMarkedUnread ||
|
||||
type == DisplayType.INVITE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,13 +20,14 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
|
||||
open class RoomListRoomSummaryProvider : PreviewParameterProvider<RoomListRoomSummary> {
|
||||
override val values: Sequence<RoomListRoomSummary>
|
||||
get() = sequenceOf(
|
||||
listOf(
|
||||
aRoomListRoomSummary(isPlaceholder = true),
|
||||
aRoomListRoomSummary(displayType = DisplayType.PLACEHOLDER),
|
||||
aRoomListRoomSummary(),
|
||||
aRoomListRoomSummary(lastMessage = null),
|
||||
aRoomListRoomSummary(
|
||||
|
|
@ -80,6 +81,27 @@ open class RoomListRoomSummaryProvider : PreviewParameterProvider<RoomListRoomSu
|
|||
)
|
||||
}.flatten()
|
||||
}.flatten(),
|
||||
listOf(
|
||||
aRoomListRoomSummary(
|
||||
displayType = DisplayType.INVITE,
|
||||
inviteSender = InviteSender(
|
||||
userId = UserId("@alice:matrix.org"),
|
||||
displayName = "Alice",
|
||||
avatarData = AvatarData("@alice:matrix.org", "Alice", size = AvatarSize.InviteSender),
|
||||
),
|
||||
canonicalAlias = "#alias:matrix.org",
|
||||
),
|
||||
aRoomListRoomSummary(
|
||||
name = "Bob",
|
||||
displayType = DisplayType.INVITE,
|
||||
inviteSender = InviteSender(
|
||||
userId = UserId("@bob:matrix.org"),
|
||||
displayName = "Bob",
|
||||
avatarData = AvatarData("@bob:matrix.org", "Bob", size = AvatarSize.InviteSender),
|
||||
),
|
||||
isDirect = true,
|
||||
)
|
||||
),
|
||||
).flatten()
|
||||
}
|
||||
|
||||
|
|
@ -92,12 +114,14 @@ internal fun aRoomListRoomSummary(
|
|||
isMarkedUnread: Boolean = false,
|
||||
lastMessage: String? = "Last message",
|
||||
timestamp: String? = lastMessage?.let { "88:88" },
|
||||
isPlaceholder: Boolean = false,
|
||||
notificationMode: RoomNotificationMode? = null,
|
||||
hasRoomCall: Boolean = false,
|
||||
avatarData: AvatarData = AvatarData(id, name, size = AvatarSize.RoomListItem),
|
||||
isDm: Boolean = false,
|
||||
isDirect: Boolean = false,
|
||||
isFavorite: Boolean = false,
|
||||
inviteSender: InviteSender? = null,
|
||||
displayType: DisplayType = DisplayType.ROOM,
|
||||
canonicalAlias: String? = null,
|
||||
) = RoomListRoomSummary(
|
||||
id = id,
|
||||
roomId = RoomId(id),
|
||||
|
|
@ -109,9 +133,11 @@ internal fun aRoomListRoomSummary(
|
|||
timestamp = timestamp,
|
||||
lastMessage = lastMessage,
|
||||
avatarData = avatarData,
|
||||
isPlaceholder = isPlaceholder,
|
||||
userDefinedNotificationMode = notificationMode,
|
||||
hasRoomCall = hasRoomCall,
|
||||
isDm = isDm,
|
||||
isDirect = isDirect,
|
||||
isFavorite = isFavorite,
|
||||
inviteSender = inviteSender,
|
||||
type = displayType,
|
||||
canonicalAlias = canonicalAlias,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,12 @@
|
|||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<string name="confirm_recovery_key_banner_message">"Your chat backup is currently out of sync. You need to enter your recovery key to maintain access to your chat backup."</string>
|
||||
<string name="confirm_recovery_key_banner_title">"Enter your recovery key"</string>
|
||||
<string name="screen_invites_decline_chat_message">"Are you sure you want to decline the invitation to join %1$s?"</string>
|
||||
<string name="screen_invites_decline_chat_title">"Decline invite"</string>
|
||||
<string name="screen_invites_decline_direct_chat_message">"Are you sure you want to decline this private chat with %1$s?"</string>
|
||||
<string name="screen_invites_decline_direct_chat_title">"Decline chat"</string>
|
||||
<string name="screen_invites_empty_list">"No Invites"</string>
|
||||
<string name="screen_invites_invited_you">"%1$s (%2$s) invited you"</string>
|
||||
<string name="screen_migration_message">"This is a one time process, thanks for waiting."</string>
|
||||
<string name="screen_migration_title">"Setting up your account."</string>
|
||||
<string name="screen_roomlist_a11y_create_message">"Create a new conversation or room"</string>
|
||||
|
|
|
|||
|
|
@ -95,6 +95,6 @@ internal fun createRoomListRoomSummary(
|
|||
isPlaceholder = false,
|
||||
userDefinedNotificationMode = userDefinedNotificationMode,
|
||||
hasRoomCall = false,
|
||||
isDm = false,
|
||||
isDirect = false,
|
||||
isFavorite = isFavorite,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -130,7 +130,8 @@
|
|||
"screen_roomlist_.*",
|
||||
"session_verification_banner_.*",
|
||||
"confirm_recovery_key_banner_.*",
|
||||
"screen_migration_.*"
|
||||
"screen_migration_.*",
|
||||
"screen_invites_.*"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue