This commit was merged in pull request #60.
This commit is contained in:
@@ -10,6 +10,7 @@ import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
@@ -17,6 +18,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.testTag
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
@@ -28,12 +30,12 @@ import org.shahondin1624.lib.components.TestTags
|
||||
import org.shahondin1624.lib.components.UiConstants
|
||||
import org.shahondin1624.lib.components.charactermodel.CharacterSheetPage
|
||||
import org.shahondin1624.lib.components.settings.SettingsPage
|
||||
import org.shahondin1624.model.EXAMPLE_CHARACTER
|
||||
import org.shahondin1624.navigation.AppRoutes
|
||||
import org.shahondin1624.theme.AppTheme
|
||||
import org.shahondin1624.theme.LocalThemeIsDark
|
||||
import org.shahondin1624.theme.LocalWindowSizeClass
|
||||
import org.shahondin1624.theme.WindowSizeClass
|
||||
import org.shahondin1624.viewmodel.CharacterViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Preview
|
||||
@@ -46,20 +48,21 @@ fun App(
|
||||
|
||||
CompositionLocalProvider(LocalWindowSizeClass provides windowSizeClass) {
|
||||
val navController = rememberNavController()
|
||||
AppContent(navController)
|
||||
val characterViewModel: CharacterViewModel = viewModel { CharacterViewModel() }
|
||||
AppContent(navController, characterViewModel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun AppContent(navController: NavHostController) {
|
||||
private fun AppContent(navController: NavHostController, characterViewModel: CharacterViewModel) {
|
||||
val windowSizeClass = LocalWindowSizeClass.current
|
||||
|
||||
when (windowSizeClass) {
|
||||
WindowSizeClass.Compact -> CompactNavigation(navController)
|
||||
WindowSizeClass.Medium -> MediumNavigation(navController)
|
||||
WindowSizeClass.Expanded -> ExpandedNavigation(navController)
|
||||
WindowSizeClass.Compact -> CompactNavigation(navController, characterViewModel)
|
||||
WindowSizeClass.Medium -> MediumNavigation(navController, characterViewModel)
|
||||
WindowSizeClass.Expanded -> ExpandedNavigation(navController, characterViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +94,7 @@ private fun navigateTo(navController: NavHostController, route: String) {
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun CompactNavigation(navController: NavHostController) {
|
||||
private fun CompactNavigation(navController: NavHostController, characterViewModel: CharacterViewModel) {
|
||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||
val scope = rememberCoroutineScope()
|
||||
val currentRoute = currentRoute(navController)
|
||||
@@ -112,6 +115,7 @@ private fun CompactNavigation(navController: NavHostController) {
|
||||
) {
|
||||
MainScaffold(
|
||||
navController = navController,
|
||||
characterViewModel = characterViewModel,
|
||||
showMenuButton = true,
|
||||
onMenuClick = {
|
||||
scope.launch {
|
||||
@@ -127,7 +131,7 @@ private fun CompactNavigation(navController: NavHostController) {
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun MediumNavigation(navController: NavHostController) {
|
||||
private fun MediumNavigation(navController: NavHostController, characterViewModel: CharacterViewModel) {
|
||||
val currentRoute = currentRoute(navController)
|
||||
|
||||
Row(modifier = Modifier.fillMaxSize()) {
|
||||
@@ -152,6 +156,7 @@ private fun MediumNavigation(navController: NavHostController) {
|
||||
}
|
||||
MainScaffold(
|
||||
navController = navController,
|
||||
characterViewModel = characterViewModel,
|
||||
showMenuButton = false,
|
||||
onMenuClick = {},
|
||||
modifier = Modifier.weight(1f)
|
||||
@@ -164,7 +169,7 @@ private fun MediumNavigation(navController: NavHostController) {
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ExpandedNavigation(navController: NavHostController) {
|
||||
private fun ExpandedNavigation(navController: NavHostController, characterViewModel: CharacterViewModel) {
|
||||
val currentRoute = currentRoute(navController)
|
||||
|
||||
PermanentNavigationDrawer(
|
||||
@@ -179,6 +184,7 @@ private fun ExpandedNavigation(navController: NavHostController) {
|
||||
) {
|
||||
MainScaffold(
|
||||
navController = navController,
|
||||
characterViewModel = characterViewModel,
|
||||
showMenuButton = false,
|
||||
onMenuClick = {}
|
||||
)
|
||||
@@ -225,25 +231,22 @@ private fun DrawerContent(
|
||||
|
||||
/**
|
||||
* Main scaffold with top app bar and routed content area.
|
||||
*
|
||||
* @param navController the NavHostController for page routing
|
||||
* @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(
|
||||
navController: NavHostController,
|
||||
characterViewModel: CharacterViewModel,
|
||||
showMenuButton: Boolean,
|
||||
onMenuClick: () -> Unit,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
var isDark by LocalThemeIsDark.current
|
||||
val currentRoute = currentRoute(navController)
|
||||
val character by characterViewModel.character.collectAsState()
|
||||
|
||||
val topBarTitle = when (currentRoute) {
|
||||
AppRoutes.CHARACTER_SHEET -> EXAMPLE_CHARACTER.characterData.name
|
||||
AppRoutes.CHARACTER_SHEET -> character.characterData.name
|
||||
AppRoutes.SETTINGS -> "Settings"
|
||||
else -> "Shadowrun Character Sheet"
|
||||
}
|
||||
@@ -301,7 +304,7 @@ private fun MainScaffold(
|
||||
.padding(contentPadding)
|
||||
) {
|
||||
composable(AppRoutes.CHARACTER_SHEET) {
|
||||
CharacterSheetPage(EXAMPLE_CHARACTER, contentPadding)
|
||||
CharacterSheetPage(character, contentPadding)
|
||||
}
|
||||
composable(AppRoutes.SETTINGS) {
|
||||
SettingsPage()
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.shahondin1624.viewmodel
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import org.shahondin1624.model.EXAMPLE_CHARACTER
|
||||
import org.shahondin1624.model.charactermodel.ShadowrunCharacter
|
||||
|
||||
/**
|
||||
* ViewModel holding the current character as observable state.
|
||||
* Foundation for all editing stories (6.2-6.6) and interactive features.
|
||||
*/
|
||||
class CharacterViewModel : ViewModel() {
|
||||
|
||||
private val _character = MutableStateFlow(EXAMPLE_CHARACTER)
|
||||
|
||||
/** Observable character state. */
|
||||
val character: StateFlow<ShadowrunCharacter> = _character.asStateFlow()
|
||||
|
||||
/**
|
||||
* Replace the current character entirely.
|
||||
*/
|
||||
fun setCharacter(character: ShadowrunCharacter) {
|
||||
_character.value = character
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the character by applying a transformation function.
|
||||
*/
|
||||
fun updateCharacter(transform: (ShadowrunCharacter) -> ShadowrunCharacter) {
|
||||
_character.value = transform(_character.value)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user