diff --git a/app/src/main/java/com/scarriffle/calendarr/ui/L10n.kt b/app/src/main/java/com/scarriffle/calendarr/ui/L10n.kt index 147f08a..fc2afa1 100644 --- a/app/src/main/java/com/scarriffle/calendarr/ui/L10n.kt +++ b/app/src/main/java/com/scarriffle/calendarr/ui/L10n.kt @@ -63,6 +63,7 @@ object L10n { "settings.reset" to "Zurücksetzen", "settings.appearance" to "Ansicht", "settings.device" to "Nur auf diesem Gerät", + "settings.more" to "Mehr", "settings.hide_menu_button" to "Menü-Button ausblenden", "settings.month_mode" to "Monatswechsel", "settings.month_mode.scroll" to "Fortlaufend scrollen", @@ -243,6 +244,7 @@ object L10n { "settings.reset" to "Reset", "settings.appearance" to "View", "settings.device" to "This device only", + "settings.more" to "More", "settings.hide_menu_button" to "Hide menu button", "settings.month_mode" to "Month switching", "settings.month_mode.scroll" to "Continuous scroll", diff --git a/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarDrawer.kt b/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarDrawer.kt index c064734..d77d526 100644 --- a/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarDrawer.kt +++ b/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarDrawer.kt @@ -30,6 +30,8 @@ import androidx.compose.material.icons.filled.Notifications import androidx.compose.material.icons.filled.NotificationsOff import androidx.compose.material.icons.filled.Refresh import androidx.compose.material.icons.filled.Settings +import androidx.compose.material.icons.filled.Visibility +import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api @@ -39,7 +41,6 @@ import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ModalDrawerSheet -import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable @@ -148,31 +149,31 @@ private fun header( onClose: () -> Unit, ) { Row( - Modifier.fillMaxWidth().statusBarsPadding().padding(start = 18.dp, end = 8.dp, top = 12.dp, bottom = 12.dp), + Modifier.fillMaxWidth().statusBarsPadding().padding(start = 16.dp, end = 4.dp, top = 8.dp, bottom = 8.dp), verticalAlignment = Alignment.CenterVertically, ) { Box( - Modifier.size(48.dp).clip(CircleShape).background(MaterialTheme.colorScheme.primary), + Modifier.size(38.dp).clip(CircleShape).background(MaterialTheme.colorScheme.primary), contentAlignment = Alignment.Center, ) { Text(username.firstOrNull()?.uppercase() ?: "?", - style = MaterialTheme.typography.titleMedium, + style = MaterialTheme.typography.titleSmall, color = MaterialTheme.colorScheme.onPrimary, fontWeight = FontWeight.Bold) } - Column(Modifier.weight(1f).padding(start = 14.dp)) { - Text(username, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.SemiBold, maxLines = 1) + Column(Modifier.weight(1f).padding(start = 12.dp)) { + Text(username, style = MaterialTheme.typography.bodyLarge, fontWeight = FontWeight.SemiBold, maxLines = 1) Text(serverUrl.removePrefix("https://").removePrefix("http://"), style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, maxLines = 1) } - IconButton(onClick = onSync) { - Icon(Icons.Filled.Refresh, contentDescription = tr("menu.sync"), tint = MaterialTheme.colorScheme.primary) + IconButton(onClick = onSync, modifier = Modifier.size(40.dp)) { + Icon(Icons.Filled.Refresh, contentDescription = tr("menu.sync"), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.primary) } - IconButton(onClick = onOpenMenu) { - Icon(Icons.Filled.Settings, contentDescription = tr("menu.appearance"), tint = MaterialTheme.colorScheme.primary) + IconButton(onClick = onOpenMenu, modifier = Modifier.size(40.dp)) { + Icon(Icons.Filled.Settings, contentDescription = tr("menu.appearance"), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.primary) } - IconButton(onClick = onClose) { - Icon(Icons.Filled.Close, contentDescription = tr("common.close"), tint = MaterialTheme.colorScheme.onSurfaceVariant) + IconButton(onClick = onClose, modifier = Modifier.size(40.dp)) { + Icon(Icons.Filled.Close, contentDescription = tr("common.close"), modifier = Modifier.size(20.dp), tint = MaterialTheme.colorScheme.onSurfaceVariant) } } } @@ -181,7 +182,7 @@ private fun header( @Composable private fun viewSwitcher(current: CalViewType, onSelect: (CalViewType) -> Unit) { Row( - Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()).padding(horizontal = 12.dp, vertical = 12.dp), + Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()).padding(horizontal = 12.dp, vertical = 8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { CalViewType.entries.forEach { type -> @@ -199,7 +200,7 @@ private fun viewSwitcher(current: CalViewType, onSelect: (CalViewType) -> Unit) @Composable private fun groupSwitcher(groups: List, active: Group?, onSwitch: (Group?) -> Unit) { Row( - Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()).padding(horizontal = 12.dp, vertical = 12.dp), + Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()).padding(horizontal = 12.dp, vertical = 8.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { FilterChip( @@ -239,29 +240,41 @@ private fun CalendarRow( onClick = { if (!sorting) onToggle(visible) }, onLongClick = { if (!sorting) menuOpen = true }, ) - .padding(horizontal = 16.dp, vertical = 10.dp), + .padding(start = 16.dp, end = 4.dp, top = 5.dp, bottom = 5.dp), verticalAlignment = Alignment.CenterVertically, ) { - Box(Modifier.size(14.dp).clip(CircleShape).background(colorFromHex(entry.color))) + Box(Modifier.size(12.dp).clip(CircleShape).background(colorFromHex(entry.color))) Text( entry.name, modifier = Modifier.weight(1f).padding(start = 12.dp), - style = MaterialTheme.typography.bodyLarge, + style = MaterialTheme.typography.bodyMedium, + maxLines = 1, color = if (visible) MaterialTheme.colorScheme.onSurface else MaterialTheme.colorScheme.onSurfaceVariant, ) if (entry.readOnly) { Icon(Icons.Filled.Lock, contentDescription = tr("filter.read_only"), - tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(end = 6.dp).size(15.dp)) + tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(end = 4.dp).size(14.dp)) } if (sorting) { - IconButton(onClick = onMoveUp) { Icon(Icons.Filled.KeyboardArrowUp, contentDescription = tr("filter.move_up")) } - IconButton(onClick = onMoveDown) { Icon(Icons.Filled.KeyboardArrowDown, contentDescription = tr("filter.move_down")) } + IconButton(onClick = onMoveUp, modifier = Modifier.size(36.dp)) { + Icon(Icons.Filled.KeyboardArrowUp, contentDescription = tr("filter.move_up")) + } + IconButton(onClick = onMoveDown, modifier = Modifier.size(36.dp)) { + Icon(Icons.Filled.KeyboardArrowDown, contentDescription = tr("filter.move_down")) + } } else { if (reminderDisabled) { Icon(Icons.Filled.NotificationsOff, contentDescription = null, - tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(end = 6.dp).size(16.dp)) + tint = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(end = 2.dp).size(15.dp)) + } + IconButton(onClick = { onToggle(visible) }, modifier = Modifier.size(40.dp)) { + Icon( + if (visible) Icons.Filled.Visibility else Icons.Filled.VisibilityOff, + contentDescription = null, + modifier = Modifier.size(20.dp), + tint = if (visible) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onSurfaceVariant, + ) } - Switch(checked = visible, onCheckedChange = onToggle) } } DropdownMenu(expanded = menuOpen, onDismissRequest = { menuOpen = false }) { diff --git a/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarScreen.kt b/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarScreen.kt index 89824c7..d15a198 100644 --- a/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarScreen.kt +++ b/app/src/main/java/com/scarriffle/calendarr/ui/calendar/CalendarScreen.kt @@ -73,7 +73,6 @@ import com.scarriffle.calendarr.ui.event.EventDetailScreen import com.scarriffle.calendarr.ui.event.EventEditorSheet import com.scarriffle.calendarr.ui.groups.GroupIcon import com.scarriffle.calendarr.ui.groups.GroupsScreen -import com.scarriffle.calendarr.ui.menu.MenuSheet import com.scarriffle.calendarr.ui.profile.ProfileScreen import com.scarriffle.calendarr.ui.settings.SettingsScreen import com.scarriffle.calendarr.ui.tr @@ -155,7 +154,6 @@ fun CalendarScreen( } var viewMenuOpen by remember { mutableStateOf(false) } - var showMenu by remember { mutableStateOf(false) } var detailEvent by remember { mutableStateOf(null) } var editor by remember { mutableStateOf(null) } var overlay by remember { mutableStateOf(Overlay.NONE) } @@ -200,7 +198,7 @@ fun CalendarScreen( CalendarDrawerContent( state = state, vm = vm, username = username, serverUrl = serverUrl, calendars = drawerCalendars, - onOpenMenu = { drawerScope.launch { drawerState.close() }; showMenu = true }, + onOpenMenu = { drawerScope.launch { drawerState.close() }; overlay = Overlay.SETTINGS }, onSync = { drawerScope.launch { drawerState.close() }; vm.syncWithServer() }, onClose = { drawerScope.launch { drawerState.close() } }, ) @@ -293,23 +291,6 @@ fun CalendarScreen( // ---- Sheets ---- - if (showMenu) { - MenuSheet( - isAdmin = false, - groups = state.groups, - activeGroup = state.activeGroup, - onSwitchGroup = { showMenu = false; vm.switchGroup(it) }, - onDismiss = { showMenu = false }, - onProfile = { showMenu = false; overlay = Overlay.PROFILE }, - onAppearance = { showMenu = false; overlay = Overlay.SETTINGS }, - onAccounts = { showMenu = false; overlay = Overlay.ACCOUNTS }, - onGroups = { showMenu = false; overlay = Overlay.GROUPS }, - onSync = { showMenu = false; vm.syncWithServer() }, - onLogout = { showMenu = false; onLogout() }, - onSwitchServer = { showMenu = false; onSwitchServer() }, - ) - } - dayPreview?.let { date -> DayPreviewDialog( date = date, @@ -387,6 +368,11 @@ fun CalendarScreen( onClose = { overlay = Overlay.NONE; vm.refreshMonthViewMode() }, onSettingsChanged = onSettingsChanged, onSettingsSynced = onSettingsSynced, + onOpenProfile = { overlay = Overlay.PROFILE }, + onOpenAccounts = { overlay = Overlay.ACCOUNTS }, + onOpenGroups = { overlay = Overlay.GROUPS }, + onSwitchServer = onSwitchServer, + onLogout = onLogout, ) Overlay.ACCOUNTS -> AccountsScreen( onClose = { overlay = Overlay.NONE }, @@ -506,6 +492,8 @@ private fun CompactTopBar( Modifier.fillMaxWidth().height(50.dp).padding(horizontal = 2.dp), verticalAlignment = Alignment.CenterVertically, ) { + // Menu (hamburger) on the left — the drawer opens from the left. + if (showMenuButton) CompactIcon(Icons.Filled.Menu, onMenu, tr("nav.menu")) CompactIcon(Icons.Filled.ChevronLeft, onPrev) TextButton(onClick = onToday, contentPadding = PaddingValues(horizontal = 6.dp)) { Text(tr("nav.today"), fontSize = 13.sp) @@ -539,7 +527,6 @@ private fun CompactTopBar( } } } - if (showMenuButton) CompactIcon(Icons.Filled.Menu, onMenu, tr("nav.menu")) } Divider( thickness = 0.5.dp, diff --git a/app/src/main/java/com/scarriffle/calendarr/ui/settings/SettingsScreen.kt b/app/src/main/java/com/scarriffle/calendarr/ui/settings/SettingsScreen.kt index 83e4390..c5396b6 100644 --- a/app/src/main/java/com/scarriffle/calendarr/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/com/scarriffle/calendarr/ui/settings/SettingsScreen.kt @@ -68,6 +68,11 @@ fun SettingsScreen( onClose: () -> Unit, onSettingsChanged: (AppSettings) -> Unit, onSettingsSynced: () -> Unit, + onOpenProfile: () -> Unit = {}, + onOpenAccounts: () -> Unit = {}, + onOpenGroups: () -> Unit = {}, + onSwitchServer: () -> Unit = {}, + onLogout: () -> Unit = {}, vm: SettingsViewModel = hiltViewModel(), ) { val initialSettings = LocalAppSettings.current @@ -209,6 +214,14 @@ fun SettingsScreen( 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)) + + 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)) } } @@ -226,6 +239,20 @@ private fun Section(title: String) { 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. */ @Composable private fun SyncIcon(on: Boolean, onClick: () -> Unit) {