diff --git a/app/src/main/java/chat/revolt/api/internals/Roles.kt b/app/src/main/java/chat/revolt/api/internals/Roles.kt new file mode 100644 index 00000000..f7ee2d59 --- /dev/null +++ b/app/src/main/java/chat/revolt/api/internals/Roles.kt @@ -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? { + return roles.minByOrNull { role -> + role?.rank ?: 0.0 + } + } + + private fun highestRoleWithColour(roles: List): 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) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/api/internals/WebCompat.kt b/app/src/main/java/chat/revolt/api/internals/WebCompat.kt index cb0e6423..266f7cab 100644 --- a/app/src/main/java/chat/revolt/api/internals/WebCompat.kt +++ b/app/src/main/java/chat/revolt/api/internals/WebCompat.kt @@ -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 { @Composable private fun parseLinearGradient(gradient: String): Brush { @@ -59,15 +72,7 @@ object WebCompat { ) } - else -> parseFunctionColour(colourPart) ?: try { - 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 - } + else -> parseFunctionColour(colourPart) ?: parseColourName(colourPart) } val stop = if (splitPart.size == 2) { @@ -149,6 +154,28 @@ object WebCompat { 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 fun parseColour(colour: String): Brush { when { @@ -172,15 +199,7 @@ object WebCompat { } else -> { - return try { - 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) - } + return Brush.solidColor(parseColourName(colour)) } } } diff --git a/app/src/main/java/chat/revolt/components/chat/InReplyTo.kt b/app/src/main/java/chat/revolt/components/chat/InReplyTo.kt index 7561b8a5..3445254f 100644 --- a/app/src/main/java/chat/revolt/components/chat/InReplyTo.kt +++ b/app/src/main/java/chat/revolt/components/chat/InReplyTo.kt @@ -44,7 +44,8 @@ fun InReplyTo( ?: stringResource(id = R.string.unknown) val contentColor = LocalContentColor.current - val usernameColor = message?.let { authorColour(it) } ?: Brush.solidColor(contentColor) + val usernameColor = + message?.let { authorColour(it) } ?: Brush.solidColor(contentColor) Box( modifier = modifier diff --git a/app/src/main/java/chat/revolt/components/chat/Message.kt b/app/src/main/java/chat/revolt/components/chat/Message.kt index d8207d77..76522715 100644 --- a/app/src/main/java/chat/revolt/components/chat/Message.kt +++ b/app/src/main/java/chat/revolt/components/chat/Message.kt @@ -35,7 +35,6 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb import androidx.compose.ui.platform.LocalContext 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.api.REVOLT_FILES import chat.revolt.api.RevoltAPI +import chat.revolt.api.internals.Roles import chat.revolt.api.internals.SpecialUsers import chat.revolt.api.internals.ULID import chat.revolt.api.internals.WebCompat @@ -66,7 +66,16 @@ fun authorColour(message: MessageSchema): Brush { return if (message.masquerade?.colour != null) { WebCompat.parseColour(message.masquerade.colour) } 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 ) } - ?: false, + ?: false ) { // TODO Add jump to message if (replyMessage == null) { @@ -218,12 +227,7 @@ fun Message( text = authorName(message), style = LocalTextStyle.current.copy( fontWeight = FontWeight.Bold, - brush = if (message.author == RevoltAPI.selfId) Brush.horizontalGradient( - listOf( - Color.Magenta, - Color.Cyan, - ), - ) else authorColour(message), + brush = authorColour(message), ), maxLines = 1, overflow = TextOverflow.Ellipsis