feat: role colours in chat
Signed-off-by: Infi <wingit@geist.ga>
This commit is contained in:
parent
dace8da8a6
commit
813b29fecd
|
|
@ -0,0 +1,36 @@
|
||||||
|
package chat.revolt.api.internals
|
||||||
|
|
||||||
|
import chat.revolt.api.RevoltAPI
|
||||||
|
import chat.revolt.api.schemas.Role
|
||||||
|
|
||||||
|
object Roles {
|
||||||
|
// lowest rank = highest role
|
||||||
|
private fun resolveHighestRole(roles: List<Role?>): Role? {
|
||||||
|
return roles.minByOrNull { role ->
|
||||||
|
role?.rank ?: 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun highestRoleWithColour(roles: List<Role?>): Role? {
|
||||||
|
return roles.filter { role ->
|
||||||
|
role?.colour != null
|
||||||
|
}.minByOrNull { role ->
|
||||||
|
role?.rank ?: 0.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resolveHighestRole(serverId: String, userId: String, withColour: Boolean = false): Role? {
|
||||||
|
val server = RevoltAPI.serverCache[serverId] ?: return null
|
||||||
|
val member = RevoltAPI.members.getMember(serverId, userId) ?: return null
|
||||||
|
|
||||||
|
val roles = member.roles?.map { roleId ->
|
||||||
|
server.roles?.get(roleId)
|
||||||
|
} ?: return null
|
||||||
|
|
||||||
|
return if (withColour) {
|
||||||
|
highestRoleWithColour(roles)
|
||||||
|
} else {
|
||||||
|
resolveHighestRole(roles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,19 @@ fun Brush.Companion.solidColor(colour: Color) = linearGradient(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Some colours that are not present in Android's built-in list.
|
||||||
|
// not exhaustive, but covers most of the ones I've seen in the wild
|
||||||
|
// for the sake of all of us, please just use hex codes
|
||||||
|
// reference: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value
|
||||||
|
private val ADDITIONAL_WEB_COLOURS = mapOf(
|
||||||
|
"orange" to Color(0xFFFFA500),
|
||||||
|
"rebeccapurple" to Color(0xFF663399),
|
||||||
|
"transparent" to Color.Transparent,
|
||||||
|
"inherit" to Color.Unspecified,
|
||||||
|
"initial" to Color.Unspecified,
|
||||||
|
"unset" to Color.Unspecified,
|
||||||
|
)
|
||||||
|
|
||||||
object WebCompat {
|
object WebCompat {
|
||||||
@Composable
|
@Composable
|
||||||
private fun parseLinearGradient(gradient: String): Brush {
|
private fun parseLinearGradient(gradient: String): Brush {
|
||||||
|
|
@ -59,15 +72,7 @@ object WebCompat {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> parseFunctionColour(colourPart) ?: try {
|
else -> parseFunctionColour(colourPart) ?: parseColourName(colourPart)
|
||||||
Color(android.graphics.Color.parseColor(colourPart))
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
Log.d(
|
|
||||||
"WebCompat",
|
|
||||||
"Failed to parse colour $colourPart in $gradient, falling back to LocalContentColor.current"
|
|
||||||
)
|
|
||||||
LocalContentColor.current
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val stop = if (splitPart.size == 2) {
|
val stop = if (splitPart.size == 2) {
|
||||||
|
|
@ -149,6 +154,28 @@ object WebCompat {
|
||||||
return Brush.solidColor(parseVarToColour(varName))
|
return Brush.solidColor(parseVarToColour(varName))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun parseColourName(colour: String): Color {
|
||||||
|
return try {
|
||||||
|
val additionalWebColour = ADDITIONAL_WEB_COLOURS[colour]
|
||||||
|
if (additionalWebColour != null) {
|
||||||
|
Log.d(
|
||||||
|
"WebCompat",
|
||||||
|
"Parsed additional web colour $colour to $additionalWebColour"
|
||||||
|
)
|
||||||
|
return additionalWebColour
|
||||||
|
}
|
||||||
|
|
||||||
|
Color(android.graphics.Color.parseColor(colour))
|
||||||
|
} catch (e: IllegalArgumentException) {
|
||||||
|
Log.d(
|
||||||
|
"WebCompat",
|
||||||
|
"Failed to parse colour $colour, falling back to LocalContentColor.current"
|
||||||
|
)
|
||||||
|
LocalContentColor.current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun parseColour(colour: String): Brush {
|
fun parseColour(colour: String): Brush {
|
||||||
when {
|
when {
|
||||||
|
|
@ -172,15 +199,7 @@ object WebCompat {
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
return try {
|
return Brush.solidColor(parseColourName(colour))
|
||||||
Brush.solidColor(Color(android.graphics.Color.parseColor(colour)))
|
|
||||||
} catch (e: IllegalArgumentException) {
|
|
||||||
Log.d(
|
|
||||||
"WebCompat",
|
|
||||||
"Failed to parse colour $colour, falling back to LocalContentColor.current"
|
|
||||||
)
|
|
||||||
Brush.solidColor(LocalContentColor.current)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,8 @@ fun InReplyTo(
|
||||||
?: stringResource(id = R.string.unknown)
|
?: stringResource(id = R.string.unknown)
|
||||||
|
|
||||||
val contentColor = LocalContentColor.current
|
val contentColor = LocalContentColor.current
|
||||||
val usernameColor = message?.let { authorColour(it) } ?: Brush.solidColor(contentColor)
|
val usernameColor =
|
||||||
|
message?.let { authorColour(it) } ?: Brush.solidColor(contentColor)
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ import androidx.compose.runtime.Composable
|
||||||
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.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
@ -50,6 +49,7 @@ import chat.revolt.activities.media.ImageViewActivity
|
||||||
import chat.revolt.activities.media.VideoViewActivity
|
import chat.revolt.activities.media.VideoViewActivity
|
||||||
import chat.revolt.api.REVOLT_FILES
|
import chat.revolt.api.REVOLT_FILES
|
||||||
import chat.revolt.api.RevoltAPI
|
import chat.revolt.api.RevoltAPI
|
||||||
|
import chat.revolt.api.internals.Roles
|
||||||
import chat.revolt.api.internals.SpecialUsers
|
import chat.revolt.api.internals.SpecialUsers
|
||||||
import chat.revolt.api.internals.ULID
|
import chat.revolt.api.internals.ULID
|
||||||
import chat.revolt.api.internals.WebCompat
|
import chat.revolt.api.internals.WebCompat
|
||||||
|
|
@ -66,7 +66,16 @@ fun authorColour(message: MessageSchema): Brush {
|
||||||
return if (message.masquerade?.colour != null) {
|
return if (message.masquerade?.colour != null) {
|
||||||
WebCompat.parseColour(message.masquerade.colour)
|
WebCompat.parseColour(message.masquerade.colour)
|
||||||
} else {
|
} else {
|
||||||
Brush.solidColor(LocalContentColor.current)
|
val defaultColour = Brush.solidColor(LocalContentColor.current)
|
||||||
|
|
||||||
|
val serverId = RevoltAPI.channelCache[message.channel]?.server ?: return defaultColour
|
||||||
|
|
||||||
|
val highestRole = message.author?.let {
|
||||||
|
Roles.resolveHighestRole(serverId, it, withColour = true)
|
||||||
|
} ?: return defaultColour
|
||||||
|
|
||||||
|
highestRole.colour?.let { WebCompat.parseColour(it) }
|
||||||
|
?: defaultColour
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,7 +180,7 @@ fun Message(
|
||||||
replyMessage.author
|
replyMessage.author
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
?: false,
|
?: false
|
||||||
) {
|
) {
|
||||||
// TODO Add jump to message
|
// TODO Add jump to message
|
||||||
if (replyMessage == null) {
|
if (replyMessage == null) {
|
||||||
|
|
@ -218,12 +227,7 @@ fun Message(
|
||||||
text = authorName(message),
|
text = authorName(message),
|
||||||
style = LocalTextStyle.current.copy(
|
style = LocalTextStyle.current.copy(
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
brush = if (message.author == RevoltAPI.selfId) Brush.horizontalGradient(
|
brush = authorColour(message),
|
||||||
listOf(
|
|
||||||
Color.Magenta,
|
|
||||||
Color.Cyan,
|
|
||||||
),
|
|
||||||
) else authorColour(message),
|
|
||||||
),
|
),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis
|
overflow = TextOverflow.Ellipsis
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue