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.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
@@ -17,6 +18,7 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
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.UiConstants
|
||||||
import org.shahondin1624.lib.components.charactermodel.CharacterSheetPage
|
import org.shahondin1624.lib.components.charactermodel.CharacterSheetPage
|
||||||
import org.shahondin1624.lib.components.settings.SettingsPage
|
import org.shahondin1624.lib.components.settings.SettingsPage
|
||||||
import org.shahondin1624.model.EXAMPLE_CHARACTER
|
|
||||||
import org.shahondin1624.navigation.AppRoutes
|
import org.shahondin1624.navigation.AppRoutes
|
||||||
import org.shahondin1624.theme.AppTheme
|
import org.shahondin1624.theme.AppTheme
|
||||||
import org.shahondin1624.theme.LocalThemeIsDark
|
import org.shahondin1624.theme.LocalThemeIsDark
|
||||||
import org.shahondin1624.theme.LocalWindowSizeClass
|
import org.shahondin1624.theme.LocalWindowSizeClass
|
||||||
import org.shahondin1624.theme.WindowSizeClass
|
import org.shahondin1624.theme.WindowSizeClass
|
||||||
|
import org.shahondin1624.viewmodel.CharacterViewModel
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Preview
|
@Preview
|
||||||
@@ -46,20 +48,21 @@ fun App(
|
|||||||
|
|
||||||
CompositionLocalProvider(LocalWindowSizeClass provides windowSizeClass) {
|
CompositionLocalProvider(LocalWindowSizeClass provides windowSizeClass) {
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
AppContent(navController)
|
val characterViewModel: CharacterViewModel = viewModel { CharacterViewModel() }
|
||||||
|
AppContent(navController, characterViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun AppContent(navController: NavHostController) {
|
private fun AppContent(navController: NavHostController, characterViewModel: CharacterViewModel) {
|
||||||
val windowSizeClass = LocalWindowSizeClass.current
|
val windowSizeClass = LocalWindowSizeClass.current
|
||||||
|
|
||||||
when (windowSizeClass) {
|
when (windowSizeClass) {
|
||||||
WindowSizeClass.Compact -> CompactNavigation(navController)
|
WindowSizeClass.Compact -> CompactNavigation(navController, characterViewModel)
|
||||||
WindowSizeClass.Medium -> MediumNavigation(navController)
|
WindowSizeClass.Medium -> MediumNavigation(navController, characterViewModel)
|
||||||
WindowSizeClass.Expanded -> ExpandedNavigation(navController)
|
WindowSizeClass.Expanded -> ExpandedNavigation(navController, characterViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +94,7 @@ private fun navigateTo(navController: NavHostController, route: String) {
|
|||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun CompactNavigation(navController: NavHostController) {
|
private fun CompactNavigation(navController: NavHostController, characterViewModel: CharacterViewModel) {
|
||||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val currentRoute = currentRoute(navController)
|
val currentRoute = currentRoute(navController)
|
||||||
@@ -112,6 +115,7 @@ private fun CompactNavigation(navController: NavHostController) {
|
|||||||
) {
|
) {
|
||||||
MainScaffold(
|
MainScaffold(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
|
characterViewModel = characterViewModel,
|
||||||
showMenuButton = true,
|
showMenuButton = true,
|
||||||
onMenuClick = {
|
onMenuClick = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
@@ -127,7 +131,7 @@ private fun CompactNavigation(navController: NavHostController) {
|
|||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun MediumNavigation(navController: NavHostController) {
|
private fun MediumNavigation(navController: NavHostController, characterViewModel: CharacterViewModel) {
|
||||||
val currentRoute = currentRoute(navController)
|
val currentRoute = currentRoute(navController)
|
||||||
|
|
||||||
Row(modifier = Modifier.fillMaxSize()) {
|
Row(modifier = Modifier.fillMaxSize()) {
|
||||||
@@ -152,6 +156,7 @@ private fun MediumNavigation(navController: NavHostController) {
|
|||||||
}
|
}
|
||||||
MainScaffold(
|
MainScaffold(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
|
characterViewModel = characterViewModel,
|
||||||
showMenuButton = false,
|
showMenuButton = false,
|
||||||
onMenuClick = {},
|
onMenuClick = {},
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
@@ -164,7 +169,7 @@ private fun MediumNavigation(navController: NavHostController) {
|
|||||||
*/
|
*/
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun ExpandedNavigation(navController: NavHostController) {
|
private fun ExpandedNavigation(navController: NavHostController, characterViewModel: CharacterViewModel) {
|
||||||
val currentRoute = currentRoute(navController)
|
val currentRoute = currentRoute(navController)
|
||||||
|
|
||||||
PermanentNavigationDrawer(
|
PermanentNavigationDrawer(
|
||||||
@@ -179,6 +184,7 @@ private fun ExpandedNavigation(navController: NavHostController) {
|
|||||||
) {
|
) {
|
||||||
MainScaffold(
|
MainScaffold(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
|
characterViewModel = characterViewModel,
|
||||||
showMenuButton = false,
|
showMenuButton = false,
|
||||||
onMenuClick = {}
|
onMenuClick = {}
|
||||||
)
|
)
|
||||||
@@ -225,25 +231,22 @@ private fun DrawerContent(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Main scaffold with top app bar and routed content area.
|
* 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)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun MainScaffold(
|
private fun MainScaffold(
|
||||||
navController: NavHostController,
|
navController: NavHostController,
|
||||||
|
characterViewModel: CharacterViewModel,
|
||||||
showMenuButton: Boolean,
|
showMenuButton: Boolean,
|
||||||
onMenuClick: () -> Unit,
|
onMenuClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
var isDark by LocalThemeIsDark.current
|
var isDark by LocalThemeIsDark.current
|
||||||
val currentRoute = currentRoute(navController)
|
val currentRoute = currentRoute(navController)
|
||||||
|
val character by characterViewModel.character.collectAsState()
|
||||||
|
|
||||||
val topBarTitle = when (currentRoute) {
|
val topBarTitle = when (currentRoute) {
|
||||||
AppRoutes.CHARACTER_SHEET -> EXAMPLE_CHARACTER.characterData.name
|
AppRoutes.CHARACTER_SHEET -> character.characterData.name
|
||||||
AppRoutes.SETTINGS -> "Settings"
|
AppRoutes.SETTINGS -> "Settings"
|
||||||
else -> "Shadowrun Character Sheet"
|
else -> "Shadowrun Character Sheet"
|
||||||
}
|
}
|
||||||
@@ -301,7 +304,7 @@ private fun MainScaffold(
|
|||||||
.padding(contentPadding)
|
.padding(contentPadding)
|
||||||
) {
|
) {
|
||||||
composable(AppRoutes.CHARACTER_SHEET) {
|
composable(AppRoutes.CHARACTER_SHEET) {
|
||||||
CharacterSheetPage(EXAMPLE_CHARACTER, contentPadding)
|
CharacterSheetPage(character, contentPadding)
|
||||||
}
|
}
|
||||||
composable(AppRoutes.SETTINGS) {
|
composable(AppRoutes.SETTINGS) {
|
||||||
SettingsPage()
|
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