Add room badges (#2822)
* Add room badges * Remove no longer used `onShareRoomMember` callback * Update screenshots * Add changelog --------- Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
parent
e0c7784180
commit
e1694fa4e8
188 changed files with 355 additions and 80 deletions
1
changelog.d/2822.misc
Normal file
1
changelog.d/2822.misc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add room badges to room details screen.
|
||||||
|
|
@ -32,9 +32,7 @@ import im.vector.app.features.analytics.plan.MobileScreen
|
||||||
import io.element.android.anvilannotations.ContributesNode
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
import io.element.android.libraries.androidutils.system.startSharePlainTextIntent
|
import io.element.android.libraries.androidutils.system.startSharePlainTextIntent
|
||||||
import io.element.android.libraries.di.RoomScope
|
import io.element.android.libraries.di.RoomScope
|
||||||
import io.element.android.libraries.matrix.api.permalink.PermalinkBuilder
|
|
||||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
|
||||||
import io.element.android.services.analytics.api.AnalyticsService
|
import io.element.android.services.analytics.api.AnalyticsService
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -48,7 +46,6 @@ class RoomDetailsNode @AssistedInject constructor(
|
||||||
private val presenter: RoomDetailsPresenter,
|
private val presenter: RoomDetailsPresenter,
|
||||||
private val room: MatrixRoom,
|
private val room: MatrixRoom,
|
||||||
private val analyticsService: AnalyticsService,
|
private val analyticsService: AnalyticsService,
|
||||||
private val permalinkBuilder: PermalinkBuilder,
|
|
||||||
) : Node(buildContext, plugins = plugins) {
|
) : Node(buildContext, plugins = plugins) {
|
||||||
interface Callback : Plugin {
|
interface Callback : Plugin {
|
||||||
fun openRoomMemberList()
|
fun openRoomMemberList()
|
||||||
|
|
@ -106,22 +103,6 @@ class RoomDetailsNode @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onShareMember(context: Context, member: RoomMember) {
|
|
||||||
val permalinkResult = permalinkBuilder.permalinkForUser(member.userId)
|
|
||||||
permalinkResult
|
|
||||||
.onSuccess { permalink ->
|
|
||||||
context.startSharePlainTextIntent(
|
|
||||||
activityResultLauncher = null,
|
|
||||||
chooserTitle = context.getString(R.string.screen_room_details_share_room_title),
|
|
||||||
text = permalink,
|
|
||||||
noActivityFoundMessage = context.getString(AndroidUtilsR.string.error_no_compatible_app_found)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
.onFailure {
|
|
||||||
Timber.e(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onEditRoomDetails() {
|
private fun onEditRoomDetails() {
|
||||||
callbacks.forEach { it.editRoomDetails() }
|
callbacks.forEach { it.editRoomDetails() }
|
||||||
}
|
}
|
||||||
|
|
@ -143,10 +124,6 @@ class RoomDetailsNode @AssistedInject constructor(
|
||||||
lifecycleScope.onShareRoom(context)
|
lifecycleScope.onShareRoom(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onShareMember(roomMember: RoomMember) {
|
|
||||||
this.onShareMember(context, roomMember)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun onActionClicked(action: RoomDetailsAction) {
|
fun onActionClicked(action: RoomDetailsAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
RoomDetailsAction.Edit -> onEditRoomDetails()
|
RoomDetailsAction.Edit -> onEditRoomDetails()
|
||||||
|
|
@ -160,7 +137,6 @@ class RoomDetailsNode @AssistedInject constructor(
|
||||||
goBack = this::navigateUp,
|
goBack = this::navigateUp,
|
||||||
onActionClicked = ::onActionClicked,
|
onActionClicked = ::onActionClicked,
|
||||||
onShareRoom = ::onShareRoom,
|
onShareRoom = ::onShareRoom,
|
||||||
onShareMember = ::onShareMember,
|
|
||||||
openRoomMemberList = ::openRoomMemberList,
|
openRoomMemberList = ::openRoomMemberList,
|
||||||
openRoomNotificationSettings = ::openRoomNotificationSettings,
|
openRoomNotificationSettings = ::openRoomNotificationSettings,
|
||||||
invitePeople = ::invitePeople,
|
invitePeople = ::invitePeople,
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ class RoomDetailsPresenter @Inject constructor(
|
||||||
val roomName by remember { derivedStateOf { (roomInfo?.name ?: room.name ?: room.displayName).trim() } }
|
val roomName by remember { derivedStateOf { (roomInfo?.name ?: room.name ?: room.displayName).trim() } }
|
||||||
val roomTopic by remember { derivedStateOf { roomInfo?.topic ?: room.topic } }
|
val roomTopic by remember { derivedStateOf { roomInfo?.topic ?: room.topic } }
|
||||||
val isFavorite by remember { derivedStateOf { roomInfo?.isFavorite.orFalse() } }
|
val isFavorite by remember { derivedStateOf { roomInfo?.isFavorite.orFalse() } }
|
||||||
|
val isPublic by remember { derivedStateOf { roomInfo?.isPublic.orFalse() } }
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
canShowNotificationSettings.value = featureFlagService.isFeatureEnabled(FeatureFlags.NotificationSettings)
|
canShowNotificationSettings.value = featureFlagService.isFeatureEnabled(FeatureFlags.NotificationSettings)
|
||||||
|
|
@ -149,6 +150,7 @@ class RoomDetailsPresenter @Inject constructor(
|
||||||
roomNotificationSettings = roomNotificationSettingsState.roomNotificationSettings(),
|
roomNotificationSettings = roomNotificationSettingsState.roomNotificationSettings(),
|
||||||
isFavorite = isFavorite,
|
isFavorite = isFavorite,
|
||||||
displayRolesAndPermissionsSettings = !room.isDm && isUserAdmin,
|
displayRolesAndPermissionsSettings = !room.isDm && isUserAdmin,
|
||||||
|
isPublic = isPublic,
|
||||||
eventSink = ::handleEvents,
|
eventSink = ::handleEvents,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ data class RoomDetailsState(
|
||||||
val roomNotificationSettings: RoomNotificationSettings?,
|
val roomNotificationSettings: RoomNotificationSettings?,
|
||||||
val isFavorite: Boolean,
|
val isFavorite: Boolean,
|
||||||
val displayRolesAndPermissionsSettings: Boolean,
|
val displayRolesAndPermissionsSettings: Boolean,
|
||||||
|
val isPublic: Boolean,
|
||||||
val eventSink: (RoomDetailsEvent) -> Unit
|
val eventSink: (RoomDetailsEvent) -> Unit
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ open class RoomDetailsStateProvider : PreviewParameterProvider<RoomDetailsState>
|
||||||
roomNotificationSettings = aRoomNotificationSettings(mode = RoomNotificationMode.ALL_MESSAGES, isDefault = true)
|
roomNotificationSettings = aRoomNotificationSettings(mode = RoomNotificationMode.ALL_MESSAGES, isDefault = true)
|
||||||
),
|
),
|
||||||
aRoomDetailsState(canCall = false, canInvite = false),
|
aRoomDetailsState(canCall = false, canInvite = false),
|
||||||
|
aRoomDetailsState(isPublic = false),
|
||||||
// Add other state here
|
// Add other state here
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -97,6 +98,7 @@ fun aRoomDetailsState(
|
||||||
roomNotificationSettings: RoomNotificationSettings = aRoomNotificationSettings(),
|
roomNotificationSettings: RoomNotificationSettings = aRoomNotificationSettings(),
|
||||||
isFavorite: Boolean = false,
|
isFavorite: Boolean = false,
|
||||||
displayAdminSettings: Boolean = false,
|
displayAdminSettings: Boolean = false,
|
||||||
|
isPublic: Boolean = true,
|
||||||
eventSink: (RoomDetailsEvent) -> Unit = {},
|
eventSink: (RoomDetailsEvent) -> Unit = {},
|
||||||
) = RoomDetailsState(
|
) = RoomDetailsState(
|
||||||
roomId = roomId,
|
roomId = roomId,
|
||||||
|
|
@ -116,6 +118,7 @@ fun aRoomDetailsState(
|
||||||
roomNotificationSettings = roomNotificationSettings,
|
roomNotificationSettings = roomNotificationSettings,
|
||||||
isFavorite = isFavorite,
|
isFavorite = isFavorite,
|
||||||
displayRolesAndPermissionsSettings = displayAdminSettings,
|
displayRolesAndPermissionsSettings = displayAdminSettings,
|
||||||
|
isPublic = isPublic,
|
||||||
eventSink = eventSink
|
eventSink = eventSink
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ import androidx.compose.ui.unit.dp
|
||||||
import io.element.android.compound.theme.ElementTheme
|
import io.element.android.compound.theme.ElementTheme
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
import io.element.android.features.leaveroom.api.LeaveRoomView
|
import io.element.android.features.leaveroom.api.LeaveRoomView
|
||||||
|
import io.element.android.features.roomdetails.impl.components.RoomBadge
|
||||||
import io.element.android.features.userprofile.shared.UserProfileHeaderSection
|
import io.element.android.features.userprofile.shared.UserProfileHeaderSection
|
||||||
import io.element.android.features.userprofile.shared.blockuser.BlockUserDialogs
|
import io.element.android.features.userprofile.shared.blockuser.BlockUserDialogs
|
||||||
import io.element.android.features.userprofile.shared.blockuser.BlockUserSection
|
import io.element.android.features.userprofile.shared.blockuser.BlockUserSection
|
||||||
|
|
@ -78,7 +79,6 @@ import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
import io.element.android.libraries.designsystem.utils.CommonDrawables
|
||||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
import io.element.android.libraries.matrix.api.room.getBestName
|
import io.element.android.libraries.matrix.api.room.getBestName
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
|
|
@ -91,7 +91,6 @@ fun RoomDetailsView(
|
||||||
goBack: () -> Unit,
|
goBack: () -> Unit,
|
||||||
onActionClicked: (RoomDetailsAction) -> Unit,
|
onActionClicked: (RoomDetailsAction) -> Unit,
|
||||||
onShareRoom: () -> Unit,
|
onShareRoom: () -> Unit,
|
||||||
onShareMember: (RoomMember) -> Unit,
|
|
||||||
openRoomMemberList: () -> Unit,
|
openRoomMemberList: () -> Unit,
|
||||||
openRoomNotificationSettings: () -> Unit,
|
openRoomNotificationSettings: () -> Unit,
|
||||||
invitePeople: () -> Unit,
|
invitePeople: () -> Unit,
|
||||||
|
|
@ -101,10 +100,6 @@ fun RoomDetailsView(
|
||||||
onJoinCallClicked: () -> Unit,
|
onJoinCallClicked: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
fun onShareMember() {
|
|
||||||
onShareMember((state.roomType as RoomDetailsType.Dm).roomMember)
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
topBar = {
|
topBar = {
|
||||||
|
|
@ -130,6 +125,8 @@ fun RoomDetailsView(
|
||||||
roomId = state.roomId,
|
roomId = state.roomId,
|
||||||
roomName = state.roomName,
|
roomName = state.roomName,
|
||||||
roomAlias = state.roomAlias,
|
roomAlias = state.roomAlias,
|
||||||
|
isEncrypted = state.isEncrypted,
|
||||||
|
isPublic = state.isPublic,
|
||||||
openAvatarPreview = { avatarUrl ->
|
openAvatarPreview = { avatarUrl ->
|
||||||
openAvatarPreview(state.roomName, avatarUrl)
|
openAvatarPreview(state.roomName, avatarUrl)
|
||||||
},
|
},
|
||||||
|
|
@ -160,7 +157,7 @@ fun RoomDetailsView(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer(Modifier.height(18.dp))
|
Spacer(Modifier.height(12.dp))
|
||||||
|
|
||||||
if (state.roomTopic !is RoomTopicState.Hidden) {
|
if (state.roomTopic !is RoomTopicState.Hidden) {
|
||||||
TopicSection(
|
TopicSection(
|
||||||
|
|
@ -269,7 +266,9 @@ private fun MainActionsSection(
|
||||||
onCall: () -> Unit,
|
onCall: () -> Unit,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||||
) {
|
) {
|
||||||
val roomNotificationSettings = state.roomNotificationSettings
|
val roomNotificationSettings = state.roomNotificationSettings
|
||||||
|
|
@ -323,6 +322,8 @@ private fun RoomHeaderSection(
|
||||||
roomId: RoomId,
|
roomId: RoomId,
|
||||||
roomName: String,
|
roomName: String,
|
||||||
roomAlias: RoomAlias?,
|
roomAlias: RoomAlias?,
|
||||||
|
isEncrypted: Boolean,
|
||||||
|
isPublic: Boolean,
|
||||||
openAvatarPreview: (url: String) -> Unit,
|
openAvatarPreview: (url: String) -> Unit,
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
|
|
@ -353,10 +354,46 @@ private fun RoomHeaderSection(
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
BadgeList(isEncrypted = isEncrypted, isPublic = isPublic)
|
||||||
Spacer(Modifier.height(32.dp))
|
Spacer(Modifier.height(32.dp))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun BadgeList(
|
||||||
|
isEncrypted: Boolean,
|
||||||
|
isPublic: Boolean,
|
||||||
|
) {
|
||||||
|
if (isEncrypted || isPublic) {
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
if (isEncrypted) {
|
||||||
|
RoomBadge.View(
|
||||||
|
text = stringResource(R.string.screen_room_details_badge_encrypted),
|
||||||
|
icon = CompoundIcons.LockSolid(),
|
||||||
|
type = RoomBadge.Type.Positive,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
RoomBadge.View(
|
||||||
|
text = stringResource(R.string.screen_room_details_badge_not_encrypted),
|
||||||
|
icon = CompoundIcons.LockOff(),
|
||||||
|
type = RoomBadge.Type.Neutral,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (isPublic) {
|
||||||
|
RoomBadge.View(
|
||||||
|
text = stringResource(R.string.screen_room_details_badge_public),
|
||||||
|
icon = CompoundIcons.Public(),
|
||||||
|
type = RoomBadge.Type.Neutral,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun TopicSection(
|
private fun TopicSection(
|
||||||
roomTopic: RoomTopicState,
|
roomTopic: RoomTopicState,
|
||||||
|
|
@ -489,7 +526,6 @@ private fun ContentToPreview(state: RoomDetailsState) {
|
||||||
goBack = {},
|
goBack = {},
|
||||||
onActionClicked = {},
|
onActionClicked = {},
|
||||||
onShareRoom = {},
|
onShareRoom = {},
|
||||||
onShareMember = {},
|
|
||||||
openRoomMemberList = {},
|
openRoomMemberList = {},
|
||||||
openRoomNotificationSettings = {},
|
openRoomNotificationSettings = {},
|
||||||
invitePeople = {},
|
invitePeople = {},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
* 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.roomdetails.impl.components
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import io.element.android.compound.theme.ElementTheme
|
||||||
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
|
import io.element.android.libraries.designsystem.components.Badge
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
import io.element.android.libraries.designsystem.theme.badgeNegativeBackgroundColor
|
||||||
|
import io.element.android.libraries.designsystem.theme.badgeNegativeContentColor
|
||||||
|
import io.element.android.libraries.designsystem.theme.badgeNeutralBackgroundColor
|
||||||
|
import io.element.android.libraries.designsystem.theme.badgeNeutralContentColor
|
||||||
|
import io.element.android.libraries.designsystem.theme.badgePositiveBackgroundColor
|
||||||
|
import io.element.android.libraries.designsystem.theme.badgePositiveContentColor
|
||||||
|
|
||||||
|
object RoomBadge {
|
||||||
|
enum class Type {
|
||||||
|
Positive,
|
||||||
|
Neutral,
|
||||||
|
Negative
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable fun View(
|
||||||
|
text: String,
|
||||||
|
icon: ImageVector,
|
||||||
|
type: Type,
|
||||||
|
) {
|
||||||
|
val backgroundColor = when (type) {
|
||||||
|
Type.Positive -> ElementTheme.colors.badgePositiveBackgroundColor
|
||||||
|
Type.Neutral -> ElementTheme.colors.badgeNeutralBackgroundColor
|
||||||
|
Type.Negative -> ElementTheme.colors.badgeNegativeBackgroundColor
|
||||||
|
}
|
||||||
|
val textColor = when (type) {
|
||||||
|
Type.Positive -> ElementTheme.colors.badgePositiveContentColor
|
||||||
|
Type.Neutral -> ElementTheme.colors.badgeNeutralContentColor
|
||||||
|
Type.Negative -> ElementTheme.colors.badgeNegativeContentColor
|
||||||
|
}
|
||||||
|
val iconColor = when (type) {
|
||||||
|
Type.Positive -> ElementTheme.colors.iconSuccessPrimary
|
||||||
|
Type.Neutral -> ElementTheme.colors.iconSecondary
|
||||||
|
Type.Negative -> ElementTheme.colors.iconCriticalPrimary
|
||||||
|
}
|
||||||
|
Badge(
|
||||||
|
text = text,
|
||||||
|
icon = icon,
|
||||||
|
backgroundColor = backgroundColor,
|
||||||
|
iconColor = iconColor,
|
||||||
|
textColor = textColor,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreviewsDayNight
|
||||||
|
@Composable
|
||||||
|
internal fun RoomBadgePositivePreview() {
|
||||||
|
ElementPreview {
|
||||||
|
RoomBadge.View(
|
||||||
|
text = "Trusted",
|
||||||
|
icon = CompoundIcons.Verified(),
|
||||||
|
type = RoomBadge.Type.Positive,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreviewsDayNight
|
||||||
|
@Composable
|
||||||
|
internal fun RoomBadgeNeutralPreview() {
|
||||||
|
ElementPreview {
|
||||||
|
RoomBadge.View(
|
||||||
|
text = "Public room",
|
||||||
|
icon = CompoundIcons.Public(),
|
||||||
|
type = RoomBadge.Type.Neutral,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreviewsDayNight
|
||||||
|
@Composable
|
||||||
|
internal fun RoomBadgeNegativePreview() {
|
||||||
|
ElementPreview {
|
||||||
|
RoomBadge.View(
|
||||||
|
text = "Not trusted",
|
||||||
|
icon = CompoundIcons.Error(),
|
||||||
|
type = RoomBadge.Type.Negative,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -35,6 +35,9 @@
|
||||||
<string name="screen_room_details_add_topic_title">"Add topic"</string>
|
<string name="screen_room_details_add_topic_title">"Add topic"</string>
|
||||||
<string name="screen_room_details_already_a_member">"Already a member"</string>
|
<string name="screen_room_details_already_a_member">"Already a member"</string>
|
||||||
<string name="screen_room_details_already_invited">"Already invited"</string>
|
<string name="screen_room_details_already_invited">"Already invited"</string>
|
||||||
|
<string name="screen_room_details_badge_encrypted">"Encrypted"</string>
|
||||||
|
<string name="screen_room_details_badge_not_encrypted">"Not encrypted"</string>
|
||||||
|
<string name="screen_room_details_badge_public">"Public room"</string>
|
||||||
<string name="screen_room_details_edit_room_title">"Edit Room"</string>
|
<string name="screen_room_details_edit_room_title">"Edit Room"</string>
|
||||||
<string name="screen_room_details_edition_error">"There was an unknown error and the information couldn\'t be changed."</string>
|
<string name="screen_room_details_edition_error">"There was an unknown error and the information couldn\'t be changed."</string>
|
||||||
<string name="screen_room_details_edition_error_title">"Unable to update room"</string>
|
<string name="screen_room_details_edition_error_title">"Unable to update room"</string>
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import androidx.compose.ui.test.onNodeWithContentDescription
|
||||||
import androidx.compose.ui.test.onNodeWithTag
|
import androidx.compose.ui.test.onNodeWithTag
|
||||||
import androidx.compose.ui.test.performClick
|
import androidx.compose.ui.test.performClick
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
import io.element.android.libraries.testtags.TestTags
|
import io.element.android.libraries.testtags.TestTags
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
@ -251,7 +250,6 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setRoomD
|
||||||
goBack: () -> Unit = EnsureNeverCalled(),
|
goBack: () -> Unit = EnsureNeverCalled(),
|
||||||
onActionClicked: (RoomDetailsAction) -> Unit = EnsureNeverCalledWithParam(),
|
onActionClicked: (RoomDetailsAction) -> Unit = EnsureNeverCalledWithParam(),
|
||||||
onShareRoom: () -> Unit = EnsureNeverCalled(),
|
onShareRoom: () -> Unit = EnsureNeverCalled(),
|
||||||
onShareMember: (RoomMember) -> Unit = EnsureNeverCalledWithParam(),
|
|
||||||
openRoomMemberList: () -> Unit = EnsureNeverCalled(),
|
openRoomMemberList: () -> Unit = EnsureNeverCalled(),
|
||||||
openRoomNotificationSettings: () -> Unit = EnsureNeverCalled(),
|
openRoomNotificationSettings: () -> Unit = EnsureNeverCalled(),
|
||||||
invitePeople: () -> Unit = EnsureNeverCalled(),
|
invitePeople: () -> Unit = EnsureNeverCalled(),
|
||||||
|
|
@ -266,7 +264,6 @@ private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setRoomD
|
||||||
goBack = goBack,
|
goBack = goBack,
|
||||||
onActionClicked = onActionClicked,
|
onActionClicked = onActionClicked,
|
||||||
onShareRoom = onShareRoom,
|
onShareRoom = onShareRoom,
|
||||||
onShareMember = onShareMember,
|
|
||||||
openRoomMemberList = openRoomMemberList,
|
openRoomMemberList = openRoomMemberList,
|
||||||
openRoomNotificationSettings = openRoomNotificationSettings,
|
openRoomNotificationSettings = openRoomNotificationSettings,
|
||||||
invitePeople = invitePeople,
|
invitePeople = invitePeople,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* 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.libraries.designsystem.components
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material3.LocalContentColor
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.Shape
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
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.libraries.designsystem.preview.ElementPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||||
|
import io.element.android.libraries.designsystem.theme.badgePositiveBackgroundColor
|
||||||
|
import io.element.android.libraries.designsystem.theme.badgePositiveContentColor
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Surface
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
|
||||||
|
@Suppress("ModifierMissing")
|
||||||
|
@Composable
|
||||||
|
fun Badge(
|
||||||
|
text: String,
|
||||||
|
icon: ImageVector,
|
||||||
|
backgroundColor: Color,
|
||||||
|
textColor: Color,
|
||||||
|
iconColor: Color,
|
||||||
|
shape: Shape = RoundedCornerShape(50),
|
||||||
|
borderStroke: BorderStroke? = null,
|
||||||
|
tintIcon: Boolean = true,
|
||||||
|
) {
|
||||||
|
Surface(
|
||||||
|
color = backgroundColor,
|
||||||
|
contentColor = textColor,
|
||||||
|
border = borderStroke,
|
||||||
|
shape = shape,
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(start = 8.dp, end = 12.dp, top = 4.5.dp, bottom = 4.5.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(5.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
modifier = Modifier.size(16.dp),
|
||||||
|
imageVector = icon,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = if (tintIcon) iconColor else LocalContentColor.current,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
style = ElementTheme.typography.fontBodySmRegular,
|
||||||
|
color = textColor,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreviewsDayNight
|
||||||
|
@Composable
|
||||||
|
internal fun BadgePreview() {
|
||||||
|
ElementPreview {
|
||||||
|
Badge(
|
||||||
|
text = "Trusted",
|
||||||
|
icon = CompoundIcons.Verified(),
|
||||||
|
backgroundColor = ElementTheme.colors.badgePositiveBackgroundColor,
|
||||||
|
textColor = ElementTheme.colors.badgePositiveContentColor,
|
||||||
|
iconColor = ElementTheme.colors.iconSuccessPrimary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -153,6 +153,32 @@ val SemanticColors.bigCheckmarkBorderColor
|
||||||
val SemanticColors.highlightedMessageBackgroundColor
|
val SemanticColors.highlightedMessageBackgroundColor
|
||||||
get() = if (isLight) LightColorTokens.colorGreen300 else DarkColorTokens.colorGreen300
|
get() = if (isLight) LightColorTokens.colorGreen300 else DarkColorTokens.colorGreen300
|
||||||
|
|
||||||
|
// Badge colors
|
||||||
|
|
||||||
|
@OptIn(CoreColorToken::class)
|
||||||
|
val SemanticColors.badgePositiveBackgroundColor
|
||||||
|
get() = if (isLight) LightColorTokens.colorAlphaGreen300 else DarkColorTokens.colorAlphaGreen300
|
||||||
|
|
||||||
|
@OptIn(CoreColorToken::class)
|
||||||
|
val SemanticColors.badgePositiveContentColor
|
||||||
|
get() = if (isLight) LightColorTokens.colorGreen1100 else DarkColorTokens.colorGreen1100
|
||||||
|
|
||||||
|
@OptIn(CoreColorToken::class)
|
||||||
|
val SemanticColors.badgeNeutralBackgroundColor
|
||||||
|
get() = if (isLight) LightColorTokens.colorAlphaGray300 else DarkColorTokens.colorAlphaGray300
|
||||||
|
|
||||||
|
@OptIn(CoreColorToken::class)
|
||||||
|
val SemanticColors.badgeNeutralContentColor
|
||||||
|
get() = if (isLight) LightColorTokens.colorGray1100 else DarkColorTokens.colorGray1100
|
||||||
|
|
||||||
|
@OptIn(CoreColorToken::class)
|
||||||
|
val SemanticColors.badgeNegativeBackgroundColor
|
||||||
|
get() = if (isLight) LightColorTokens.colorAlphaRed300 else DarkColorTokens.colorAlphaRed300
|
||||||
|
|
||||||
|
@OptIn(CoreColorToken::class)
|
||||||
|
val SemanticColors.badgeNegativeContentColor
|
||||||
|
get() = if (isLight) LightColorTokens.colorRed1100 else DarkColorTokens.colorRed1100
|
||||||
|
|
||||||
@PreviewsDayNight
|
@PreviewsDayNight
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ColorAliasesPreview() = ElementPreview {
|
internal fun ColorAliasesPreview() = ElementPreview {
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,9 @@ class KonsistPreviewTest {
|
||||||
"PollContentViewEndedPreview",
|
"PollContentViewEndedPreview",
|
||||||
"PollContentViewUndisclosedPreview",
|
"PollContentViewUndisclosedPreview",
|
||||||
"ReadReceiptBottomSheetPreview",
|
"ReadReceiptBottomSheetPreview",
|
||||||
|
"RoomBadgePositivePreview",
|
||||||
|
"RoomBadgeNeutralPreview",
|
||||||
|
"RoomBadgeNegativePreview",
|
||||||
"RoomMemberListViewBannedPreview",
|
"RoomMemberListViewBannedPreview",
|
||||||
"SasEmojisPreview",
|
"SasEmojisPreview",
|
||||||
"SecureBackupSetupViewChangePreview",
|
"SecureBackupSetupViewChangePreview",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:36732b00716ecb119ec28287f6f7529d4dfaf97e73ab87b43b38bc98ae8c26a1
|
||||||
|
size 7657
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:cfb7055db252f4b67fd7a02e1d2fef518f4c341c66de80e498975cde1aafa753
|
||||||
|
size 7613
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:c0d2167073409a0f6ec2d1bb29441e155bf557f92f5f1816ebb92ba2e639c624
|
||||||
|
size 7671
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:15db0579b31a2c0f397555b4ede3e51818a0635753b1bdc1de2356c28bff6b10
|
||||||
|
size 7541
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:f2ca020d90c2244213df7e8b2b9401aefefdcab1c6d76d3f686019e4ecc2f5dd
|
||||||
|
size 7208
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:8f4eca223c607db377a78994d165d277e9e9f8b9f1d319b5995ba5395413de62
|
||||||
|
size 6925
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue