Android: full-screen menu landing page + much denser settings

- gear now opens a full-screen Menu screen (Profile / Appearance / Accounts /
  Groups / Sync / Switch server / Logout), replacing the bottom-sheet menu that
  sat partly under the system nav buttons. Each entry opens its own full-screen
  page and returns to the menu on close.
- settings 'Darstellung' is the appearance table only again (no long scroll to
  reach navigation)
- much more compact settings: dropdowns use a small outlined chip instead of a
  full-height OutlinedTextField, smaller sync icons, bodyMedium row labels

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Guido Schmit
2026-07-15 20:31:21 +02:00
parent e72ffab4f4
commit 101370719b
4 changed files with 168 additions and 200 deletions

View File

@@ -73,13 +73,14 @@ import com.scarriffle.calendarr.ui.event.EventDetailScreen
import com.scarriffle.calendarr.ui.event.EventEditorSheet import com.scarriffle.calendarr.ui.event.EventEditorSheet
import com.scarriffle.calendarr.ui.groups.GroupIcon import com.scarriffle.calendarr.ui.groups.GroupIcon
import com.scarriffle.calendarr.ui.groups.GroupsScreen import com.scarriffle.calendarr.ui.groups.GroupsScreen
import com.scarriffle.calendarr.ui.menu.MenuScreen
import com.scarriffle.calendarr.ui.profile.ProfileScreen import com.scarriffle.calendarr.ui.profile.ProfileScreen
import com.scarriffle.calendarr.ui.settings.SettingsScreen import com.scarriffle.calendarr.ui.settings.SettingsScreen
import com.scarriffle.calendarr.ui.tr import com.scarriffle.calendarr.ui.tr
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.LocalDate import java.time.LocalDate
private enum class Overlay { NONE, PROFILE, SETTINGS, ACCOUNTS, GROUPS } private enum class Overlay { NONE, MENU, PROFILE, SETTINGS, ACCOUNTS, GROUPS }
data class EditorRequest(val existing: CalEvent?, val date: LocalDate, val prefill: CalEvent? = null) data class EditorRequest(val existing: CalEvent?, val date: LocalDate, val prefill: CalEvent? = null)
@@ -198,7 +199,7 @@ fun CalendarScreen(
CalendarDrawerContent( CalendarDrawerContent(
state = state, vm = vm, username = username, serverUrl = serverUrl, state = state, vm = vm, username = username, serverUrl = serverUrl,
calendars = drawerCalendars, calendars = drawerCalendars,
onOpenMenu = { drawerScope.launch { drawerState.close() }; overlay = Overlay.SETTINGS }, onOpenMenu = { drawerScope.launch { drawerState.close() }; overlay = Overlay.MENU },
onSync = { drawerScope.launch { drawerState.close() }; vm.syncWithServer() }, onSync = { drawerScope.launch { drawerState.close() }; vm.syncWithServer() },
onClose = { drawerScope.launch { drawerState.close() } }, onClose = { drawerScope.launch { drawerState.close() } },
) )
@@ -363,23 +364,30 @@ fun CalendarScreen(
} }
when (overlay) { when (overlay) {
Overlay.PROFILE -> ProfileScreen(onClose = { overlay = Overlay.NONE }) Overlay.MENU -> MenuScreen(
Overlay.SETTINGS -> SettingsScreen( username = username,
onClose = { overlay = Overlay.NONE; vm.refreshMonthViewMode() }, serverUrl = serverUrl,
onSettingsChanged = onSettingsChanged, onClose = { overlay = Overlay.NONE },
onSettingsSynced = onSettingsSynced, onProfile = { overlay = Overlay.PROFILE },
onOpenProfile = { overlay = Overlay.PROFILE }, onAppearance = { overlay = Overlay.SETTINGS },
onOpenAccounts = { overlay = Overlay.ACCOUNTS }, onAccounts = { overlay = Overlay.ACCOUNTS },
onOpenGroups = { overlay = Overlay.GROUPS }, onGroups = { overlay = Overlay.GROUPS },
onSync = { overlay = Overlay.NONE; vm.syncWithServer() },
onSwitchServer = onSwitchServer, onSwitchServer = onSwitchServer,
onLogout = onLogout, onLogout = onLogout,
) )
Overlay.PROFILE -> ProfileScreen(onClose = { overlay = Overlay.MENU })
Overlay.SETTINGS -> SettingsScreen(
onClose = { overlay = Overlay.MENU; vm.refreshMonthViewMode() },
onSettingsChanged = onSettingsChanged,
onSettingsSynced = onSettingsSynced,
)
Overlay.ACCOUNTS -> AccountsScreen( Overlay.ACCOUNTS -> AccountsScreen(
onClose = { overlay = Overlay.NONE }, onClose = { overlay = Overlay.MENU },
onChanged = { vm.loadWritableCalendars(); vm.syncWithServer() }, onChanged = { vm.loadWritableCalendars(); vm.syncWithServer() },
) )
Overlay.GROUPS -> GroupsScreen( Overlay.GROUPS -> GroupsScreen(
onClose = { overlay = Overlay.NONE }, onClose = { overlay = Overlay.MENU },
onChanged = { vm.loadGroups(); vm.loadWritableCalendars() }, onChanged = { vm.loadGroups(); vm.loadWritableCalendars() },
onOpenGroupView = { g -> overlay = Overlay.NONE; vm.switchGroup(g) }, onOpenGroupView = { g -> overlay = Overlay.NONE; vm.switchGroup(g) },
) )

View File

@@ -0,0 +1,124 @@
package com.scarriffle.calendarr.ui.menu
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.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CalendarMonth
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Dns
import androidx.compose.material.icons.filled.Logout
import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.filled.People
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.Sync
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
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.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.scarriffle.calendarr.ui.tr
/** Full-screen menu / landing page reached from the drawer's gear: the hub for
* Profile / Appearance / Accounts / Groups / Sync / Server / Logout. Each entry
* opens its own full-screen page. */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MenuScreen(
username: String,
serverUrl: String,
onClose: () -> Unit,
onProfile: () -> Unit,
onAppearance: () -> Unit,
onAccounts: () -> Unit,
onGroups: () -> Unit,
onSync: () -> Unit,
onSwitchServer: () -> Unit,
onLogout: () -> Unit,
) {
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
Scaffold(
topBar = {
TopAppBar(
title = { Text(tr("nav.menu")) },
navigationIcon = {
IconButton(onClick = onClose) { Icon(Icons.Filled.Close, contentDescription = tr("common.close")) }
},
)
},
contentWindowInsets = WindowInsets(0),
) { padding ->
Column(
Modifier.fillMaxSize().padding(padding).verticalScroll(rememberScrollState()).navigationBarsPadding(),
) {
Row(
Modifier.fillMaxWidth().padding(horizontal = 20.dp, vertical = 16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Box(
Modifier.size(44.dp).clip(CircleShape).background(MaterialTheme.colorScheme.primary),
contentAlignment = Alignment.Center,
) {
Text(username.firstOrNull()?.uppercase() ?: "?",
style = MaterialTheme.typography.titleMedium,
color = MaterialTheme.colorScheme.onPrimary, fontWeight = FontWeight.Bold)
}
Spacer(Modifier.width(14.dp))
Column {
Text(username, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold, maxLines = 1)
Text(serverUrl.removePrefix("https://").removePrefix("http://"),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 1)
}
}
Divider()
MenuRow(Icons.Filled.Person, tr("menu.profile"), onProfile)
MenuRow(Icons.Filled.Palette, tr("menu.appearance"), onAppearance)
MenuRow(Icons.Filled.CalendarMonth, tr("menu.accounts"), onAccounts)
MenuRow(Icons.Filled.People, tr("menu.groups"), onGroups)
Divider(Modifier.padding(vertical = 4.dp))
MenuRow(Icons.Filled.Sync, tr("menu.sync"), onSync)
MenuRow(Icons.Filled.Dns, tr("server.switch"), onSwitchServer)
MenuRow(Icons.Filled.Logout, tr("menu.logout"), onLogout, destructive = true)
}
}
}
}
@Composable
private fun MenuRow(icon: ImageVector, label: String, onClick: () -> Unit, destructive: Boolean = false) {
val tint = if (destructive) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurfaceVariant
Row(
Modifier.fillMaxWidth().clickable(onClick = onClick).padding(horizontal = 20.dp, vertical = 14.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(icon, contentDescription = null, tint = tint)
Spacer(Modifier.width(18.dp))
Text(label, style = MaterialTheme.typography.bodyLarge,
color = if (destructive) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurface)
}
}

View File

@@ -1,146 +0,0 @@
package com.scarriffle.calendarr.ui.menu
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.CalendarMonth
import androidx.compose.material.icons.filled.Check
import androidx.compose.material.icons.filled.Dns
import androidx.compose.material.icons.filled.Logout
import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.filled.People
import androidx.compose.material.icons.filled.Person
import androidx.compose.material.icons.filled.Sync
import androidx.compose.material3.Divider
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.scarriffle.calendarr.domain.model.Group
import com.scarriffle.calendarr.ui.groups.GroupIcon
import com.scarriffle.calendarr.ui.tr
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MenuSheet(
isAdmin: Boolean,
groups: List<Group>,
activeGroup: Group?,
onSwitchGroup: (Group?) -> Unit,
onDismiss: () -> Unit,
onProfile: () -> Unit,
onAppearance: () -> Unit,
onAccounts: () -> Unit,
onGroups: () -> Unit,
onSync: () -> Unit,
onLogout: () -> Unit,
onSwitchServer: () -> Unit,
) {
ModalBottomSheet(onDismissRequest = onDismiss) {
// Inset for the system navigation bar so the last rows aren't hidden
// behind the Android nav buttons; scroll as a fallback on short screens.
Column(
Modifier.fillMaxWidth()
.verticalScroll(rememberScrollState())
.navigationBarsPadding()
.padding(bottom = 12.dp),
) {
Text(
"Calendarr",
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.SemiBold,
modifier = Modifier.padding(horizontal = 20.dp, vertical = 8.dp),
)
MenuRow(Icons.Filled.AccountCircle, tr("menu.profile"), onProfile)
MenuRow(Icons.Filled.Palette, tr("menu.appearance"), onAppearance)
MenuRow(Icons.Filled.CalendarMonth, tr("menu.accounts"), onAccounts)
// Group view switch (personal + each group) — moved here from the
// top bar to free up space. Group *management* stays below.
if (groups.isNotEmpty()) {
Divider(Modifier.padding(vertical = 4.dp))
MenuSectionLabel(tr("groups.view"))
GroupSwitchRow(
label = tr("group.switch.personal"),
checked = activeGroup == null,
leading = { Icon(Icons.Filled.Person, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant) },
onClick = { onSwitchGroup(null) },
)
groups.forEach { g ->
GroupSwitchRow(
label = g.name,
checked = activeGroup?.id == g.id,
leading = { GroupIcon(g.icon) },
onClick = { onSwitchGroup(g) },
)
}
}
Divider(Modifier.padding(vertical = 4.dp))
MenuRow(Icons.Filled.People, tr("menu.groups"), onGroups)
Divider(Modifier.padding(vertical = 4.dp))
MenuRow(Icons.Filled.Sync, tr("menu.sync"), onSync)
Divider(Modifier.padding(vertical = 4.dp))
MenuRow(Icons.Filled.Logout, tr("menu.logout"), onLogout)
MenuRow(Icons.Filled.Dns, tr("server.switch"), onSwitchServer)
}
}
}
@Composable
private fun MenuRow(icon: ImageVector, label: String, onClick: () -> Unit) {
Row(
Modifier.fillMaxWidth().clickable(onClick = onClick).padding(horizontal = 20.dp, vertical = 14.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(icon, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant)
Spacer(Modifier.width(18.dp))
Text(label, style = MaterialTheme.typography.bodyLarge)
}
}
@Composable
private fun MenuSectionLabel(text: String) {
Text(
text,
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(horizontal = 20.dp, vertical = 4.dp),
)
}
/** A group-view choice (personal or a specific group) with a trailing check. */
@Composable
private fun GroupSwitchRow(
label: String,
checked: Boolean,
leading: @Composable () -> Unit,
onClick: () -> Unit,
) {
Row(
Modifier.fillMaxWidth().clickable(onClick = onClick).padding(horizontal = 20.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
leading()
Spacer(Modifier.width(18.dp))
Text(label, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.weight(1f))
if (checked) {
Icon(Icons.Filled.Check, contentDescription = null, tint = MaterialTheme.colorScheme.primary)
}
}
}

View File

@@ -22,6 +22,9 @@ import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Refresh import androidx.compose.material.icons.filled.Refresh
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Divider import androidx.compose.material3.Divider
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.filled.ArrowDropDown
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuBox
@@ -68,11 +71,6 @@ fun SettingsScreen(
onClose: () -> Unit, onClose: () -> Unit,
onSettingsChanged: (AppSettings) -> Unit, onSettingsChanged: (AppSettings) -> Unit,
onSettingsSynced: () -> Unit, onSettingsSynced: () -> Unit,
onOpenProfile: () -> Unit = {},
onOpenAccounts: () -> Unit = {},
onOpenGroups: () -> Unit = {},
onSwitchServer: () -> Unit = {},
onLogout: () -> Unit = {},
vm: SettingsViewModel = hiltViewModel(), vm: SettingsViewModel = hiltViewModel(),
) { ) {
val initialSettings = LocalAppSettings.current val initialSettings = LocalAppSettings.current
@@ -214,14 +212,6 @@ fun SettingsScreen(
Switch(checked = hideMenu, onCheckedChange = { hideMenu = it; vm.hideMenuButton = it }) Switch(checked = hideMenu, onCheckedChange = { hideMenu = it; vm.hideMenuButton = it })
} }
Text(tr("settings.device.footer"), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(start = 44.dp, top = 6.dp)) Text(tr("settings.device.footer"), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(start = 44.dp, top = 6.dp))
Divider(Modifier.padding(vertical = 16.dp))
Section(tr("settings.more"))
NavRow(tr("menu.accounts"), onOpenAccounts)
NavRow(tr("groups.title"), onOpenGroups)
NavRow(tr("menu.profile"), onOpenProfile)
NavRow(tr("menu.server"), onSwitchServer)
NavRow(tr("menu.logout"), onLogout, destructive = true)
Spacer(Modifier.size(40.dp)) Spacer(Modifier.size(40.dp))
} }
} }
@@ -239,47 +229,39 @@ private fun Section(title: String) {
Text(title, style = MaterialTheme.typography.titleSmall, fontWeight = FontWeight.SemiBold, modifier = Modifier.padding(bottom = 8.dp)) Text(title, style = MaterialTheme.typography.titleSmall, fontWeight = FontWeight.SemiBold, modifier = Modifier.padding(bottom = 8.dp))
} }
@Composable
private fun NavRow(label: String, onClick: () -> Unit, destructive: Boolean = false) {
Row(
Modifier.fillMaxWidth().clickable(onClick = onClick).padding(vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
label,
style = MaterialTheme.typography.bodyLarge,
color = if (destructive) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurface,
)
}
}
/** Leading per-row sync toggle: highlighted = synced across devices. */ /** Leading per-row sync toggle: highlighted = synced across devices. */
@Composable @Composable
private fun SyncIcon(on: Boolean, onClick: () -> Unit) { private fun SyncIcon(on: Boolean, onClick: () -> Unit) {
IconButton(onClick = onClick, modifier = Modifier.size(36.dp)) { IconButton(onClick = onClick, modifier = Modifier.size(32.dp)) {
Icon( Icon(
Icons.Filled.Refresh, Icons.Filled.Refresh,
contentDescription = tr("settings.sync_this"), contentDescription = tr("settings.sync_this"),
modifier = Modifier.size(18.dp),
tint = if (on) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant, tint = if (on) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant,
) )
} }
} }
@OptIn(ExperimentalMaterial3Api::class) // Compact dropdown trigger (a small outlined chip) — much shorter than a full
// OutlinedTextField, so the settings rows aren't inflated.
@Composable @Composable
private fun Dropdown(options: List<Pair<String, String>>, selected: String, onSelect: (String) -> Unit) { private fun Dropdown(options: List<Pair<String, String>>, selected: String, onSelect: (String) -> Unit) {
var expanded by remember { mutableStateOf(false) } var expanded by remember { mutableStateOf(false) }
val selectedLabel = options.firstOrNull { it.first == selected }?.second ?: selected val selectedLabel = options.firstOrNull { it.first == selected }?.second ?: selected
ExposedDropdownMenuBox(expanded = expanded, onExpandedChange = { expanded = it }, modifier = Modifier.width(170.dp)) { Box {
OutlinedTextField( Row(
value = selectedLabel, Modifier
onValueChange = {}, .clip(RoundedCornerShape(8.dp))
readOnly = true, .border(1.dp, MaterialTheme.colorScheme.outline, RoundedCornerShape(8.dp))
singleLine = true, .clickable { expanded = true }
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) }, .padding(start = 12.dp, end = 6.dp, top = 6.dp, bottom = 6.dp),
modifier = Modifier.menuAnchor().fillMaxWidth(), verticalAlignment = Alignment.CenterVertically,
) ) {
ExposedDropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) { Text(selectedLabel, style = MaterialTheme.typography.bodyMedium, maxLines = 1)
Icon(Icons.Filled.ArrowDropDown, contentDescription = null, tint = MaterialTheme.colorScheme.onSurfaceVariant)
}
DropdownMenu(expanded = expanded, onDismissRequest = { expanded = false }) {
options.forEach { (key, label) -> options.forEach { (key, label) ->
DropdownMenuItem(text = { Text(label) }, onClick = { onSelect(key); expanded = false }) DropdownMenuItem(text = { Text(label) }, onClick = { onSelect(key); expanded = false })
} }
@@ -299,7 +281,7 @@ private fun SyncDropdownRow(
Row(Modifier.fillMaxWidth().padding(vertical = 4.dp), verticalAlignment = Alignment.CenterVertically) { Row(Modifier.fillMaxWidth().padding(vertical = 4.dp), verticalAlignment = Alignment.CenterVertically) {
SyncIcon(synced, onToggleSync) SyncIcon(synced, onToggleSync)
Spacer(Modifier.size(8.dp)) Spacer(Modifier.size(8.dp))
Text(label, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.weight(1f)) Text(label, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.weight(1f))
Dropdown(options, selected, onSelect) Dropdown(options, selected, onSelect)
} }
} }
@@ -313,7 +295,7 @@ private fun DeviceDropdownRow(
) { ) {
Row(Modifier.fillMaxWidth().padding(vertical = 4.dp), verticalAlignment = Alignment.CenterVertically) { Row(Modifier.fillMaxWidth().padding(vertical = 4.dp), verticalAlignment = Alignment.CenterVertically) {
Spacer(Modifier.size(44.dp)) Spacer(Modifier.size(44.dp))
Text(label, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.weight(1f)) Text(label, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.weight(1f))
Dropdown(options, selected, onSelect) Dropdown(options, selected, onSelect)
} }
} }
@@ -323,7 +305,7 @@ private fun SyncSwitchRow(label: String, checked: Boolean, onChange: (Boolean) -
Row(Modifier.fillMaxWidth().padding(vertical = 4.dp), verticalAlignment = Alignment.CenterVertically) { Row(Modifier.fillMaxWidth().padding(vertical = 4.dp), verticalAlignment = Alignment.CenterVertically) {
SyncIcon(synced, onToggleSync) SyncIcon(synced, onToggleSync)
Spacer(Modifier.size(8.dp)) Spacer(Modifier.size(8.dp))
Text(label, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.weight(1f)) Text(label, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.weight(1f))
Switch(checked = checked, onCheckedChange = onChange) Switch(checked = checked, onCheckedChange = onChange)
} }
} }
@@ -341,7 +323,7 @@ private fun SyncColorRow(
Row(Modifier.fillMaxWidth().padding(vertical = 6.dp), verticalAlignment = Alignment.CenterVertically) { Row(Modifier.fillMaxWidth().padding(vertical = 6.dp), verticalAlignment = Alignment.CenterVertically) {
SyncIcon(synced, onToggleSync) SyncIcon(synced, onToggleSync)
Spacer(Modifier.size(8.dp)) Spacer(Modifier.size(8.dp))
Text(label, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.weight(1f)) Text(label, style = MaterialTheme.typography.bodyMedium, modifier = Modifier.weight(1f))
Text(colorFromHex(current).toHex(), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) Text(colorFromHex(current).toHex(), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant)
Spacer(Modifier.size(12.dp)) Spacer(Modifier.size(12.dp))
Box( Box(