feat: link and bot embeds

This commit is contained in:
Infi 2023-03-22 02:02:34 +01:00
parent 40a9cdf344
commit 219d252912
8 changed files with 197 additions and 18 deletions

View File

@ -112,8 +112,8 @@ dependencies {
implementation 'androidx.compose.material:material'
implementation 'androidx.compose.material3:material3'
implementation "androidx.compose.ui:ui-tooling-preview"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.6.0'
implementation 'androidx.activity:activity-compose:1.6.1'
// Accompanist - Jetpack Compose Extensions
@ -144,7 +144,7 @@ dependencies {
// Glide - Image Loading
implementation "com.github.bumptech.glide:glide:$glide_version"
implementation "com.github.bumptech.glide:compose:1.0.0-alpha.1"
implementation "com.github.bumptech.glide:compose:1.0.0-alpha.4-SNAPSHOT"
// AboutLibraries - automated OSS library attribution
implementation "com.mikepenz:aboutlibraries-compose:$aboutlibraries_version"

View File

@ -10,11 +10,15 @@ object WebCompat {
@Composable
fun parseColour(colour: String): Color {
if (colour.startsWith("var(")) {
Log.d(
"WebCompat",
"Parsing colour $colour. ${colour.substringAfter("var(").substringBefore(")")}"
)
return when (colour.substringAfter("var(").substringBefore(")")) {
"accent" -> MaterialTheme.colorScheme.primary
"foreground" -> MaterialTheme.colorScheme.onBackground
"background" -> MaterialTheme.colorScheme.background
"error" -> MaterialTheme.colorScheme.error
"--accent" -> MaterialTheme.colorScheme.primary
"--foreground" -> MaterialTheme.colorScheme.onBackground
"--background" -> MaterialTheme.colorScheme.background
"--error" -> MaterialTheme.colorScheme.error
else -> LocalContentColor.current
}
} else {

View File

@ -24,7 +24,11 @@ suspend fun fetchSelf(): User {
val user = RevoltJson.decodeFromString(User.serializer(), response)
RevoltAPI.userCache[user.id!!] = user
if (user.id == null) {
throw Error("Self user ID is null")
}
RevoltAPI.userCache[user.id] = user
RevoltAPI.selfId = user.id
return user

View File

@ -0,0 +1,145 @@
package chat.revolt.components.chat
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import chat.revolt.api.asJanuaryProxyUrl
import chat.revolt.api.internals.WebCompat
import chat.revolt.api.schemas.Embed
import chat.revolt.components.generic.RemoteImage
import chat.revolt.components.generic.UIMarkdown
import chat.revolt.api.schemas.Embed as EmbedSchema
@Composable
fun RegularEmbed(
embed: EmbedSchema,
modifier: Modifier = Modifier,
onLinkClick: (String) -> Unit = {}
) {
Row(
modifier = modifier
.clip(MaterialTheme.shapes.medium)
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp))
.fillMaxWidth()
.height(IntrinsicSize.Min)
) {
// Stripe at the left side of the embed
Box(
modifier = Modifier
.width(4.dp)
.fillMaxHeight()
.background(
embed.colour?.let { WebCompat.parseColour(it) }
?: MaterialTheme.colorScheme.primary
)
)
Box(
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
) {
Column {
// Title row (icon + title)
Row(
modifier = Modifier
.then(
if (embed.originalURL != null)
Modifier
.clickable {
onLinkClick(embed.originalURL)
}
else Modifier
)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
embed.iconURL?.let {
if (it.endsWith(".svg")) return@let
RemoteImage(
url = asJanuaryProxyUrl(it),
width = 48,
height = 48,
contentScale = ContentScale.Crop,
description = null // decorative
)
Spacer(modifier = Modifier.width(8.dp))
}
embed.title?.let {
Text(
text = it,
fontWeight = FontWeight.Bold
)
}
}
// Description
embed.description?.let {
UIMarkdown(
text = it,
modifier = Modifier.padding(top = 8.dp)
)
}
// Image
embed.image?.let {
if (it.url == null || it.url.endsWith(".svg")) return@let
Spacer(modifier = Modifier.height(8.dp))
RemoteImage(
url = asJanuaryProxyUrl(it.url),
width = (it.width ?: 48).toInt(),
height = (it.height ?: 48).toInt(),
modifier = Modifier
.clip(MaterialTheme.shapes.medium)
.then(
if (embed.originalURL != null) Modifier.clickable {
onLinkClick(embed.originalURL)
} else Modifier
)
.aspectRatio(
(it.width?.toFloat() ?: 0f) / (it.height?.toFloat() ?: 0f)
),
contentScale = ContentScale.Crop,
description = null // decorative
)
}
}
}
}
}
@Composable
fun Embed(
embed: Embed,
modifier: Modifier = Modifier,
onLinkClick: (String) -> Unit
) {
Column {
when (embed.type) {
else -> RegularEmbed(embed = embed, modifier = modifier, onLinkClick = onLinkClick)
}
}
}

View File

@ -31,14 +31,16 @@ import chat.revolt.components.generic.UserAvatar
import chat.revolt.components.generic.UserAvatarWidthPlaceholder
import chat.revolt.api.schemas.Message as MessageSchema
fun viewAttachmentInBrowser(ctx: android.content.Context, attachment: AutumnResource) {
fun viewUrlInBrowser(ctx: android.content.Context, url: String) {
val customTab = CustomTabsIntent
.Builder()
.build()
customTab.launchUrl(
ctx,
Uri.parse("$REVOLT_FILES/attachments/${attachment.id}/${attachment.filename}")
)
customTab.launchUrl(ctx, Uri.parse(url))
}
fun viewAttachmentInBrowser(ctx: android.content.Context, attachment: AutumnResource) {
val url = REVOLT_FILES + attachment.id + "/" + attachment.filename
viewUrlInBrowser(ctx, url)
}
@ -159,10 +161,31 @@ fun Message(
message.attachments?.let {
message.attachments.forEach { attachment ->
Spacer(modifier = Modifier.height(5.dp))
Spacer(modifier = Modifier.height(2.dp))
MessageAttachment(attachment) {
viewAttachmentInBrowser(context, attachment)
}
Spacer(modifier = Modifier.height(2.dp))
}
}
message.embeds?.let {
message.embeds.forEach { embed ->
val embedIsEmpty =
embed.title == null && embed.description == null && embed.iconURL == null && embed.image == null
if (embedIsEmpty) {
// if we do not emit anything, compose will cause an internal error.
// FIXME if you are doing fixme's anyways then check if this is still an issue
Box {}
return@forEach
}
Spacer(modifier = Modifier.height(8.dp))
Embed(embed = embed, onLinkClick = {
viewUrlInBrowser(context, it)
})
Spacer(modifier = Modifier.height(8.dp))
}
}
}

View File

@ -4,6 +4,7 @@ import android.text.SpannableStringBuilder
import android.text.TextUtils
import android.util.Log
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
@ -42,8 +43,8 @@ import com.discord.simpleast.core.simple.SimpleRenderer
@Composable
fun UIMarkdown(
text: String,
fontSize: TextUnit,
modifier: Modifier = Modifier,
fontSize: TextUnit = LocalTextStyle.current.fontSize,
maxLines: Int = Int.MAX_VALUE,
) {
val context = LocalContext.current
@ -96,8 +97,6 @@ fun UIMarkdown(
setTextColor(foregroundColor.toArgb())
setMaxLines(maxLines)
setTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, fontSize.value)
setText(spannableStringBuilder.value)
}
},
modifier = modifier,

View File

@ -16,7 +16,7 @@ import com.bumptech.glide.integration.compose.GlideImage
@Composable
fun RemoteImage(
url: String,
description: String,
description: String?,
modifier: Modifier = Modifier,
contentScale: ContentScale = ContentScale.Crop,
width: Int = 0,

View File

@ -11,6 +11,10 @@ dependencyResolutionManagement {
google()
mavenCentral()
maven { url "https://jitpack.io" }
maven {
name 'snapshot'
url 'https://oss.sonatype.org/content/repositories/snapshots'
}
}
}
rootProject.name = "Revolt"