From 57a6e5135ee554079c6064bd770d51545800969d Mon Sep 17 00:00:00 2001 From: Joffrey Bion Date: Sun, 29 Mar 2020 18:02:47 +0200 Subject: Fix duplicated inconsistent state --- .../ui/components/gameBrowser/GameBrowser.kt | 2 +- .../ui/components/gameBrowser/GameList.kt | 104 +++++++++++---------- .../ui/components/gameBrowser/PlayerInfo.kt | 8 +- .../sevenwonders/ui/components/lobby/Lobby.kt | 7 +- .../ui/components/lobby/RadialPlayerList.kt | 20 ++-- .../org/luxons/sevenwonders/ui/redux/Actions.kt | 4 +- .../org/luxons/sevenwonders/ui/redux/Reducers.kt | 9 +- 7 files changed, 80 insertions(+), 74 deletions(-) (limited to 'sw-ui-kt/src/main/kotlin/org') diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt index fc7e12d5..2f860ca7 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameBrowser.kt @@ -6,5 +6,5 @@ import react.dom.* fun RBuilder.gameBrowser() = div { h1 { +"Games" } createGameForm {} - gameList {} + gameList() } diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt index 19cd961f..47c17da1 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/GameList.kt @@ -15,6 +15,7 @@ import kotlinx.css.flexDirection import kotlinx.css.verticalAlign import kotlinx.html.classes import kotlinx.html.title +import org.luxons.sevenwonders.model.api.ConnectedPlayer import org.luxons.sevenwonders.model.api.LobbyDTO import org.luxons.sevenwonders.model.api.State import org.luxons.sevenwonders.ui.redux.RequestJoinGame @@ -30,6 +31,7 @@ import styled.styledSpan import styled.styledTr interface GameListStateProps : RProps { + var connectedPlayer: ConnectedPlayer var games: List } @@ -56,69 +58,73 @@ class GameListPresenter(props: GameListProps) : RComponent Unit) = styledTr { - css { - verticalAlign = VerticalAlign.middle + private fun RBuilder.gameListHeaderRow() = tr { + th { +"Name" } + th { +"Status" } + th { +"Nb Players" } + th { +"Join" } } - attrs { - key = lobby.id.toString() - } - td { +lobby.name } - td { gameStatus(lobby.state) } - td { playerCount(lobby.players.size) } - td { joinButton(lobby, joinGame) } -} -private fun RBuilder.gameStatus(state: State) { - val intent = when(state) { - State.LOBBY -> Intent.SUCCESS - State.PLAYING -> Intent.WARNING - State.FINISHED -> Intent.DANGER - } - bpTag(minimal = true, intent = intent) { - +state.toString() - } -} - -private fun RBuilder.playerCount(nPlayers: Int) { - styledDiv { + private fun RBuilder.gameListItemRow(lobby: LobbyDTO, joinGame: (Long) -> Unit) = styledTr { css { - display = Display.flex - flexDirection = FlexDirection.row - alignItems = Align.center + verticalAlign = VerticalAlign.middle } attrs { - title = "Number of players" + key = lobby.id.toString() + } + td { +lobby.name } + td { gameStatus(lobby.state) } + td { playerCount(lobby.players.size) } + td { joinButton(lobby) } + } + + private fun RBuilder.gameStatus(state: State) { + val intent = when(state) { + State.LOBBY -> Intent.SUCCESS + State.PLAYING -> Intent.WARNING + State.FINISHED -> Intent.DANGER } - bpIcon(name = "people", title = null) - styledSpan { - +nPlayers.toString() + bpTag(minimal = true, intent = intent) { + +state.toString() } } -} -private fun RBuilder.joinButton(lobby: LobbyDTO, joinGame: (Long) -> Unit) { - bpButton( - minimal = true, - title = lobby.joinAction.tooltip, - icon = "arrow-right", - disabled = !lobby.joinAction.canDo, - onClick = { joinGame(lobby.id) } - ) + private fun RBuilder.playerCount(nPlayers: Int) { + styledDiv { + css { + display = Display.flex + flexDirection = FlexDirection.row + alignItems = Align.center + } + attrs { + title = "Number of players" + } + bpIcon(name = "people", title = null) + styledSpan { + +nPlayers.toString() + } + } + } + + private fun RBuilder.joinButton(lobby: LobbyDTO) { + val joinability = lobby.joinability(props.connectedPlayer.displayName) + bpButton( + minimal = true, + title = joinability.tooltip, + icon = "arrow-right", + disabled = !joinability.canDo, + onClick = { props.joinGame(lobby.id) } + ) + } } -val gameList = connectStateAndDispatch( +fun RBuilder.gameList() = gameList {} + +private val gameList = connectStateAndDispatch( clazz = GameListPresenter::class, mapStateToProps = { state, _ -> + connectedPlayer = state.connectedPlayer ?: error("there should be a connected player") games = state.games }, mapDispatchToProps = { dispatch, _ -> diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt index 222d4329..b939dfe1 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/gameBrowser/PlayerInfo.kt @@ -1,6 +1,6 @@ package org.luxons.sevenwonders.ui.components.gameBrowser -import org.luxons.sevenwonders.model.api.PlayerDTO +import org.luxons.sevenwonders.model.api.ConnectedPlayer import org.luxons.sevenwonders.ui.redux.connectState import react.RBuilder import react.RComponent @@ -9,7 +9,7 @@ import react.RState import react.dom.* interface PlayerInfoProps : RProps { - var currentPlayer: PlayerDTO? + var connectedPlayer: ConnectedPlayer? } class PlayerInfoPresenter(props: PlayerInfoProps) : RComponent(props) { @@ -19,7 +19,7 @@ class PlayerInfoPresenter(props: PlayerInfoProps) : RComponent - currentPlayer = state.currentPlayer + connectedPlayer = state.connectedPlayer } ) diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/Lobby.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/Lobby.kt index 45c9ca11..5b13d8b1 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/Lobby.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/Lobby.kt @@ -34,14 +34,15 @@ class LobbyPresenter(props: LobbyProps) : RComponent(props) } div { h2 { +"${currentGame.name} — Lobby" } - radialPlayerList(currentGame.players) + radialPlayerList(currentGame.players, currentPlayer) if (currentPlayer.isGameOwner) { + val startability = currentGame.startability(currentPlayer.username) bpButton( large = true, intent = Intent.PRIMARY, icon = "play", - title = currentGame.startAction.tooltip, - disabled = !currentGame.startAction.canDo, + title = startability.tooltip, + disabled = !startability.canDo, onClick = { props.startGame() } ) { + "START" diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt index 364a0dde..ff541696 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/components/lobby/RadialPlayerList.kt @@ -19,11 +19,11 @@ import styled.css import styled.styledDiv import styled.styledH5 -fun RBuilder.radialPlayerList(players: List): ReactElement { +fun RBuilder.radialPlayerList(players: List, currentPlayer: PlayerDTO): ReactElement { val playerItemBuilders = players .growTo(targetSize = 3) - .withUserFirst() - .map { p -> p.elementBuilder() } + .withUserFirst(currentPlayer) + .map { p -> p.elementBuilder(p?.username == currentPlayer.username) } val tableImgBuilder: ElementBuilder = { roundTableImg() } @@ -48,35 +48,33 @@ private fun RBuilder.roundTableImg(): ReactElement = img { } } -private fun List.withUserFirst(): List { - val nonUsersBeginning = takeWhile { !it.isMe } +private fun List.withUserFirst(me: PlayerDTO): List { + val nonUsersBeginning = takeWhile { it?.username != me.username } val userToEnd = subList(nonUsersBeginning.size, size) return userToEnd + nonUsersBeginning } -private val PlayerDTO?.isMe: Boolean get() = this?.isMe ?: false - private fun List.growTo(targetSize: Int): List { if (size >= targetSize) return this return this + List(targetSize - size) { null } } -private fun PlayerDTO?.elementBuilder(): ElementBuilder { +private fun PlayerDTO?.elementBuilder(isMe: Boolean): ElementBuilder { if (this == null) { return { playerPlaceholder() } } else { - return { playerItem(this@elementBuilder) } + return { playerItem(this@elementBuilder, isMe) } } } -private fun RBuilder.playerItem(player: PlayerDTO): ReactElement = styledDiv { +private fun RBuilder.playerItem(player: PlayerDTO, isMe: Boolean): ReactElement = styledDiv { css { display = Display.flex flexDirection = FlexDirection.column alignItems = Align.center } val title = if (player.isGameOwner) "Game owner" else null - userIcon(isMe = player.isMe, isOwner = player.isGameOwner, title = title) + userIcon(isMe = isMe, isOwner = player.isGameOwner, title = title) styledH5 { css { margin = "0" diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt index 63fc26eb..4947fa9b 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Actions.kt @@ -1,12 +1,12 @@ package org.luxons.sevenwonders.ui.redux import org.luxons.sevenwonders.model.PlayerTurnInfo +import org.luxons.sevenwonders.model.api.ConnectedPlayer import org.luxons.sevenwonders.model.api.LobbyDTO -import org.luxons.sevenwonders.model.api.PlayerDTO import org.luxons.sevenwonders.model.cards.PreparedCard import redux.RAction -data class SetCurrentPlayerAction(val player: PlayerDTO): RAction +data class SetCurrentPlayerAction(val player: ConnectedPlayer): RAction data class UpdateGameListAction(val games: List): RAction diff --git a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt index f2a20cef..18d34d78 100644 --- a/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt +++ b/sw-ui-kt/src/main/kotlin/org/luxons/sevenwonders/ui/redux/Reducers.kt @@ -1,25 +1,26 @@ package org.luxons.sevenwonders.ui.redux import org.luxons.sevenwonders.model.PlayerTurnInfo +import org.luxons.sevenwonders.model.api.ConnectedPlayer import org.luxons.sevenwonders.model.api.LobbyDTO import org.luxons.sevenwonders.model.api.PlayerDTO import org.luxons.sevenwonders.model.api.State import redux.RAction data class SwState( - val currentPlayer: PlayerDTO? = null, + val connectedPlayer: ConnectedPlayer? = null, // they must be by ID to support updates to a sublist val gamesById: Map = emptyMap(), - val currentPlayerUsername: String? = null, val currentLobby: LobbyDTO? = null, val currentTurnInfo: PlayerTurnInfo? = null ) { + val currentPlayer: PlayerDTO? = currentLobby?.players?.first { it.username == connectedPlayer?.username } val games: List = gamesById.values.toList() } fun rootReducer(state: SwState, action: RAction): SwState = state.copy( gamesById = gamesReducer(state.gamesById, action), - currentPlayer = currentPlayerReducer(state.currentPlayer, action), + connectedPlayer = currentPlayerReducer(state.connectedPlayer, action), currentLobby = currentLobbyReducer(state.currentLobby, action), currentTurnInfo = currentTurnInfoReducer(state.currentTurnInfo, action) ) @@ -29,7 +30,7 @@ private fun gamesReducer(games: Map, action: RAction): Map games } -private fun currentPlayerReducer(currentPlayer: PlayerDTO?, action: RAction): PlayerDTO? = when (action) { +private fun currentPlayerReducer(currentPlayer: ConnectedPlayer?, action: RAction): ConnectedPlayer? = when (action) { is SetCurrentPlayerAction -> action.player else -> currentPlayer } -- cgit