feat(labs): new sandboxes
Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
parent
32398e8d99
commit
6918f7b9fc
|
|
@ -305,6 +305,9 @@ dependencies {
|
||||||
// Square Logcat
|
// Square Logcat
|
||||||
implementation("com.squareup.logcat:logcat:0.1")
|
implementation("com.squareup.logcat:logcat:0.1")
|
||||||
|
|
||||||
|
// Librevolt
|
||||||
|
implementation("librevolt:librevolt-jvm:0.1.0")
|
||||||
|
|
||||||
// Testing
|
// Testing
|
||||||
androidTestImplementation("androidx.test:runner:$androidXTestVersion")
|
androidTestImplementation("androidx.test:runner:$androidXTestVersion")
|
||||||
androidTestImplementation("androidx.test:rules:$androidXTestVersion")
|
androidTestImplementation("androidx.test:rules:$androidXTestVersion")
|
||||||
|
|
@ -315,7 +318,16 @@ aboutLibraries {
|
||||||
additionalLicenses += listOf("ofl")
|
additionalLicenses += listOf("ofl")
|
||||||
includePlatform = true
|
includePlatform = true
|
||||||
strictMode = StrictMode.FAIL
|
strictMode = StrictMode.FAIL
|
||||||
allowedLicenses += listOf("Apache-2.0", "OFL", "MIT", "ASDKL", "BSD-2-Clause", "cmark")
|
allowedLicenses += listOf(
|
||||||
|
"Apache-2.0",
|
||||||
|
"OFL",
|
||||||
|
"MIT",
|
||||||
|
"ASDKL",
|
||||||
|
"BSD-2-Clause",
|
||||||
|
"cmark",
|
||||||
|
"EPL-1.0",
|
||||||
|
"BSD-3-Clause"
|
||||||
|
)
|
||||||
configPath = "compliance"
|
configPath = "compliance"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
package chat.revolt.components.generic
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import androidx.compose.foundation.Canvas
|
||||||
|
import androidx.compose.foundation.gestures.detectTapGestures
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.input.pointer.pointerInput
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import logcat.logcat
|
||||||
|
|
||||||
|
@SuppressLint("UnusedBoxWithConstraintsScope")
|
||||||
|
@Composable
|
||||||
|
fun GradientStopEditor(
|
||||||
|
segments: Int,
|
||||||
|
stops: List<Pair<Float, Color>>,
|
||||||
|
onStopsChanged: (List<Pair<Float, Color>>) -> Unit,
|
||||||
|
_onClickSegment: (Int) -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
// Our gradient stop editor uses zero-width "segments" to represent points where the stops can be placed.
|
||||||
|
// There are two segments, one at the start and one at the end, that are not visible to the user.
|
||||||
|
// They only exist so that the user can place stops at the very beginning and end of the gradient without
|
||||||
|
// having to tap at the edge of the screen.
|
||||||
|
Canvas(
|
||||||
|
modifier
|
||||||
|
.padding(horizontal = 16.dp)
|
||||||
|
.pointerInput(segments) {
|
||||||
|
detectTapGestures { offset ->
|
||||||
|
val segment = (offset.x / size.width * segments).toInt()
|
||||||
|
logcat { "Tapped segment $segment" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
// Debug code for now
|
||||||
|
val debugStops = mutableListOf(Color.Transparent)
|
||||||
|
for (i in 1 until segments + 1) {
|
||||||
|
if (i % 2 == 0) {
|
||||||
|
debugStops.add(Color(0xff366fd1))
|
||||||
|
} else {
|
||||||
|
debugStops.add(Color(0xff36d1af))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debugStops.add(Color.Transparent)
|
||||||
|
|
||||||
|
drawRect(
|
||||||
|
brush = Brush.linearGradient(debugStops, Offset(0f, 0f), Offset(size.width, 0f)),
|
||||||
|
size = size,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,12 +11,14 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Home
|
import androidx.compose.material.icons.filled.Home
|
||||||
import androidx.compose.material.icons.filled.Menu
|
import androidx.compose.material.icons.filled.Menu
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.ListItem
|
import androidx.compose.material3.ListItem
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.NavigationBar
|
import androidx.compose.material3.NavigationBar
|
||||||
|
|
@ -30,9 +32,12 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
|
import chat.revolt.ui.theme.FragmentMono
|
||||||
|
|
||||||
enum class LabsHomeScreenTab {
|
enum class LabsHomeScreenTab {
|
||||||
Home,
|
Home,
|
||||||
|
|
@ -42,7 +47,7 @@ enum class LabsHomeScreenTab {
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun LabsHomeScreen(navController: NavController) {
|
fun LabsHomeScreen(navController: NavController, topNav: NavController) {
|
||||||
val currentTab = rememberSaveable { mutableStateOf(LabsHomeScreenTab.Home) }
|
val currentTab = rememberSaveable { mutableStateOf(LabsHomeScreenTab.Home) }
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
|
@ -51,6 +56,16 @@ fun LabsHomeScreen(navController: NavController) {
|
||||||
scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(),
|
scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(),
|
||||||
title = {
|
title = {
|
||||||
Text("Labs")
|
Text("Labs")
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
topNav.popBackStack()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Default.ArrowBack,
|
||||||
|
contentDescription = "Back"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
@ -175,6 +190,29 @@ fun LabsHomeScreen(navController: NavController) {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
HorizontalDivider()
|
HorizontalDivider()
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text("Gradient Editor")
|
||||||
|
},
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
navController.navigate("sandboxes/gradienteditor")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
HorizontalDivider()
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(buildAnnotatedString {
|
||||||
|
pushStyle(SpanStyle(fontFamily = FragmentMono))
|
||||||
|
append("librevolt")
|
||||||
|
pop()
|
||||||
|
append(" Sample")
|
||||||
|
})
|
||||||
|
},
|
||||||
|
modifier = Modifier.clickable {
|
||||||
|
navController.navigate("sandboxes/librevolt")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
HorizontalDivider()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ import androidx.navigation.compose.rememberNavController
|
||||||
import chat.revolt.api.settings.FeatureFlags
|
import chat.revolt.api.settings.FeatureFlags
|
||||||
import chat.revolt.screens.labs.ui.mockups.CallScreenMockup
|
import chat.revolt.screens.labs.ui.mockups.CallScreenMockup
|
||||||
import chat.revolt.screens.labs.ui.mockups.NewLoginExperienceMockup
|
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.JBMSandbox
|
||||||
import chat.revolt.screens.labs.ui.sandbox.SettingsDslSandbox
|
import chat.revolt.screens.labs.ui.sandbox.SettingsDslSandbox
|
||||||
|
|
||||||
|
|
@ -59,7 +61,7 @@ fun LabsRootScreen(topNav: NavController) {
|
||||||
startDestination = "home",
|
startDestination = "home",
|
||||||
) {
|
) {
|
||||||
composable("home") {
|
composable("home") {
|
||||||
LabsHomeScreen(labsNav)
|
LabsHomeScreen(labsNav, topNav)
|
||||||
}
|
}
|
||||||
|
|
||||||
composable("mockups/call") {
|
composable("mockups/call") {
|
||||||
|
|
@ -75,6 +77,12 @@ fun LabsRootScreen(topNav: NavController) {
|
||||||
composable("sandboxes/jbm") {
|
composable("sandboxes/jbm") {
|
||||||
JBMSandbox(labsNav)
|
JBMSandbox(labsNav)
|
||||||
}
|
}
|
||||||
|
composable("sandboxes/gradienteditor") {
|
||||||
|
GradientEditorSandbox(labsNav)
|
||||||
|
}
|
||||||
|
composable("sandboxes/librevolt") {
|
||||||
|
CoreLibSandbox(labsNav)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
package chat.revolt.screens.labs.ui.sandbox
|
||||||
|
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
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.text.SpanStyle
|
||||||
|
import androidx.compose.ui.text.buildAnnotatedString
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import chat.revolt.settings.dsl.SettingsPage
|
||||||
|
import chat.revolt.ui.theme.FragmentMono
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CoreLibSandbox(navController: NavController) {
|
||||||
|
var greeting by remember { mutableStateOf("<no greeting>") }
|
||||||
|
|
||||||
|
SettingsPage(
|
||||||
|
navController,
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = buildAnnotatedString {
|
||||||
|
pushStyle(SpanStyle(fontFamily = FragmentMono))
|
||||||
|
append("librevolt")
|
||||||
|
pop()
|
||||||
|
append(" Sample")
|
||||||
|
},
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Button(onClick = {
|
||||||
|
greeting = librevolt.greet()
|
||||||
|
}) {
|
||||||
|
Text("Greet")
|
||||||
|
}
|
||||||
|
Text(greeting)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package chat.revolt.screens.labs.ui.sandbox
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import chat.revolt.components.generic.GradientStopEditor
|
||||||
|
import chat.revolt.settings.dsl.SettingsPage
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun GradientEditorSandbox(navController: NavController) {
|
||||||
|
var segmentCount by remember { mutableIntStateOf(10) }
|
||||||
|
|
||||||
|
SettingsPage(
|
||||||
|
navController,
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = "Gradient Editor Sandbox",
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
if (segmentCount >= 2)
|
||||||
|
segmentCount--
|
||||||
|
else showSnackbar("Minimum of 2 segments required.")
|
||||||
|
},
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Text("-")
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
"$segmentCount segments",
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
TextButton(
|
||||||
|
onClick = { segmentCount++ },
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Text("+")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GradientStopEditor(
|
||||||
|
segments = segmentCount,
|
||||||
|
stops = emptyList(),
|
||||||
|
onStopsChanged = {},
|
||||||
|
_onClickSegment = { showSnackbar("Clicked segment $it") },
|
||||||
|
modifier = Modifier.height(24.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -15,9 +15,13 @@ import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.LargeTopAppBar
|
import androidx.compose.material3.LargeTopAppBar
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
@ -26,11 +30,14 @@ import androidx.navigation.NavController
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.components.generic.ListHeader
|
import chat.revolt.components.generic.ListHeader
|
||||||
import chat.revolt.components.generic.RadioItem
|
import chat.revolt.components.generic.RadioItem
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.enums.EnumEntries
|
import kotlin.enums.EnumEntries
|
||||||
|
|
||||||
val SubcategoryContentInsets = PaddingValues(horizontal = 16.dp)
|
val SubcategoryContentInsets = PaddingValues(horizontal = 16.dp)
|
||||||
|
|
||||||
interface SettingsPageScope {
|
interface SettingsPageScope {
|
||||||
|
fun showSnackbar(message: String)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun Subcategory(
|
fun Subcategory(
|
||||||
title: @Composable () -> Unit,
|
title: @Composable () -> Unit,
|
||||||
|
|
@ -84,7 +91,9 @@ fun SettingsPage(
|
||||||
title: @Composable () -> Unit,
|
title: @Composable () -> Unit,
|
||||||
content: @Composable SettingsPageScope.() -> Unit
|
content: @Composable SettingsPageScope.() -> Unit
|
||||||
) {
|
) {
|
||||||
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
|
|
@ -106,6 +115,9 @@ fun SettingsPage(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
snackbarHost = {
|
||||||
|
SnackbarHost(hostState = snackbarHostState)
|
||||||
|
},
|
||||||
) { pv ->
|
) { pv ->
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
|
|
@ -115,7 +127,13 @@ fun SettingsPage(
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
) {
|
) {
|
||||||
content(
|
content(
|
||||||
object : SettingsPageScope {}
|
object : SettingsPageScope {
|
||||||
|
override fun showSnackbar(message: String) {
|
||||||
|
scope.launch {
|
||||||
|
snackbarHostState.showSnackbar(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,10 @@ dependencyResolutionManagement {
|
||||||
name = "compose-dev"
|
name = "compose-dev"
|
||||||
url = uri("https://maven.pkg.jetbrains.space/public/p/compose/dev")
|
url = uri("https://maven.pkg.jetbrains.space/public/p/compose/dev")
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
name = "revolt"
|
||||||
|
url = uri("https://git.revolt.chat/api/packages/librevolt/maven")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rootProject.name = "Revolt"
|
rootProject.name = "Revolt"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue