- Back now closes the drawer instead of the app: a `BackHandler` inside the sheet, enabled while the drawer is open. The four host screens (Month/Week/Day/Agenda) pass their `drawerState` in. - Header and section labels use `GroupedListInset` instead of a hardcoded 28.dp, so "Calendula", "View" and "Calendars" share the left edge of the rows below them — same as the Settings screens. The account labels and placeholders in `CalendarFilterList` follow. - Plain leading icons now sit in a 40.dp box, matching `CalendarColorChip`'s footprint, so view rows, jump-to-date, Settings and the calendar rows all line up on one vertical axis. Closes #114 Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de> Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/121
This commit is contained in:
@@ -112,6 +112,7 @@ fun AgendaScreen(
|
|||||||
CalendarDrawer(
|
CalendarDrawer(
|
||||||
currentView = selectedView,
|
currentView = selectedView,
|
||||||
currentDate = anchor,
|
currentDate = anchor,
|
||||||
|
drawerState = drawerState,
|
||||||
viewOrder = drawerViewOrder,
|
viewOrder = drawerViewOrder,
|
||||||
onSelectView = { view ->
|
onSelectView = { view ->
|
||||||
onSelectView(view)
|
onSelectView(view)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package de.jeanlucmakiola.calendula.ui.common
|
package de.jeanlucmakiola.calendula.ui.common
|
||||||
|
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@@ -19,6 +20,7 @@ import androidx.compose.foundation.verticalScroll
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.DateRange
|
import androidx.compose.material.icons.filled.DateRange
|
||||||
import androidx.compose.material.icons.filled.Settings
|
import androidx.compose.material.icons.filled.Settings
|
||||||
|
import androidx.compose.material3.DrawerState
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ModalDrawerSheet
|
import androidx.compose.material3.ModalDrawerSheet
|
||||||
@@ -27,19 +29,23 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.res.colorResource
|
import androidx.compose.ui.res.colorResource
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import de.jeanlucmakiola.calendula.R
|
import de.jeanlucmakiola.calendula.R
|
||||||
import de.jeanlucmakiola.calendula.ui.filter.CalendarFilterList
|
import de.jeanlucmakiola.calendula.ui.filter.CalendarFilterList
|
||||||
|
import de.jeanlucmakiola.floret.components.GroupedListInset
|
||||||
import de.jeanlucmakiola.floret.components.GroupedRow
|
import de.jeanlucmakiola.floret.components.GroupedRow
|
||||||
import de.jeanlucmakiola.floret.components.Position
|
import de.jeanlucmakiola.floret.components.Position
|
||||||
import de.jeanlucmakiola.floret.components.positionOf
|
import de.jeanlucmakiola.floret.components.positionOf
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +56,8 @@ import kotlinx.datetime.LocalDate
|
|||||||
* a jump-to-date action, the per-calendar visibility filter (M3) inline, and a
|
* a jump-to-date action, the per-calendar visibility filter (M3) inline, and a
|
||||||
* pinned Settings row. The "View" section mirrors the top-bar switcher pill —
|
* pinned Settings row. The "View" section mirrors the top-bar switcher pill —
|
||||||
* tapping a view here selects it (and closes the drawer) rather than cycling.
|
* tapping a view here selects it (and closes the drawer) rather than cycling.
|
||||||
* The host screen owns the drawer state.
|
* The host screen owns the drawer state; the sheet reads it only to dismiss
|
||||||
|
* itself on back.
|
||||||
*
|
*
|
||||||
* [currentDate] seeds the jump-to-date picker (the visible day/week-start/month
|
* [currentDate] seeds the jump-to-date picker (the visible day/week-start/month
|
||||||
* anchor); [onJumpToDate] navigates the active view to the chosen day.
|
* anchor); [onJumpToDate] navigates the active view to the chosen day.
|
||||||
@@ -59,12 +66,17 @@ import kotlinx.datetime.LocalDate
|
|||||||
fun CalendarDrawer(
|
fun CalendarDrawer(
|
||||||
currentView: CalendarView,
|
currentView: CalendarView,
|
||||||
currentDate: LocalDate,
|
currentDate: LocalDate,
|
||||||
|
drawerState: DrawerState,
|
||||||
onSelectView: (CalendarView) -> Unit,
|
onSelectView: (CalendarView) -> Unit,
|
||||||
onJumpToDate: (LocalDate) -> Unit,
|
onJumpToDate: (LocalDate) -> Unit,
|
||||||
onSettings: () -> Unit,
|
onSettings: () -> Unit,
|
||||||
viewOrder: List<CalendarView> = IMPLEMENTED_VIEWS,
|
viewOrder: List<CalendarView> = IMPLEMENTED_VIEWS,
|
||||||
) {
|
) {
|
||||||
var showDatePicker by remember { mutableStateOf(false) }
|
var showDatePicker by remember { mutableStateOf(false) }
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
// Registered in the sheet so it takes precedence over the host's back handler.
|
||||||
|
BackHandler(enabled = drawerState.isOpen) { scope.launch { drawerState.close() } }
|
||||||
|
|
||||||
ModalDrawerSheet {
|
ModalDrawerSheet {
|
||||||
// The whole sidebar scrolls as one — header, views, the calendar filter
|
// The whole sidebar scrolls as one — header, views, the calendar filter
|
||||||
@@ -83,7 +95,7 @@ fun CalendarDrawer(
|
|||||||
position = positionOf(index, viewOrder.size),
|
position = positionOf(index, viewOrder.size),
|
||||||
selected = view == currentView,
|
selected = view == currentView,
|
||||||
minHeight = 56.dp,
|
minHeight = 56.dp,
|
||||||
leading = { Icon(view.icon, contentDescription = null) },
|
leading = { DrawerLeadingIcon(view.icon) },
|
||||||
onClick = { onSelectView(view) },
|
onClick = { onSelectView(view) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -93,7 +105,7 @@ fun CalendarDrawer(
|
|||||||
title = stringResource(R.string.drawer_jump_to_date),
|
title = stringResource(R.string.drawer_jump_to_date),
|
||||||
position = Position.Alone,
|
position = Position.Alone,
|
||||||
minHeight = 56.dp,
|
minHeight = 56.dp,
|
||||||
leading = { Icon(Icons.Filled.DateRange, contentDescription = null) },
|
leading = { DrawerLeadingIcon(Icons.Filled.DateRange) },
|
||||||
onClick = { showDatePicker = true },
|
onClick = { showDatePicker = true },
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -107,7 +119,7 @@ fun CalendarDrawer(
|
|||||||
title = stringResource(R.string.month_action_settings),
|
title = stringResource(R.string.month_action_settings),
|
||||||
position = Position.Alone,
|
position = Position.Alone,
|
||||||
minHeight = 56.dp,
|
minHeight = 56.dp,
|
||||||
leading = { Icon(Icons.Filled.Settings, contentDescription = null) },
|
leading = { DrawerLeadingIcon(Icons.Filled.Settings) },
|
||||||
onClick = onSettings,
|
onClick = onSettings,
|
||||||
)
|
)
|
||||||
Spacer(Modifier.height(8.dp))
|
Spacer(Modifier.height(8.dp))
|
||||||
@@ -126,13 +138,27 @@ fun CalendarDrawer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Leading slot for the drawer's plain icons: the same 40.dp footprint
|
||||||
|
* [CalendarColorChip] takes, so every leading glyph shares one vertical axis. */
|
||||||
|
@Composable
|
||||||
|
private fun DrawerLeadingIcon(icon: ImageVector) {
|
||||||
|
Box(Modifier.size(40.dp), contentAlignment = Alignment.Center) {
|
||||||
|
Icon(icon, contentDescription = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Branded header: the app-icon chip beside the app name. */
|
/** Branded header: the app-icon chip beside the app name. */
|
||||||
@Composable
|
@Composable
|
||||||
private fun DrawerHeader() {
|
private fun DrawerHeader() {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(start = 28.dp, end = 28.dp, top = 24.dp, bottom = 16.dp),
|
.padding(
|
||||||
|
start = GroupedListInset,
|
||||||
|
end = GroupedListInset,
|
||||||
|
top = 24.dp,
|
||||||
|
bottom = 16.dp,
|
||||||
|
),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
@@ -164,6 +190,11 @@ private fun DrawerSectionHeader(text: String) {
|
|||||||
text = text,
|
text = text,
|
||||||
style = MaterialTheme.typography.titleSmall,
|
style = MaterialTheme.typography.titleSmall,
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
modifier = Modifier.padding(start = 28.dp, end = 28.dp, top = 16.dp, bottom = 8.dp),
|
modifier = Modifier.padding(
|
||||||
|
start = GroupedListInset,
|
||||||
|
end = GroupedListInset,
|
||||||
|
top = 16.dp,
|
||||||
|
bottom = 8.dp,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,6 +198,7 @@ fun DayScreen(
|
|||||||
CalendarDrawer(
|
CalendarDrawer(
|
||||||
currentView = selectedView,
|
currentView = selectedView,
|
||||||
currentDate = date,
|
currentDate = date,
|
||||||
|
drawerState = drawerState,
|
||||||
viewOrder = drawerViewOrder,
|
viewOrder = drawerViewOrder,
|
||||||
onSelectView = { view ->
|
onSelectView = { view ->
|
||||||
onSelectView(view)
|
onSelectView(view)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import de.jeanlucmakiola.calendula.R
|
|||||||
import de.jeanlucmakiola.calendula.domain.FailureReason
|
import de.jeanlucmakiola.calendula.domain.FailureReason
|
||||||
import de.jeanlucmakiola.calendula.ui.common.CalendarColorChip
|
import de.jeanlucmakiola.calendula.ui.common.CalendarColorChip
|
||||||
import de.jeanlucmakiola.calendula.ui.common.sourceAppName
|
import de.jeanlucmakiola.calendula.ui.common.sourceAppName
|
||||||
|
import de.jeanlucmakiola.floret.components.GroupedListInset
|
||||||
import de.jeanlucmakiola.floret.components.GroupedRow
|
import de.jeanlucmakiola.floret.components.GroupedRow
|
||||||
import de.jeanlucmakiola.floret.components.positionOf
|
import de.jeanlucmakiola.floret.components.positionOf
|
||||||
|
|
||||||
@@ -73,7 +74,12 @@ private fun FilterList(
|
|||||||
},
|
},
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
modifier = Modifier.padding(start = 28.dp, end = 28.dp, top = 12.dp, bottom = 4.dp),
|
modifier = Modifier.padding(
|
||||||
|
start = GroupedListInset,
|
||||||
|
end = GroupedListInset,
|
||||||
|
top = 12.dp,
|
||||||
|
bottom = 4.dp,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
group.calendars.forEachIndexed { index, cal ->
|
group.calendars.forEachIndexed { index, cal ->
|
||||||
GroupedRow(
|
GroupedRow(
|
||||||
@@ -103,7 +109,7 @@ private fun FilterLoading(modifier: Modifier = Modifier) {
|
|||||||
repeat(4) {
|
repeat(4) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 28.dp)
|
.padding(horizontal = GroupedListInset)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.height(36.dp)
|
.height(36.dp)
|
||||||
.background(
|
.background(
|
||||||
@@ -129,6 +135,6 @@ private fun FilterMessage(reason: FailureReason, modifier: Modifier = Modifier)
|
|||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 28.dp, vertical = 24.dp),
|
.padding(horizontal = GroupedListInset, vertical = 24.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -330,6 +330,7 @@ fun MonthScreen(
|
|||||||
CalendarDrawer(
|
CalendarDrawer(
|
||||||
currentView = selectedView,
|
currentView = selectedView,
|
||||||
currentDate = LocalDate(titleMonth.year, titleMonth.month, 1),
|
currentDate = LocalDate(titleMonth.year, titleMonth.month, 1),
|
||||||
|
drawerState = drawerState,
|
||||||
viewOrder = drawerViewOrder,
|
viewOrder = drawerViewOrder,
|
||||||
onSelectView = { view ->
|
onSelectView = { view ->
|
||||||
onSelectView(view)
|
onSelectView(view)
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ fun WeekScreen(
|
|||||||
CalendarDrawer(
|
CalendarDrawer(
|
||||||
currentView = selectedView,
|
currentView = selectedView,
|
||||||
currentDate = weekStart,
|
currentDate = weekStart,
|
||||||
|
drawerState = drawerState,
|
||||||
viewOrder = drawerViewOrder,
|
viewOrder = drawerViewOrder,
|
||||||
onSelectView = { view ->
|
onSelectView = { view ->
|
||||||
onSelectView(view)
|
onSelectView(view)
|
||||||
|
|||||||
Reference in New Issue
Block a user