feat: special banner borders for team

Signed-off-by: Infi <wingit@geist.ga>
This commit is contained in:
Infi 2023-08-11 00:54:56 +02:00
parent 04237e3dfd
commit 96b0f1a69f
2 changed files with 123 additions and 1 deletions

View File

@ -1,10 +1,96 @@
package chat.revolt.api.internals package chat.revolt.api.internals
import android.content.Context
import android.graphics.RuntimeShader
import android.os.Build
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ShaderBrush
import org.intellij.lang.annotations.Language
import androidx.compose.ui.graphics.Brush as AndroidBrush
object SpecialUsers { object SpecialUsers {
val PLATFORM_MODERATION_USER = "01FC17E1WTM2BGE4F3ARN3FDAF" val PLATFORM_MODERATION_USER = "01FC17E1WTM2BGE4F3ARN3FDAF"
val TRUSTED_MODERATION_BOTS = listOf( val TRUSTED_MODERATION_BOTS = listOf(
"01GXBYCNQ52A9QYCQ99RBPXPAW", // AutoMod "01GXBYCNQ52A9QYCQ99RBPXPAW", // AutoMod
"01FCXRNNVW69AMSHBE61W1M5T3", // AutoMod Nightly "01FCXRNNVW69AMSHBE61W1M5T3", // AutoMod Nightly
) )
sealed class TeamMemberFlair {
data class Brush(val brush: AndroidBrush) : TeamMemberFlair()
data class AGSLShader(val shader: String, val fallback: AndroidBrush) :
TeamMemberFlair()
}
@Language("AGSL")
private val INSERT_SHADER = """
uniform float value;
half4 main(in float2 fragCoord) {
return half4(fragCoord[0] / 1000.0, fragCoord[1] / 1000.0, sin(value), 1.0);
}
""".trimIndent()
val TEAM_MEMBER_FLAIRS = mapOf(
"01F1WKM5TK2V6KCZWR6DGBJDTZ" to TeamMemberFlair.Brush(
AndroidBrush.linearGradient(
listOf(
Color(0xFFD62900),
Color(0xFFFF9B55),
Color(0xFFFFFFFF),
Color(0xFFD461A6),
Color(0xFFA50062),
),
start = Offset.Zero,
end = Offset.Infinite
)
), // jen
"01EX2NCWQ0CHS3QJF0FEQS1GR4" to TeamMemberFlair.AGSLShader(
INSERT_SHADER,
AndroidBrush.linearGradient(
listOf(
Color(0xFF68224F),
Color(0xFFC68235),
),
start = Offset.Zero,
end = Offset.Infinite
)
), // insert
"01EXAF3KX65608AJ4NG27YG1HM" to TeamMemberFlair.Brush(
AndroidBrush.solidColor(Color(0xFFFFC1F1))
), // lea
"01FEEFJCKY5C4DMMJYZ20ACWWC" to TeamMemberFlair.Brush(
AndroidBrush.linearGradient(
listOf(
Color(0xFF0BA39F),
Color(0xFFCD1414)
)
)
), // sophie
"01FD58YK5W7QRV5H3D64KTQYX3" to TeamMemberFlair.Brush(
AndroidBrush.verticalGradient(
listOf(
Color(0xFF980000),
Color(0xFF1000AF)
)
)
), // zomatree
)
fun teamFlairAsBrush(context: Context, id: String): AndroidBrush? {
return when (val flair = TEAM_MEMBER_FLAIRS[id]) {
is TeamMemberFlair.Brush -> flair.brush
is TeamMemberFlair.AGSLShader -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val shader = RuntimeShader(flair.shader)
shader.setFloatUniform("value", (0..1000).random().toFloat())
ShaderBrush(shader)
} else {
flair.fallback
}
null -> null
}
}
} }

View File

@ -1,6 +1,7 @@
package chat.revolt.components.screens.settings package chat.revolt.components.screens.settings
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@ -9,6 +10,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.material3.LocalContentColor import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@ -18,9 +20,11 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
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
@ -29,13 +33,17 @@ import androidx.compose.ui.unit.dp
import chat.revolt.R import chat.revolt.R
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.SpecialUsers
import chat.revolt.api.internals.ULID import chat.revolt.api.internals.ULID
import chat.revolt.api.internals.solidColor
import chat.revolt.api.routes.user.fetchUserProfile import chat.revolt.api.routes.user.fetchUserProfile
import chat.revolt.api.schemas.Profile import chat.revolt.api.schemas.Profile
import chat.revolt.api.schemas.User import chat.revolt.api.schemas.User
import chat.revolt.components.generic.RemoteImage import chat.revolt.components.generic.RemoteImage
import chat.revolt.components.generic.UserAvatar import chat.revolt.components.generic.UserAvatar
import chat.revolt.components.generic.presenceFromStatus import chat.revolt.components.generic.presenceFromStatus
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
@Composable @Composable
fun SelfUserOverview() { fun SelfUserOverview() {
@ -63,8 +71,36 @@ fun UserOverview(user: User) {
@Composable @Composable
fun RawUserOverview(user: User, profile: Profile? = null) { fun RawUserOverview(user: User, profile: Profile? = null) {
val context = LocalContext.current
var teamMemberFlair by remember { mutableStateOf<Brush?>(null) }
LaunchedEffect(user) {
runBlocking(Dispatchers.IO) {
user.id?.let {
teamMemberFlair = SpecialUsers.teamFlairAsBrush(
context,
it
)
}
}
}
Box( Box(
contentAlignment = Alignment.BottomStart, contentAlignment = Alignment.BottomStart,
modifier = Modifier
.padding(horizontal = 16.dp)
.clip(MaterialTheme.shapes.large)
.then(
if (user.id in SpecialUsers.TEAM_MEMBER_FLAIRS.keys) {
Modifier
.border(
width = 4.dp,
brush = teamMemberFlair
?: Brush.solidColor(Color.Transparent),
shape = MaterialTheme.shapes.large,
)
} else Modifier
)
) { ) {
profile?.background?.let { background -> profile?.background?.let { background ->
RemoteImage( RemoteImage(