Refactor the windows navigation system

This commit is contained in:
Thomas Andres Gomez 2024-11-13 16:36:35 +01:00
parent 5ac0c2dcf6
commit 59f8aff121
20 changed files with 155 additions and 148 deletions

View file

@ -7,80 +7,44 @@ import androidx.compose.material.SnackbarHostState
import androidx.compose.material.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.ApplicationScope
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.rememberWindowState
import com.pixelized.desktop.lwa.navigation.MainNavHost
import com.pixelized.desktop.lwa.navigation.destination.CharacterSheetDestination
import com.pixelized.desktop.lwa.navigation.destination.CharacterSheetEditDestination
import com.pixelized.desktop.lwa.navigation.screen.MainNavHost
import com.pixelized.desktop.lwa.navigation.screen.destination.CharacterSheetDestination
import com.pixelized.desktop.lwa.navigation.screen.destination.CharacterSheetEditDestination
import com.pixelized.desktop.lwa.navigation.window.WindowController
import com.pixelized.desktop.lwa.navigation.window.WindowsNavHost
import com.pixelized.desktop.lwa.navigation.window.destination.CharacterSheetCreateWindow
import com.pixelized.desktop.lwa.navigation.window.destination.CharacterSheetWindow
import com.pixelized.desktop.lwa.screen.characterSheet.CharacterSheetMainNavHost
import com.pixelized.desktop.lwa.screen.main.CharacterUio
import com.pixelized.desktop.lwa.theme.LwaTheme
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__title
import org.jetbrains.compose.resources.stringResource
import org.jetbrains.compose.ui.tooling.preview.Preview
val LocalSnackHost = compositionLocalOf<SnackbarHostState> {
error("Local Snack Controller is not yet ready")
}
val LocalWindowController = compositionLocalOf<WindowController> {
error("Local Window Controller is not yet ready")
}
@Stable
data class WindowController(
private val onCloseRequest: () -> Unit
) {
val sheet: State<Set<CharacterUio>> get() = _sheet
val create: State<Set<Int>> get() = _create
fun showCreateCharacterSheet() {
_create.value = _create.value.toMutableSet().apply { add(size) }
}
fun hideCreateCharacterSheet(id: Int) {
_create.value = _create.value.toMutableSet().apply { remove(id) }
}
fun showCharacterSheet(sheet: CharacterUio) {
_sheet.value = _sheet.value.toMutableSet().apply { add(sheet) }
}
fun hideCharacterSheet(sheet: CharacterUio) {
_sheet.value = _sheet.value.toMutableSet().apply { remove(sheet) }
}
fun closeWindows() = onCloseRequest()
companion object {
private val _sheet = mutableStateOf<Set<CharacterUio>>(emptySet())
private val _create = mutableStateOf<Set<Int>>(emptySet())
}
val LocalSnackHost = compositionLocalOf<SnackbarHostState> {
error("Local Snack Controller is not yet ready")
}
@Composable
@Preview
fun ApplicationScope.App() {
val controller = remember { WindowController(onCloseRequest = ::exitApplication) }
val snackHostState = remember { SnackbarHostState() }
val windowController = remember { WindowController() }
CompositionLocalProvider(
LocalWindowController provides controller,
LocalSnackHost provides snackHostState,
LocalWindowController provides windowController,
) {
Window(
onCloseRequest = {
controller.closeWindows()
},
onCloseRequest = ::exitApplication,
state = rememberWindowState(
width = 320.dp + 64.dp,
height = 900.dp,
@ -101,13 +65,8 @@ fun ApplicationScope.App() {
MainNavHost()
}
)
HandleCharacterSheet(
sheets = controller.sheet,
onCloseRequest = { controller.hideCharacterSheet(sheet = it) }
)
HandleCharacterSheetCreation(
sheets = controller.create,
onCloseRequest = { controller.hideCreateCharacterSheet(id = it) },
WindowsHandler(
windowController = windowController,
)
}
}
@ -116,64 +75,26 @@ fun ApplicationScope.App() {
}
@Composable
fun HandleCharacterSheet(
sheets: State<Set<CharacterUio>>,
onCloseRequest: (id: CharacterUio) -> Unit,
private fun WindowsHandler(
windowController: WindowController
) {
sheets.value.forEach { sheet ->
val controller = remember {
WindowController(
onCloseRequest = { onCloseRequest(sheet) }
)
}
CompositionLocalProvider(
LocalWindowController provides controller,
) {
Window(
onCloseRequest = { onCloseRequest(sheet) },
state = rememberWindowState(
width = 400.dp + 64.dp,
height = 900.dp,
),
title = sheet.name,
) {
CharacterSheetMainNavHost(
startDestination = CharacterSheetDestination.navigationRoute(id = sheet.id)
WindowsNavHost(
controller = windowController,
content = { window ->
when (window) {
is CharacterSheetWindow -> CharacterSheetMainNavHost(
startDestination = CharacterSheetDestination.navigationRoute(
id = window.characterId,
),
)
}
}
}
}
@Composable
fun HandleCharacterSheetCreation(
sheets: State<Set<Int>>,
onCloseRequest: (id: Int) -> Unit,
) {
sheets.value.forEach { sheet ->
val controller = remember {
WindowController(
onCloseRequest = { onCloseRequest(sheet) }
)
}
CompositionLocalProvider(
LocalWindowController provides controller,
) {
Window(
onCloseRequest = { controller.closeWindows() },
state = rememberWindowState(
width = 400.dp + 64.dp,
height = 900.dp,
),
title = stringResource(Res.string.character_sheet_edit__title),
) {
CharacterSheetMainNavHost(
is CharacterSheetCreateWindow -> CharacterSheetMainNavHost(
startDestination = CharacterSheetEditDestination.navigationRoute(
id = null,
enableBack = false,
)
),
)
}
}
}
)
}

View file

@ -1,4 +1,4 @@
package com.pixelized.desktop.lwa.navigation
package com.pixelized.desktop.lwa.navigation.screen
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
@ -6,11 +6,10 @@ import androidx.compose.runtime.compositionLocalOf
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController
import com.pixelized.desktop.lwa.navigation.destination.MainDestination
import com.pixelized.desktop.lwa.navigation.destination.composableMainPage
import com.pixelized.desktop.lwa.navigation.destination.composableNetworkPage
import com.pixelized.desktop.lwa.navigation.destination.composableRollHistory
import com.pixelized.desktop.lwa.screen.main.MainPageViewModel
import com.pixelized.desktop.lwa.navigation.screen.destination.MainDestination
import com.pixelized.desktop.lwa.navigation.screen.destination.composableMainPage
import com.pixelized.desktop.lwa.navigation.screen.destination.composableNetworkPage
import com.pixelized.desktop.lwa.navigation.screen.destination.composableRollHistory
val LocalScreenController = compositionLocalOf<NavHostController> {
error("MainNavHost controller is not yet ready")

View file

@ -1,4 +1,4 @@
package com.pixelized.desktop.lwa.navigation.destination
package com.pixelized.desktop.lwa.navigation.screen.destination
import androidx.lifecycle.SavedStateHandle
import androidx.navigation.NavGraphBuilder

View file

@ -1,4 +1,4 @@
package com.pixelized.desktop.lwa.navigation.destination
package com.pixelized.desktop.lwa.navigation.screen.destination
import androidx.lifecycle.SavedStateHandle
import androidx.navigation.NavGraphBuilder

View file

@ -1,4 +1,4 @@
package com.pixelized.desktop.lwa.navigation.destination
package com.pixelized.desktop.lwa.navigation.screen.destination
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController

View file

@ -1,4 +1,4 @@
package com.pixelized.desktop.lwa.navigation.destination
package com.pixelized.desktop.lwa.navigation.screen.destination
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController

View file

@ -1,4 +1,4 @@
package com.pixelized.desktop.lwa.navigation.destination
package com.pixelized.desktop.lwa.navigation.screen.destination
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController

View file

@ -0,0 +1,56 @@
package com.pixelized.desktop.lwa.navigation.window
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.rememberWindowState
import com.pixelized.desktop.lwa.navigation.window.destination.Window
val LocalWindow = compositionLocalOf<Window> {
error("Local Window is not yet ready")
}
@Stable
class WindowController {
private val _windows = mutableStateOf<Set<Window>>(emptySet())
val windows: State<Set<Window>> get() = _windows
fun showWindow(window: Window) {
_windows.value = _windows.value.toMutableSet().apply { add(window) }
}
fun hideWindow(window: Window) {
hideWindow(id = window.id)
}
fun hideWindow(id: String) {
_windows.value = _windows.value.toMutableSet().apply { removeIf { it.id == id } }
}
}
@Composable
fun WindowsNavHost(
controller: WindowController,
content: @Composable (Window) -> Unit,
) {
controller.windows.value.forEach { window ->
CompositionLocalProvider(
LocalWindow provides window,
) {
Window(
onCloseRequest = { controller.hideWindow(id = window.id) },
state = rememberWindowState(
width = window.width,
height = window.height,
),
title = window.title,
) {
content.invoke(window)
}
}
}
}

View file

@ -0,0 +1,6 @@
package com.pixelized.desktop.lwa.navigation.window.destination
import androidx.compose.runtime.Stable
@Stable
class CharacterSheetCreateWindow : Window(title = "")

View file

@ -0,0 +1,12 @@
package com.pixelized.desktop.lwa.navigation.window.destination
import androidx.compose.runtime.Stable
@Stable
class CharacterSheetWindow(
val characterId: String,
characterName: String,
) : Window(
title = characterName,
)

View file

@ -0,0 +1,14 @@
package com.pixelized.desktop.lwa.navigation.window.destination
import androidx.compose.runtime.Stable
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import java.util.UUID
@Stable
sealed class Window(
val id: String = UUID.randomUUID().toString(),
val title: String,
val width: Dp = 400.dp + 64.dp,
val height: Dp = 900.dp,
)

View file

@ -8,9 +8,9 @@ import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController
import com.pixelized.desktop.lwa.navigation.LocalScreenController
import com.pixelized.desktop.lwa.navigation.destination.composableCharacterSheetEditPage
import com.pixelized.desktop.lwa.navigation.destination.composableCharacterSheetPage
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
import com.pixelized.desktop.lwa.navigation.screen.destination.composableCharacterSheetEditPage
import com.pixelized.desktop.lwa.navigation.screen.destination.composableCharacterSheetPage
@Composable
fun CharacterSheetMainNavHost(

View file

@ -51,8 +51,9 @@ import com.pixelized.desktop.lwa.LocalWindowController
import com.pixelized.desktop.lwa.composable.blur.BlurContent
import com.pixelized.desktop.lwa.composable.blur.BlurContentController
import com.pixelized.desktop.lwa.composable.decoratedBox.DecoratedBox
import com.pixelized.desktop.lwa.navigation.LocalScreenController
import com.pixelized.desktop.lwa.navigation.destination.navigateToCharacterSheetEdit
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
import com.pixelized.desktop.lwa.navigation.screen.destination.navigateToCharacterSheetEdit
import com.pixelized.desktop.lwa.navigation.window.LocalWindow
import com.pixelized.desktop.lwa.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialog
import com.pixelized.desktop.lwa.screen.characterSheet.detail.dialog.CharacterSheetStatDialog
import com.pixelized.desktop.lwa.screen.roll.RollPage
@ -107,7 +108,8 @@ fun CharacterSheetPage(
},
rollViewModel: RollViewModel = viewModel { RollViewModel() },
) {
val window = LocalWindowController.current
val windowController = LocalWindowController.current
val window = LocalWindow.current
val screen = LocalScreenController.current
val scope = rememberCoroutineScope()
val blurController = remember { BlurContentController() }
@ -189,7 +191,7 @@ fun CharacterSheetPage(
scope.launch {
viewModel.deleteCharacter(id = it.id)
if (screen.popBackStack().not()) {
window.closeWindows()
windowController.hideWindow(window = window)
}
}
},

View file

@ -8,7 +8,7 @@ import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import com.pixelized.desktop.lwa.navigation.destination.CharacterSheetDestination
import com.pixelized.desktop.lwa.navigation.screen.destination.CharacterSheetDestination
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialogUio
import com.pixelized.desktop.lwa.screen.characterSheet.detail.dialog.StatChangeDialogUio

View file

@ -32,7 +32,8 @@ import androidx.lifecycle.createSavedStateHandle
import androidx.lifecycle.viewmodel.compose.viewModel
import com.pixelized.desktop.lwa.LocalWindowController
import com.pixelized.desktop.lwa.composable.decoratedBox.DecoratedBox
import com.pixelized.desktop.lwa.navigation.LocalScreenController
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
import com.pixelized.desktop.lwa.navigation.window.LocalWindow
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.FieldUio
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.Form
import kotlinx.coroutines.launch
@ -77,7 +78,8 @@ fun CharacterSheetEditPage(
)
},
) {
val window = LocalWindowController.current
val windowController = LocalWindowController.current
val window = LocalWindow.current
val screen = LocalScreenController.current
val scope = rememberCoroutineScope()
@ -99,7 +101,7 @@ fun CharacterSheetEditPage(
scope.launch {
viewModel.save()
if (screen.popBackStack().not()) {
window.closeWindows()
windowController.hideWindow(window = window)
}
}
},

View file

@ -4,7 +4,7 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import com.pixelized.desktop.lwa.navigation.destination.CharacterSheetEditDestination
import com.pixelized.desktop.lwa.navigation.screen.destination.CharacterSheetEditDestination
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.screen.characterSheet.edit.CharacterSheetEditPageUio.SkillGroup
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.FieldUio

View file

@ -12,28 +12,21 @@ import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Stable
import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.rememberWindowState
import androidx.lifecycle.viewmodel.compose.viewModel
import com.pixelized.desktop.lwa.LocalWindowController
import com.pixelized.desktop.lwa.WindowController
import com.pixelized.desktop.lwa.navigation.LocalScreenController
import com.pixelized.desktop.lwa.navigation.destination.CharacterSheetDestination
import com.pixelized.desktop.lwa.navigation.destination.CharacterSheetEditDestination
import com.pixelized.desktop.lwa.navigation.destination.navigateToNetwork
import com.pixelized.desktop.lwa.navigation.destination.navigateToRollHistory
import com.pixelized.desktop.lwa.screen.characterSheet.CharacterSheetMainNavHost
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
import com.pixelized.desktop.lwa.navigation.screen.destination.navigateToNetwork
import com.pixelized.desktop.lwa.navigation.screen.destination.navigateToRollHistory
import com.pixelized.desktop.lwa.navigation.window.destination.CharacterSheetCreateWindow
import com.pixelized.desktop.lwa.navigation.window.destination.CharacterSheetWindow
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__title
import lwacharactersheet.composeapp.generated.resources.main_page__create_action
import lwacharactersheet.composeapp.generated.resources.main_page__network_action
import lwacharactersheet.composeapp.generated.resources.main_page__roll_history_action
@ -65,10 +58,15 @@ fun MainPage(
MainPageContent(
characters = viewModel.characters,
onCharacter = {
window.showCharacterSheet(sheet = it)
window.showWindow(
window = CharacterSheetWindow(
characterId = it.id,
characterName = it.name,
)
)
},
onCreateCharacter = {
window.showCreateCharacterSheet()
window.showWindow(window = CharacterSheetCreateWindow())
},
onRollHistory = {
screen.navigateToRollHistory()

View file

@ -29,7 +29,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.pixelized.desktop.lwa.navigation.LocalScreenController
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.network__host__label
import lwacharactersheet.composeapp.generated.resources.network__player_name__label

View file

@ -21,7 +21,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.pixelized.desktop.lwa.navigation.LocalScreenController
import com.pixelized.desktop.lwa.navigation.screen.LocalScreenController
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.roll_history__title
import org.jetbrains.compose.resources.stringResource

View file

@ -4,9 +4,6 @@ import androidx.compose.ui.window.application
import com.pixelized.desktop.lwa.business.SkillStepUseCase
fun main() {
SkillStepUseCase.exportTest()
application {
App()
}