feat: material 3-ise member sheet
Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
parent
b75f540578
commit
1f81399da2
|
|
@ -0,0 +1,72 @@
|
||||||
|
package chat.revolt.components.chat
|
||||||
|
|
||||||
|
import androidx.compose.material3.ListItem
|
||||||
|
import androidx.compose.material3.LocalContentColor
|
||||||
|
import androidx.compose.material3.LocalTextStyle
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import chat.revolt.api.REVOLT_FILES
|
||||||
|
import chat.revolt.api.internals.Roles
|
||||||
|
import chat.revolt.api.internals.WebCompat
|
||||||
|
import chat.revolt.api.internals.solidColor
|
||||||
|
import chat.revolt.api.schemas.Member
|
||||||
|
import chat.revolt.api.schemas.User
|
||||||
|
import chat.revolt.components.generic.UserAvatar
|
||||||
|
import chat.revolt.components.generic.presenceFromStatus
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MemberListItem(
|
||||||
|
member: Member?,
|
||||||
|
user: User?,
|
||||||
|
serverId: String?,
|
||||||
|
userId: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
val highestColourRole = serverId?.let {
|
||||||
|
user?.id?.let { userId ->
|
||||||
|
Roles.resolveHighestRole(
|
||||||
|
it,
|
||||||
|
userId,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val colour = highestColourRole?.colour?.let { WebCompat.parseColour(it) }
|
||||||
|
?: Brush.solidColor(LocalContentColor.current)
|
||||||
|
|
||||||
|
ListItem(
|
||||||
|
modifier = modifier,
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = member?.nickname
|
||||||
|
?: user?.displayName
|
||||||
|
?: user?.username
|
||||||
|
?: user?.id
|
||||||
|
?: userId,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
style = LocalTextStyle.current.copy(brush = colour),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
UserAvatar(
|
||||||
|
username = member?.nickname
|
||||||
|
?: user?.displayName
|
||||||
|
?: user?.username
|
||||||
|
?: user?.id
|
||||||
|
?: userId,
|
||||||
|
avatar = user?.avatar,
|
||||||
|
rawUrl = member?.avatar?.let { "$REVOLT_FILES/avatars/${it.id}?max_side=256" },
|
||||||
|
userId = userId,
|
||||||
|
presence = presenceFromStatus(
|
||||||
|
user?.status?.presence,
|
||||||
|
user?.online ?: false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -9,17 +9,20 @@ import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ListHeader(
|
fun ListHeader(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
backgroundColor: Color = MaterialTheme.colorScheme.background,
|
||||||
content: @Composable () -> Unit,
|
content: @Composable () -> Unit,
|
||||||
) {
|
) {
|
||||||
CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.labelLarge) {
|
CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.labelLarge) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(MaterialTheme.colorScheme.background)
|
.background(backgroundColor)
|
||||||
.padding(top = 24.dp, bottom = 8.dp, start = 16.dp, end = 16.dp)
|
.padding(top = 24.dp, bottom = 8.dp, start = 16.dp, end = 16.dp)
|
||||||
) {
|
) {
|
||||||
content()
|
content()
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,11 @@ import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
|
@ -34,31 +29,27 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.runtime.snapshotFlow
|
import androidx.compose.runtime.snapshotFlow
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Brush
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.text.SpanStyle
|
import androidx.compose.ui.text.SpanStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.api.REVOLT_FILES
|
|
||||||
import chat.revolt.api.RevoltAPI
|
import chat.revolt.api.RevoltAPI
|
||||||
import chat.revolt.api.internals.PermissionBit
|
import chat.revolt.api.internals.PermissionBit
|
||||||
import chat.revolt.api.internals.Roles
|
import chat.revolt.api.internals.Roles
|
||||||
import chat.revolt.api.internals.WebCompat
|
|
||||||
import chat.revolt.api.internals.hasPermission
|
import chat.revolt.api.internals.hasPermission
|
||||||
import chat.revolt.api.internals.solidColor
|
|
||||||
import chat.revolt.api.routes.channel.fetchGroupParticipants
|
import chat.revolt.api.routes.channel.fetchGroupParticipants
|
||||||
import chat.revolt.api.routes.server.fetchMembers
|
import chat.revolt.api.routes.server.fetchMembers
|
||||||
import chat.revolt.api.schemas.Member
|
import chat.revolt.api.schemas.Member
|
||||||
import chat.revolt.api.schemas.User
|
import chat.revolt.api.schemas.User
|
||||||
|
import chat.revolt.components.chat.MemberListItem
|
||||||
|
import chat.revolt.components.generic.ListHeader
|
||||||
import chat.revolt.components.generic.PageHeader
|
import chat.revolt.components.generic.PageHeader
|
||||||
import chat.revolt.components.generic.Presence
|
import chat.revolt.components.generic.Presence
|
||||||
import chat.revolt.components.generic.UserAvatar
|
|
||||||
import chat.revolt.components.generic.presenceFromStatus
|
import chat.revolt.components.generic.presenceFromStatus
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
|
@ -281,24 +272,26 @@ fun MemberListSheet(
|
||||||
}
|
}
|
||||||
|
|
||||||
is MemberListItem.MemberItem -> item(key = item.member.id!!.user) {
|
is MemberListItem.MemberItem -> item(key = item.member.id!!.user) {
|
||||||
MemberListMemberUser(
|
MemberListItem(
|
||||||
user = RevoltAPI.userCache[item.member.id.user]!!,
|
user = RevoltAPI.userCache[item.member.id.user],
|
||||||
member = item.member,
|
member = item.member,
|
||||||
serverId = serverId,
|
serverId = serverId,
|
||||||
onSelectUser = {
|
userId = item.member.id.user,
|
||||||
userContextSheetTarget = it
|
modifier = Modifier.clickable {
|
||||||
|
userContextSheetTarget = item.member.id.user
|
||||||
showUserContextSheet = true
|
showUserContextSheet = true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
is MemberListItem.UserItem -> item(key = item.user.id!!) {
|
is MemberListItem.UserItem -> item(key = item.user.id!!) {
|
||||||
MemberListMemberUser(
|
MemberListItem(
|
||||||
user = item.user,
|
user = item.user,
|
||||||
member = null,
|
member = null,
|
||||||
serverId = serverId,
|
serverId = serverId,
|
||||||
onSelectUser = {
|
userId = item.user.id,
|
||||||
userContextSheetTarget = it
|
modifier = Modifier.clickable {
|
||||||
|
userContextSheetTarget = item.user.id
|
||||||
showUserContextSheet = true
|
showUserContextSheet = true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -309,86 +302,23 @@ fun MemberListSheet(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun MemberListMemberUser(
|
|
||||||
user: User,
|
|
||||||
member: Member?,
|
|
||||||
serverId: String?,
|
|
||||||
onSelectUser: (String) -> Unit
|
|
||||||
) {
|
|
||||||
val highestColourRole = serverId?.let {
|
|
||||||
user.id?.let { userId ->
|
|
||||||
Roles.resolveHighestRole(
|
|
||||||
it,
|
|
||||||
userId,
|
|
||||||
true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val colour = highestColourRole?.colour?.let { WebCompat.parseColour(it) }
|
|
||||||
?: Brush.solidColor(LocalContentColor.current)
|
|
||||||
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
|
||||||
.clickable {
|
|
||||||
onSelectUser(user.id!!)
|
|
||||||
}
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 12.dp, vertical = 8.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
UserAvatar(
|
|
||||||
username = member?.nickname
|
|
||||||
?: user.displayName
|
|
||||||
?: user.username
|
|
||||||
?: user.id!!,
|
|
||||||
avatar = user.avatar,
|
|
||||||
rawUrl = member?.avatar?.let { "$REVOLT_FILES/avatars/${it.id}?max_side=256" },
|
|
||||||
userId = user.id!!,
|
|
||||||
presence = presenceFromStatus(
|
|
||||||
user.status?.presence,
|
|
||||||
user.online ?: false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(12.dp))
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = member?.nickname
|
|
||||||
?: user.displayName
|
|
||||||
?: user.username
|
|
||||||
?: user.id,
|
|
||||||
style = LocalTextStyle.current.copy(
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
brush = colour
|
|
||||||
),
|
|
||||||
maxLines = 1,
|
|
||||||
overflow = TextOverflow.Ellipsis
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun MemberListCategory(text: String, count: Int) {
|
fun MemberListCategory(text: String, count: Int) {
|
||||||
Text(
|
ListHeader(backgroundColor = MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp)) {
|
||||||
text = AnnotatedString.Builder().apply {
|
Text(
|
||||||
pushStyle(SpanStyle(fontWeight = FontWeight.Bold))
|
text = AnnotatedString.Builder().apply {
|
||||||
append(text)
|
append(text)
|
||||||
pop()
|
|
||||||
|
|
||||||
pushStyle(
|
pushStyle(
|
||||||
SpanStyle(
|
SpanStyle(
|
||||||
fontWeight = FontWeight.Medium,
|
fontWeight = FontWeight.Medium,
|
||||||
fontSize = LocalTextStyle.current.fontSize * 0.8,
|
fontSize = LocalTextStyle.current.fontSize * 0.8,
|
||||||
color = LocalContentColor.current.copy(alpha = 0.6f)
|
color = LocalContentColor.current.copy(alpha = 0.6f)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
append("—$count")
|
||||||
append("—$count")
|
pop()
|
||||||
pop()
|
}.toAnnotatedString()
|
||||||
}.toAnnotatedString(),
|
)
|
||||||
modifier = Modifier
|
}
|
||||||
.fillMaxWidth()
|
|
||||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp))
|
|
||||||
.padding(horizontal = 12.dp, vertical = 8.dp)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ import chat.revolt.api.internals.isUlid
|
||||||
import chat.revolt.api.routes.custom.fetchEmoji
|
import chat.revolt.api.routes.custom.fetchEmoji
|
||||||
import chat.revolt.api.schemas.Emoji
|
import chat.revolt.api.schemas.Emoji
|
||||||
import chat.revolt.api.schemas.User
|
import chat.revolt.api.schemas.User
|
||||||
|
import chat.revolt.components.chat.MemberListItem
|
||||||
import chat.revolt.components.generic.RemoteImage
|
import chat.revolt.components.generic.RemoteImage
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
|
@ -210,7 +211,12 @@ fun ReactionInfoSheet(messageId: String, emoji: String, onDismiss: () -> Unit) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberListMemberUser(user = user, member = member, serverId = channel.server) {}
|
MemberListItem(
|
||||||
|
member = member,
|
||||||
|
user = user,
|
||||||
|
serverId = channel.server,
|
||||||
|
userId = reaction,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue