From aa186719d9508413c6d0cce14033e271b7068ceb Mon Sep 17 00:00:00 2001 From: Infi Date: Sat, 10 Aug 2024 21:20:36 +0200 Subject: [PATCH] feat(labs): experiment with a settings DSL Signed-off-by: Infi --- .../revolt/screens/labs/LabsHomeScreen.kt | 9 ++ .../revolt/screens/labs/LabsRootScreen.kt | 4 + .../labs/ui/sandbox/SettingsDslSandbox.kt | 44 +++++++ .../chat/revolt/settings/dsl/SettingsPage.kt | 117 ++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 app/src/main/java/chat/revolt/screens/labs/ui/sandbox/SettingsDslSandbox.kt create mode 100644 app/src/main/java/chat/revolt/settings/dsl/SettingsPage.kt diff --git a/app/src/main/java/chat/revolt/screens/labs/LabsHomeScreen.kt b/app/src/main/java/chat/revolt/screens/labs/LabsHomeScreen.kt index b28787b6..0e7f4cb4 100644 --- a/app/src/main/java/chat/revolt/screens/labs/LabsHomeScreen.kt +++ b/app/src/main/java/chat/revolt/screens/labs/LabsHomeScreen.kt @@ -157,6 +157,15 @@ fun LabsHomeScreen(navController: NavController) { } ) HorizontalDivider() + ListItem( + headlineContent = { + Text("Settings DSL") + }, + modifier = Modifier.clickable { + navController.navigate("sandboxes/settingsdsl") + } + ) + HorizontalDivider() } } } diff --git a/app/src/main/java/chat/revolt/screens/labs/LabsRootScreen.kt b/app/src/main/java/chat/revolt/screens/labs/LabsRootScreen.kt index 49402468..bc7d90cd 100644 --- a/app/src/main/java/chat/revolt/screens/labs/LabsRootScreen.kt +++ b/app/src/main/java/chat/revolt/screens/labs/LabsRootScreen.kt @@ -14,6 +14,7 @@ import androidx.navigation.compose.rememberNavController import chat.revolt.api.settings.FeatureFlags import chat.revolt.screens.labs.ui.mockups.CallScreenMockup import chat.revolt.screens.labs.ui.sandbox.CryptographicAgeVerificationSandbox +import chat.revolt.screens.labs.ui.sandbox.SettingsDslSandbox annotation class LabsFeature @@ -67,6 +68,9 @@ fun LabsRootScreen(topNav: NavController) { composable("sandboxes/cryptoageverif") { CryptographicAgeVerificationSandbox(labsNav) } + composable("sandboxes/settingsdsl") { + SettingsDslSandbox(labsNav) + } } } } diff --git a/app/src/main/java/chat/revolt/screens/labs/ui/sandbox/SettingsDslSandbox.kt b/app/src/main/java/chat/revolt/screens/labs/ui/sandbox/SettingsDslSandbox.kt new file mode 100644 index 00000000..11e9bc4e --- /dev/null +++ b/app/src/main/java/chat/revolt/screens/labs/ui/sandbox/SettingsDslSandbox.kt @@ -0,0 +1,44 @@ +package chat.revolt.screens.labs.ui.sandbox + +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.style.TextOverflow +import androidx.navigation.NavController +import chat.revolt.settings.dsl.SettingsPage +import chat.revolt.settings.dsl.SubcategoryContentInsets + +enum class SettingsDslSandboxTab { + General, + Appearance, +} + +@Composable +fun SettingsDslSandbox(navController: NavController) { + SettingsPage( + navController = navController, + title = { + Text( + text = "Settings DSL Demo", + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + ) { + Subcategory( + title = { Text("General") }, + contentInsets = SubcategoryContentInsets + ) { + Text(text = "General settings") + } + + Subcategory( + title = { Text("Appearance") } + ) { + RadioOptions( + options = SettingsDslSandboxTab.entries, + selectedOption = SettingsDslSandboxTab.General, + onOptionSelected = { } + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/chat/revolt/settings/dsl/SettingsPage.kt b/app/src/main/java/chat/revolt/settings/dsl/SettingsPage.kt new file mode 100644 index 00000000..0eddb1b2 --- /dev/null +++ b/app/src/main/java/chat/revolt/settings/dsl/SettingsPage.kt @@ -0,0 +1,117 @@ +package chat.revolt.settings.dsl + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.LargeTopAppBar +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import chat.revolt.R +import chat.revolt.components.generic.ListHeader +import chat.revolt.components.generic.RadioItem +import kotlin.enums.EnumEntries + +val SubcategoryContentInsets = PaddingValues(horizontal = 16.dp) + +interface SettingsPageScope { + @Composable + fun Subcategory( + title: @Composable () -> Unit, + contentInsets: PaddingValues, + content: @Composable SettingsPageScope.() -> Unit + ) { + ListHeader { + title() + } + + Column( + Modifier + .padding(contentInsets) + ) { + content() + } + } + + @Composable + fun Subcategory( + title: @Composable () -> Unit, + content: @Composable SettingsPageScope.() -> Unit + ) = Subcategory( + title = title, + contentInsets = PaddingValues(0.dp), + content = content + ) + + @Composable + fun > RadioOptions( + options: EnumEntries, + selectedOption: X, + onOptionSelected: (X) -> Unit + ) { + Column(Modifier.selectableGroup()) { + for (option in options) { + RadioItem( + selected = option == selectedOption, + onClick = { onOptionSelected(option) }, + label = { Text(option.toString()) } + ) + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SettingsPage( + navController: NavController?, + title: @Composable () -> Unit, + content: @Composable SettingsPageScope.() -> Unit +) { + val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior() + + Scaffold( + modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), + topBar = { + LargeTopAppBar( + scrollBehavior = scrollBehavior, + title = title, + navigationIcon = { + navController?.let { + IconButton(onClick = { + navController.popBackStack() + }) { + Icon( + imageVector = Icons.AutoMirrored.Default.ArrowBack, + contentDescription = stringResource(id = R.string.back) + ) + } + } + }, + ) + }, + ) { pv -> + Column( + Modifier + .padding(pv) + .fillMaxSize() + ) { + content( + object : SettingsPageScope {} + ) + } + } +} \ No newline at end of file