feat: masquerade support

This commit is contained in:
Infi 2023-02-05 19:22:41 +01:00
parent fcddb8a968
commit 9017fc52a5
9 changed files with 137 additions and 21 deletions

View File

@ -23,8 +23,13 @@ const val REVOLT_BASE = "https://api.revolt.chat"
const val REVOLT_SUPPORT = "https://support.revolt.chat"
const val REVOLT_MARKETING = "https://revolt.chat"
const val REVOLT_FILES = "https://autumn.revolt.chat"
const val REVOLT_JANUARY = "https://jan.revolt.chat"
const val REVOLT_WEBSOCKET = "wss://ws.revolt.chat"
fun asJanuaryProxyUrl(url: String): String {
return "$REVOLT_JANUARY/proxy?url=${url}"
}
private const val BACKEND_IS_STABLE = false
val RevoltJson = Json { ignoreUnknownKeys = true }

View File

@ -0,0 +1,32 @@
package chat.revolt.api.internals
import android.util.Log
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
object WebCompat {
@Composable
fun parseColour(colour: String): Color {
if (colour.startsWith("var(")) {
return when (colour.substringAfter("var(").substringBefore(")")) {
"accent" -> MaterialTheme.colorScheme.primary
"foreground" -> MaterialTheme.colorScheme.onBackground
"background" -> MaterialTheme.colorScheme.background
"error" -> MaterialTheme.colorScheme.error
else -> LocalContentColor.current
}
} else {
try {
return Color(android.graphics.Color.parseColor(colour))
} catch (e: IllegalArgumentException) {
Log.d(
"WebCompat",
"Failed to parse colour $colour, falling back to LocalContentColor.current"
)
return LocalContentColor.current
}
}
}
}

View File

@ -15,6 +15,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.revolt.R
import chat.revolt.api.RevoltAPI
import chat.revolt.api.asJanuaryProxyUrl
import chat.revolt.components.generic.UserAvatar
@Composable
@ -27,6 +28,8 @@ fun InReplyTo(
val message = RevoltAPI.messageCache[messageId]
val author = RevoltAPI.userCache[message?.author ?: ""]
val username = message?.masquerade?.name ?: author?.username ?: ""
Row(
modifier = modifier
.fillMaxWidth()
@ -38,22 +41,23 @@ fun InReplyTo(
if (message != null) {
UserAvatar(
username = author?.username ?: "",
username = username,
userId = author?.id ?: "",
avatar = author?.avatar,
rawUrl = message.masquerade?.avatar?.let { asJanuaryProxyUrl(it) },
size = 16.dp
)
Text(
text = if (author != null) {
if (withMention) {
"@${author.username}"
"@$username"
} else {
author.username
username
}
} else {
stringResource(id = R.string.unknown)
} ?: stringResource(id = R.string.unknown),
},
fontWeight = FontWeight.Bold,
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.9f),
@ -62,6 +66,15 @@ fun InReplyTo(
modifier = Modifier.padding(horizontal = 4.dp)
)
if (message.masquerade != null && author?.bot != null) {
InlineBadge(
badge = InlineBadge.Masquerade,
colour = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.5f),
modifier = Modifier.size(8.dp)
)
Spacer(modifier = Modifier.width(4.dp))
}
Text(
text = message.content ?: "",
fontSize = 12.sp,

View File

@ -0,0 +1,40 @@
package chat.revolt.components.chat
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import chat.revolt.R
enum class InlineBadge {
Bot,
Masquerade,
PlatformModeration,
Developer
}
@Composable
fun InlineBadge(
badge: InlineBadge,
modifier: Modifier = Modifier,
colour: Color = Color.Unspecified,
) {
when (badge) {
InlineBadge.Bot -> Icon(
painter = painterResource(id = R.drawable.ic_robot_24dp),
contentDescription = stringResource(id = R.string.badge_bot_alt),
tint = colour,
modifier = modifier
)
InlineBadge.Masquerade -> Icon(
painter = painterResource(id = R.drawable.ic_link_variant_24dp),
contentDescription = stringResource(id = R.string.badge_masquerade_alt),
tint = colour,
modifier = modifier
)
InlineBadge.PlatformModeration -> TODO()
InlineBadge.Developer -> TODO()
}
}

View File

@ -3,14 +3,9 @@ package chat.revolt.components.chat
import android.net.Uri
import android.widget.Toast
import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -26,7 +21,9 @@ import androidx.compose.ui.unit.sp
import chat.revolt.R
import chat.revolt.api.REVOLT_FILES
import chat.revolt.api.RevoltAPI
import chat.revolt.api.asJanuaryProxyUrl
import chat.revolt.api.internals.ULID
import chat.revolt.api.internals.WebCompat
import chat.revolt.api.schemas.AutumnResource
import chat.revolt.components.generic.RemoteImage
import chat.revolt.components.generic.UserAvatar
@ -50,12 +47,6 @@ fun formatLongAsTime(time: Long): String {
val format =
java.text.SimpleDateFormat("dd.MM.yyyy HH:mm:ss", java.util.Locale.getDefault())
// EQUIVALENT CODE WITH kotlinx.datetime:
// val date = Instant.fromEpochMilliseconds(time)
// val format = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")
return format.format(date)
}
@ -109,7 +100,8 @@ fun Message(
UserAvatar(
username = author.username ?: "",
userId = author.id!!,
avatar = author.avatar
avatar = author.avatar,
rawUrl = message.masquerade?.avatar?.let { asJanuaryProxyUrl(it) }
)
} else {
UserAvatarWidthPlaceholder()
@ -119,12 +111,25 @@ fun Message(
if (message.tail == false) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = author.username ?: "",
text = message.masquerade?.name ?: author.username ?: "",
fontWeight = FontWeight.Bold,
color = if (message.masquerade?.colour != null) {
WebCompat.parseColour(message.masquerade.colour)
} else LocalContentColor.current,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
if (message.masquerade != null && author.bot != null) {
Spacer(modifier = Modifier.width(5.dp))
InlineBadge(
badge = InlineBadge.Masquerade,
colour = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.5f),
modifier = Modifier.size(16.dp)
)
}
Spacer(modifier = Modifier.width(5.dp))
Text(

View File

@ -57,6 +57,7 @@ fun UserAvatar(
modifier: Modifier = Modifier,
presence: Presence? = null,
avatar: AutumnResource? = null,
rawUrl: String? = null,
size: Dp = 40.dp,
presenceSize: Dp = 16.dp,
) {
@ -67,7 +68,7 @@ fun UserAvatar(
) {
if (avatar != null) {
RemoteImage(
url = "$REVOLT_FILES/avatars/${avatar.id!!}/user.png",
url = rawUrl ?: "$REVOLT_FILES/avatars/${avatar.id!!}/user.png",
description = stringResource(id = R.string.avatar_alt, username),
contentScale = ContentScale.Crop,
modifier = Modifier

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M10.59,13.41C11,13.8 11,14.44 10.59,14.83C10.2,15.22 9.56,15.22 9.17,14.83C7.22,12.88 7.22,9.71 9.17,7.76V7.76L12.71,4.22C14.66,2.27 17.83,2.27 19.78,4.22C21.73,6.17 21.73,9.34 19.78,11.29L18.29,12.78C18.3,11.96 18.17,11.14 17.89,10.36L18.36,9.88C19.54,8.71 19.54,6.81 18.36,5.64C17.19,4.46 15.29,4.46 14.12,5.64L10.59,9.17C9.41,10.34 9.41,12.24 10.59,13.41M13.41,9.17C13.8,8.78 14.44,8.78 14.83,9.17C16.78,11.12 16.78,14.29 14.83,16.24V16.24L11.29,19.78C9.34,21.73 6.17,21.73 4.22,19.78C2.27,17.83 2.27,14.66 4.22,12.71L5.71,11.22C5.7,12.04 5.83,12.86 6.11,13.65L5.64,14.12C4.46,15.29 4.46,17.19 5.64,18.36C6.81,19.54 8.71,19.54 9.88,18.36L13.41,14.83C14.59,13.66 14.59,11.76 13.41,10.59C13,10.2 13,9.56 13.41,9.17Z"
android:fillColor="#ffffff" />
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M12,2A2,2 0 0,1 14,4C14,4.74 13.6,5.39 13,5.73V7H14A7,7 0 0,1 21,14H22A1,1 0 0,1 23,15V18A1,1 0 0,1 22,19H21V20A2,2 0 0,1 19,22H5A2,2 0 0,1 3,20V19H2A1,1 0 0,1 1,18V15A1,1 0 0,1 2,14H3A7,7 0 0,1 10,7H11V5.73C10.4,5.39 10,4.74 10,4A2,2 0 0,1 12,2M7.5,13A2.5,2.5 0 0,0 5,15.5A2.5,2.5 0 0,0 7.5,18A2.5,2.5 0 0,0 10,15.5A2.5,2.5 0 0,0 7.5,13M16.5,13A2.5,2.5 0 0,0 14,15.5A2.5,2.5 0 0,0 16.5,18A2.5,2.5 0 0,0 19,15.5A2.5,2.5 0 0,0 16.5,13Z"
android:fillColor="#ffffff" />
</vector>

View File

@ -70,7 +70,9 @@
<string name="send_alt">Send</string>
<string name="add_attachment_alt">Add attachment</string>
<string name="remove_attachment_alt">Remove attachment</string>
<string name="show_more_alt">Show more</string>
<string name="badge_bot_alt">Bot</string>
<string name="badge_masquerade_alt">From linked channel</string>
<string name="tutorial">Welcome to Revolt\'s in-progress Android experience!</string>
<string name="select_channel">Select a server and channel by swiping from the left.</string>