This commit was merged in pull request #50.
This commit is contained in:
@@ -40,18 +40,29 @@ fun App(
|
|||||||
val windowSizeClass = WindowSizeClass.fromWidth(maxWidth)
|
val windowSizeClass = WindowSizeClass.fromWidth(maxWidth)
|
||||||
|
|
||||||
CompositionLocalProvider(LocalWindowSizeClass provides windowSizeClass) {
|
CompositionLocalProvider(LocalWindowSizeClass provides windowSizeClass) {
|
||||||
AppContent(onThemeChanged = {})
|
AppContent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun AppContent(
|
private fun AppContent() {
|
||||||
onThemeChanged: @Composable (isDark: Boolean) -> Unit = {}
|
val windowSizeClass = LocalWindowSizeClass.current
|
||||||
) {
|
|
||||||
val character = EXAMPLE_CHARACTER
|
when (windowSizeClass) {
|
||||||
var isDark by LocalThemeIsDark.current
|
WindowSizeClass.Compact -> CompactNavigation()
|
||||||
|
WindowSizeClass.Medium -> MediumNavigation()
|
||||||
|
WindowSizeClass.Expanded -> ExpandedNavigation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compact layout: ModalNavigationDrawer with hamburger menu button.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
private fun CompactNavigation() {
|
||||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
@@ -59,6 +70,80 @@ private fun AppContent(
|
|||||||
drawerState = drawerState,
|
drawerState = drawerState,
|
||||||
drawerContent = {
|
drawerContent = {
|
||||||
ModalDrawerSheet {
|
ModalDrawerSheet {
|
||||||
|
DrawerContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
MainScaffold(
|
||||||
|
showMenuButton = true,
|
||||||
|
onMenuClick = {
|
||||||
|
scope.launch {
|
||||||
|
if (drawerState.isClosed) drawerState.open() else drawerState.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Medium layout: NavigationRail on the left side with main content.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
private fun MediumNavigation() {
|
||||||
|
Row(modifier = Modifier.fillMaxSize()) {
|
||||||
|
NavigationRail(
|
||||||
|
modifier = Modifier.testTag(TestTags.NAV_RAIL)
|
||||||
|
) {
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
NavigationRailItem(
|
||||||
|
icon = { Icon(Icons.Default.Person, contentDescription = null) },
|
||||||
|
label = { Text("Character") },
|
||||||
|
selected = true,
|
||||||
|
onClick = { /* TODO: Navigate */ },
|
||||||
|
modifier = Modifier.testTag(TestTags.NAV_CHARACTER_SHEET)
|
||||||
|
)
|
||||||
|
NavigationRailItem(
|
||||||
|
icon = { Icon(Icons.Default.Settings, contentDescription = null) },
|
||||||
|
label = { Text("Settings") },
|
||||||
|
selected = false,
|
||||||
|
onClick = { /* TODO: Navigate to settings */ },
|
||||||
|
modifier = Modifier.testTag(TestTags.NAV_SETTINGS)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
MainScaffold(
|
||||||
|
showMenuButton = false,
|
||||||
|
onMenuClick = {},
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expanded layout: PermanentNavigationDrawer always visible.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
private fun ExpandedNavigation() {
|
||||||
|
PermanentNavigationDrawer(
|
||||||
|
drawerContent = {
|
||||||
|
PermanentDrawerSheet(modifier = Modifier.testTag(TestTags.NAV_PERMANENT_DRAWER)) {
|
||||||
|
DrawerContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
MainScaffold(
|
||||||
|
showMenuButton = false,
|
||||||
|
onMenuClick = {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shared drawer content used by Compact (ModalDrawerSheet) and Expanded (PermanentDrawerSheet).
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
private fun DrawerContent() {
|
||||||
Spacer(Modifier.height(16.dp))
|
Spacer(Modifier.height(16.dp))
|
||||||
Text(
|
Text(
|
||||||
"Menu",
|
"Menu",
|
||||||
@@ -72,9 +157,7 @@ private fun AppContent(
|
|||||||
icon = { Icon(Icons.Default.Person, contentDescription = null) },
|
icon = { Icon(Icons.Default.Person, contentDescription = null) },
|
||||||
label = { Text("Character Sheet") },
|
label = { Text("Character Sheet") },
|
||||||
selected = true,
|
selected = true,
|
||||||
onClick = {
|
onClick = { /* TODO: Navigate */ },
|
||||||
scope.launch { drawerState.close() }
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 12.dp, vertical = 4.dp)
|
.padding(horizontal = 12.dp, vertical = 4.dp)
|
||||||
.testTag(TestTags.NAV_CHARACTER_SHEET)
|
.testTag(TestTags.NAV_CHARACTER_SHEET)
|
||||||
@@ -84,37 +167,45 @@ private fun AppContent(
|
|||||||
icon = { Icon(Icons.Default.Settings, contentDescription = null) },
|
icon = { Icon(Icons.Default.Settings, contentDescription = null) },
|
||||||
label = { Text("Settings") },
|
label = { Text("Settings") },
|
||||||
selected = false,
|
selected = false,
|
||||||
onClick = {
|
onClick = { /* TODO: Navigate to settings */ },
|
||||||
scope.launch { drawerState.close() }
|
|
||||||
// TODO: Navigate to settings
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(horizontal = 12.dp, vertical = 4.dp)
|
.padding(horizontal = 12.dp, vertical = 4.dp)
|
||||||
.testTag(TestTags.NAV_SETTINGS)
|
.testTag(TestTags.NAV_SETTINGS)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
|
* Main scaffold with top app bar and content area.
|
||||||
|
*
|
||||||
|
* @param showMenuButton whether to show the hamburger menu icon (hidden when nav is persistent)
|
||||||
|
* @param onMenuClick callback for hamburger menu button click
|
||||||
|
* @param modifier optional modifier (e.g., weight in Row for Medium layout)
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
private fun MainScaffold(
|
||||||
|
showMenuButton: Boolean,
|
||||||
|
onMenuClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
val character = EXAMPLE_CHARACTER
|
||||||
|
var isDark by LocalThemeIsDark.current
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = modifier.fillMaxSize(),
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text("Shadowrun Character Sheet") },
|
title = { Text("Shadowrun Character Sheet") },
|
||||||
|
modifier = Modifier.testTag(TestTags.TOP_APP_BAR),
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
|
if (showMenuButton) {
|
||||||
IconButton(
|
IconButton(
|
||||||
onClick = {
|
onClick = onMenuClick,
|
||||||
scope.launch {
|
|
||||||
if (drawerState.isClosed) {
|
|
||||||
drawerState.open()
|
|
||||||
} else {
|
|
||||||
drawerState.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifier = Modifier.testTag(TestTags.MENU_BUTTON)
|
modifier = Modifier.testTag(TestTags.MENU_BUTTON)
|
||||||
) {
|
) {
|
||||||
Icon(Icons.Default.Menu, contentDescription = "Menu")
|
Icon(Icons.Default.Menu, contentDescription = "Menu")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
actions = {
|
actions = {
|
||||||
IconButton(
|
IconButton(
|
||||||
@@ -156,4 +247,3 @@ private fun AppContent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ object TestTags {
|
|||||||
// --- Navigation items ---
|
// --- Navigation items ---
|
||||||
const val NAV_CHARACTER_SHEET = "nav_character_sheet"
|
const val NAV_CHARACTER_SHEET = "nav_character_sheet"
|
||||||
const val NAV_SETTINGS = "nav_settings"
|
const val NAV_SETTINGS = "nav_settings"
|
||||||
|
const val NAV_RAIL = "nav_rail"
|
||||||
|
const val NAV_PERMANENT_DRAWER = "nav_permanent_drawer"
|
||||||
|
|
||||||
// --- Dice / roll buttons ---
|
// --- Dice / roll buttons ---
|
||||||
fun rollButton(name: String): String = "roll_button_${name.lowercase().replace(" ", "_")}"
|
fun rollButton(name: String): String = "roll_button_${name.lowercase().replace(" ", "_")}"
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ class TestTagsTest {
|
|||||||
fun navTagsAreDefined() {
|
fun navTagsAreDefined() {
|
||||||
assertEquals("nav_character_sheet", TestTags.NAV_CHARACTER_SHEET)
|
assertEquals("nav_character_sheet", TestTags.NAV_CHARACTER_SHEET)
|
||||||
assertEquals("nav_settings", TestTags.NAV_SETTINGS)
|
assertEquals("nav_settings", TestTags.NAV_SETTINGS)
|
||||||
|
assertEquals("nav_rail", TestTags.NAV_RAIL)
|
||||||
|
assertEquals("nav_permanent_drawer", TestTags.NAV_PERMANENT_DRAWER)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -49,6 +51,8 @@ class TestTagsTest {
|
|||||||
TestTags.PANEL_DAMAGE_MONITOR,
|
TestTags.PANEL_DAMAGE_MONITOR,
|
||||||
TestTags.NAV_CHARACTER_SHEET,
|
TestTags.NAV_CHARACTER_SHEET,
|
||||||
TestTags.NAV_SETTINGS,
|
TestTags.NAV_SETTINGS,
|
||||||
|
TestTags.NAV_RAIL,
|
||||||
|
TestTags.NAV_PERMANENT_DRAWER,
|
||||||
TestTags.TOP_APP_BAR,
|
TestTags.TOP_APP_BAR,
|
||||||
TestTags.THEME_TOGGLE,
|
TestTags.THEME_TOGGLE,
|
||||||
TestTags.MENU_BUTTON
|
TestTags.MENU_BUTTON
|
||||||
|
|||||||
Reference in New Issue
Block a user