feat(labs): mystery card sandbox

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2025-08-02 20:50:30 +02:00
parent d71650225b
commit 79dca0074d
4 changed files with 213 additions and 2 deletions

View File

@ -10,8 +10,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
@ -203,6 +201,15 @@ fun LabsHomeScreen(navController: NavController, topNav: NavController) {
}
)
HorizontalDivider()
ListItem(
headlineContent = {
Text("New Card")
},
modifier = Modifier.clickable {
navController.navigate("sandboxes/newcard")
}
)
HorizontalDivider()
}
}
}

View File

@ -16,6 +16,7 @@ import chat.revolt.screens.labs.ui.mockups.NewLoginExperienceMockup
import chat.revolt.screens.labs.ui.sandbox.CoreLibSandbox
import chat.revolt.screens.labs.ui.sandbox.GradientEditorSandbox
import chat.revolt.screens.labs.ui.sandbox.JBMSandbox
import chat.revolt.screens.labs.ui.sandbox.NewCardSandboxScreen
import chat.revolt.screens.labs.ui.sandbox.SettingsDslSandbox
annotation class LabsFeature
@ -79,6 +80,10 @@ fun LabsRootScreen(topNav: NavController) {
composable("sandboxes/librevolt") {
CoreLibSandbox(labsNav)
}
composable("sandboxes/newcard") {
NewCardSandboxScreen(labsNav)
}
}
}
}

View File

@ -0,0 +1,164 @@
package chat.revolt.screens.labs.ui.sandbox
import android.widget.Toast
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.TextAutoSize
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialShapes
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.material3.toShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.constraintlayout.compose.ConstraintLayout
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.api.RevoltAPI
import chat.revolt.composables.generic.UserAvatar
import chat.revolt.settings.dsl.SettingsPage
import chat.revolt.ui.theme.FragmentMono
import java.text.DateFormat
import java.util.Date
import java.util.Locale
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun NewCardSandboxScreen(navController: NavController) {
var uidInput by remember { mutableStateOf(RevoltAPI.selfId ?: "") }
var activeUid by remember { mutableStateOf(RevoltAPI.selfId) }
val activeUser = remember(activeUid) {
RevoltAPI.userCache[activeUid]!!
}
val context = LocalContext.current
val date = remember {
DateFormat
.getDateInstance(
DateFormat.MEDIUM,
Locale.getDefault()
)
.format(Date())
}
SettingsPage(
navController,
title = {
Text(
text = "New Card",
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
}
) {
TextField(
value = uidInput,
onValueChange = { uidInput = it },
label = { Text("User ID") },
placeholder = { Text("Enter user ID") },
keyboardActions = KeyboardActions(
onDone = {
if (uidInput.isNotBlank() && RevoltAPI.userCache.containsKey(uidInput)) {
activeUid = uidInput
uidInput = ""
} else if (!RevoltAPI.userCache.containsKey(uidInput)) {
Toast.makeText(
context,
"User id not found in cache",
Toast.LENGTH_SHORT
).show()
}
}
),
singleLine = true,
maxLines = 1,
modifier = Modifier.fillMaxWidth()
)
ConstraintLayout(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(16f / 9f)
.clip(RoundedCornerShape(10))
.background(Color.Red)
.padding(16.dp)
) {
val (logoAsset, cardIssuedLabel, cardIssued, tag, avatar) = createRefs()
Image(
painter = painterResource(R.drawable.tmp_card_asset_tl),
contentDescription = "XY Uppercase Text",
modifier = Modifier
.constrainAs(logoAsset) {
top.linkTo(parent.top)
start.linkTo(parent.start)
}
.fillMaxWidth(1f / 3f)
)
Text(
text = "Card Issued",
modifier = Modifier.constrainAs(cardIssuedLabel) {
top.linkTo(parent.top)
end.linkTo(parent.end)
},
fontSize = 16.sp,
fontWeight = FontWeight.ExtraBold,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Text(
text = date,
modifier = Modifier.constrainAs(cardIssued) {
top.linkTo(cardIssuedLabel.bottom)
end.linkTo(parent.end)
},
fontFamily = FragmentMono,
fontSize = 20.sp,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
Text(
text = "${activeUser.username}#${activeUser.discriminator}",
modifier = Modifier
.constrainAs(tag) {
bottom.linkTo(parent.bottom)
start.linkTo(parent.start)
}
.fillMaxWidth(5f / 6f),
fontWeight = FontWeight.ExtraBold,
autoSize = TextAutoSize.StepBased(),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
UserAvatar(
username = activeUser.username ?: "",
userId = activeUser.id ?: "",
avatar = activeUser.avatar,
shape = MaterialShapes.Circle.toShape(),
size = 84.dp,
modifier = Modifier
.constrainAs(avatar) {
bottom.linkTo(tag.top, margin = 8.dp)
start.linkTo(tag.start)
}
)
}
}
}

View File

@ -0,0 +1,35 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24.404684dp" android:viewportHeight="52" android:viewportWidth="427" android:width="200.4dp">
<path android:fillAlpha="1" android:fillColor="#ffffff" android:pathData="M426.74,-0L426.74,51.66L0,51.66L0,-0L426.74,-0ZM425.75,0.99L1,0.99L1,50.65L425.75,50.65L425.75,0.99Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M76.69,50.86C74.5,50.86 72.57,50.4 70.92,49.56C69.3,48.71 68.03,47.52 67.15,46.02C66.22,44.51 65.76,42.82 65.76,40.9L65.76,22.39L69.15,22.39L69.15,40.63C69.15,42.01 69.46,43.21 70.07,44.28C70.65,45.32 71.53,46.17 72.65,46.78C73.77,47.4 75.11,47.71 76.69,47.71C78.23,47.71 79.58,47.4 80.69,46.78C81.81,46.17 82.69,45.32 83.27,44.28C83.89,43.21 84.2,42.01 84.2,40.63L84.2,22.39L87.58,22.39L87.58,40.9C87.58,42.82 87.12,44.51 86.24,46.02C85.31,47.52 84.04,48.71 82.43,49.56C80.81,50.4 78.88,50.86 76.69,50.86Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M92.97,50.4L92.97,22.39L103.02,22.39C105.94,22.39 108.25,23.16 109.95,24.69C111.68,26.2 112.53,28.27 112.53,30.89C112.53,32.62 112.14,34.16 111.33,35.43C110.52,36.7 109.41,37.66 107.98,38.36C106.52,39.05 104.83,39.4 102.87,39.4L96.36,39.4L96.36,50.4L92.97,50.4ZM96.36,36.39L102.9,36.39C104.87,36.39 106.37,35.89 107.48,34.93C108.64,33.93 109.18,32.58 109.18,30.89C109.18,29.2 108.64,27.85 107.48,26.89C106.37,25.89 104.87,25.43 102.9,25.43L96.36,25.43L96.36,36.39Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M116.52,50.4L116.52,22.39L126.56,22.39C129.49,22.39 131.8,23.16 133.49,24.69C135.22,26.2 136.07,28.27 136.07,30.89C136.07,32.62 135.69,34.16 134.88,35.43C134.07,36.7 132.95,37.66 131.53,38.36C130.07,39.05 128.37,39.4 126.41,39.4L119.91,39.4L119.91,50.4L116.52,50.4ZM119.91,36.39L126.45,36.39C128.41,36.39 129.91,35.89 131.03,34.93C132.18,33.93 132.72,32.58 132.72,30.89C132.72,29.2 132.18,27.85 131.03,26.89C129.91,25.89 128.41,25.43 126.45,25.43L119.91,25.43L119.91,36.39Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M140.07,50.4L140.07,22.39L158.27,22.39L158.27,25.43L143.45,25.43L143.45,34.55L157.19,34.55L157.19,37.59L143.45,37.59L143.45,47.4L158.27,47.4L158.27,50.4L140.07,50.4Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M162.37,50.4L162.37,22.39L172.76,22.39C175.69,22.39 178,23.16 179.73,24.69C181.42,26.2 182.27,28.27 182.27,30.89C182.27,32.89 181.73,34.59 180.69,35.97C179.61,37.32 178.15,38.32 176.34,38.86L182.62,50.4L178.69,50.4L172.76,39.4L165.76,39.4L165.76,50.4L162.37,50.4ZM165.76,36.39L172.69,36.39C174.65,36.39 176.15,35.89 177.27,34.93C178.38,33.93 178.92,32.58 178.92,30.89C178.92,29.2 178.38,27.85 177.27,26.89C176.15,25.89 174.61,25.43 172.65,25.43L165.76,25.43L165.76,36.39Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M198.56,50.86C195.98,50.86 193.75,50.25 191.79,49.02C189.86,47.79 188.32,46.05 187.25,43.9C186.17,41.7 185.63,39.24 185.63,36.43C185.63,33.58 186.17,31.08 187.25,28.93C188.32,26.73 189.82,25.04 191.79,23.81C193.71,22.58 195.98,21.96 198.56,21.96C200.52,21.96 202.33,22.35 203.95,23.12C205.57,23.89 206.91,24.96 207.99,26.39C209.07,27.81 209.76,29.51 210.11,31.47L206.64,31.47C206.22,29.43 205.26,27.85 203.79,26.73C202.37,25.66 200.6,25.12 198.56,25.12C196.6,25.12 194.9,25.58 193.48,26.54C192.06,27.5 190.94,28.85 190.17,30.54C189.4,32.24 189.02,34.2 189.02,36.43C189.02,38.63 189.4,40.59 190.17,42.28C190.94,43.98 192.06,45.28 193.48,46.25C194.9,47.21 196.6,47.71 198.56,47.71C200.6,47.71 202.33,47.17 203.79,46.05C205.22,44.98 206.18,43.4 206.68,41.4L210.11,41.4C209.76,43.32 209.07,45.01 207.99,46.4C206.91,47.82 205.57,48.94 203.95,49.71C202.33,50.48 200.52,50.86 198.56,50.86Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M211.55,50.4L221.87,22.39L225.71,22.39L235.95,50.4L232.33,50.4L229.6,42.55L217.9,42.55L215.09,50.4L211.55,50.4ZM218.98,39.55L228.56,39.55L226.45,33.55C226.1,32.55 225.71,31.43 225.29,30.2C224.91,29 224.41,27.43 223.79,25.58C223.21,27.43 222.67,29 222.29,30.2C221.87,31.43 221.48,32.55 221.13,33.55L218.98,39.55Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M248.36,50.86C246.2,50.86 244.31,50.48 242.74,49.71C241.16,48.94 239.93,47.82 239.08,46.4C238.19,45.01 237.77,43.32 237.77,41.4L241.24,41.4C241.24,43.4 241.85,44.94 243.12,46.09C244.35,47.21 246.08,47.79 248.36,47.79C250.39,47.79 252.01,47.32 253.24,46.44C254.47,45.55 255.09,44.36 255.09,42.86C255.09,41.67 254.67,40.74 253.86,40.01C253.01,39.28 251.59,38.66 249.55,38.16L246.43,37.39C243.54,36.7 241.5,35.74 240.23,34.59C238.96,33.39 238.35,31.85 238.35,29.97C238.35,28.35 238.73,26.93 239.54,25.73C240.31,24.54 241.47,23.62 242.89,22.96C244.35,22.27 246.05,21.96 248.01,21.96C250.93,21.96 253.24,22.73 254.97,24.31C256.71,25.85 257.63,27.97 257.71,30.66L254.36,30.66C254.24,28.93 253.63,27.54 252.47,26.54C251.32,25.54 249.78,25.04 247.89,25.04C246.08,25.04 244.58,25.5 243.43,26.39C242.27,27.27 241.7,28.39 241.7,29.77C241.7,30.89 242.12,31.78 242.97,32.43C243.81,33.12 245.28,33.74 247.32,34.24L250.47,35.05C253.2,35.7 255.24,36.66 256.51,37.89C257.82,39.16 258.48,40.74 258.48,42.71C258.48,44.32 258.05,45.75 257.21,46.98C256.36,48.21 255.17,49.13 253.67,49.83C252.13,50.52 250.36,50.86 248.36,50.86Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M262.72,50.4L262.72,22.39L280.92,22.39L280.92,25.43L266.11,25.43L266.11,34.55L279.84,34.55L279.84,37.59L266.11,37.59L266.11,47.4L280.92,47.4L280.92,50.4L262.72,50.4Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M292.8,25.43L292.8,22.39L314.43,22.39L314.43,25.43L305.34,25.43L305.34,50.4L301.96,50.4L301.96,25.43L292.8,25.43Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M318.13,50.4L318.13,22.39L336.34,22.39L336.34,25.43L321.52,25.43L321.52,34.55L335.26,34.55L335.26,37.59L321.52,37.59L321.52,47.4L336.34,47.4L336.34,50.4L318.13,50.4Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M338.13,50.4L348.18,36.05L338.75,22.39L342.63,22.39L346.79,28.47C347.91,30.12 349.02,31.78 350.14,33.47C350.68,32.62 351.26,31.81 351.79,30.97C352.37,30.12 352.95,29.27 353.53,28.47L357.72,22.39L361.53,22.39L352.1,35.97L362.03,50.4L358.14,50.4L353.18,43.17C352.64,42.44 352.14,41.67 351.64,40.9C351.1,40.17 350.6,39.4 350.1,38.63C349.6,39.4 349.06,40.17 348.56,40.9C348.02,41.67 347.52,42.44 346.98,43.17L341.98,50.4L338.13,50.4Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M363.44,25.43L363.44,22.39L385.07,22.39L385.07,25.43L375.98,25.43L375.98,50.4L372.6,50.4L372.6,25.43L363.44,25.43Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M0.3,51.65L10.38,37.34L1.42,23.63L10.23,23.63L12.46,27.29C12.85,27.91 13.23,28.52 13.58,29.14C13.96,29.75 14.31,30.37 14.66,30.99C15,30.37 15.39,29.75 15.73,29.14C16.12,28.52 16.5,27.91 16.89,27.29L19.16,23.63L27.74,23.63L18.93,37.14L28.82,51.65L19.74,51.65L16.69,46.84C16.35,46.26 15.96,45.69 15.62,45.11C15.27,44.53 14.92,43.95 14.54,43.42C14.19,43.95 13.85,44.53 13.46,45.11C13.12,45.69 12.73,46.26 12.35,46.84L9.11,51.65L0.3,51.65Z"/>
<path android:fillColor="#ffffff" android:fillType="nonZero" android:pathData="M39.25,27.99L39.25,18.45L28.82,-0.02L37.75,-0.02L41.79,7.87C42.03,8.29 42.22,8.71 42.45,9.18C42.68,9.64 42.87,10.06 43.06,10.52C43.26,10.06 43.45,9.64 43.64,9.18C43.83,8.71 44.07,8.29 44.26,7.87L48.07,-0.02L56.92,-0.02L46.8,18.45L46.8,27.99L39.25,27.99Z"/>
</vector>