From ed6d30ec42d580c05b231c0ed8bcf9d63984d913 Mon Sep 17 00:00:00 2001 From: efim Date: Thu, 27 Apr 2023 22:15:13 +0400 Subject: [PATCH] models: separate backend room model not viewable on front end, since doesn't have json codecs, yay! --- .../sunshine/planningpoker/Models.scala | 53 +++++++++---------- .../sunshine/planningpoker/TestModels.scala | 39 +++++++------- .../planningpoker/OwnHandControls.scala | 4 +- .../planningpoker/TableControls.scala | 10 ++-- .../sunshine/planningpoker/TableView.scala | 8 +-- 5 files changed, 55 insertions(+), 59 deletions(-) diff --git a/common/src/main/scala/industries/sunshine/planningpoker/Models.scala b/common/src/main/scala/industries/sunshine/planningpoker/Models.scala index f8d47f0..f509bf5 100644 --- a/common/src/main/scala/industries/sunshine/planningpoker/Models.scala +++ b/common/src/main/scala/industries/sunshine/planningpoker/Models.scala @@ -20,30 +20,27 @@ object Models { players: List[Player], me: PlayerID, allowedCards: List[String], - round: RoundState, + round: RoundStateView, canCloseRound: Boolean = false - ) derives Codec.AsObject { - def playersCount: Int = players.size - } + ) derives Codec.AsObject object RoomStateView { val empty = RoomStateView( List.empty, PlayerID(0), List.empty, - RoundState.Voting(None, List.empty), + RoundStateView.Voting(None, List.empty), false ) } - enum RoundState derives Codec.AsObject: - + enum RoundStateView derives Codec.AsObject: /** view state for round before votes are open player can know their vote and who of the other * players have voted */ case Voting( myCard: Option[String], - alreadyVoted: List[Player] + alreadyVoted: List[PlayerID] ) /** view state for round after opening the votes @@ -51,15 +48,14 @@ object Models { case Viewing( votes: List[(PlayerID, String)] ) - final case class PlayerID(id: Long) derives Codec.AsObject + final case class PlayerID(id: Long) derives Codec.AsObject final case class Player(name: String, id: PlayerID) derives Codec.AsObject object Player { def create(name: String) = Player(name, PlayerID(Random.nextLong)) } final case class RoomID(name: String) derives Codec.AsObject - final case class Room( id: RoomID, players: List[Player], @@ -69,7 +65,7 @@ object Models { round: RoundState, playersPasswords: Map[String, String] = Map.empty // nickname into password ) { - def toViewFor(playerId: PlayerID): RoomStateView = { + def getViewFor(playerId: PlayerID): RoomStateView = { players .find(_.id == playerId) .fold(ifEmpty = RoomStateView.empty)((me: Player) => @@ -77,27 +73,28 @@ object Models { players, me.id, allowedCards, - round, + round.toViewFor(playerId), playerId == owner ) ) } } - object Room { - val testRoom = Room( - id = RoomID("testroom"), - players = List( - Player("me", PlayerID(1L)), - Player("horsey", PlayerID(444L)), - Player("froggy", PlayerID(555L)), - Player("owley", PlayerID(777L)) - ), - owner = PlayerID(1L), - password = "password", - allowedCards = List("S", "M", "L"), - // TODO - this needs to be a different hting - round = RoundState.Voting(None, List.empty) - ) - } + // no need to send to the front end, no deed to derive codec, cool + sealed trait RoundState { + def toViewFor(player: PlayerID): RoundStateView + } + object RoundState { + final case class Voting(votes: Map[PlayerID, String]) extends RoundState { + def toViewFor(playerId: PlayerID): RoundStateView.Voting = RoundStateView.Voting( + myCard = votes.get(playerId), + alreadyVoted = votes.filterKeys(id => id != playerId).keys.toList + ) + } + + final case class Viewing(votes: Map[PlayerID, String]) extends RoundState { + def toViewFor(player: PlayerID): RoundStateView.Viewing = + RoundStateView.Viewing(votes.toList) + } + } } diff --git a/common/src/main/scala/industries/sunshine/planningpoker/TestModels.scala b/common/src/main/scala/industries/sunshine/planningpoker/TestModels.scala index ff93582..3b788ae 100644 --- a/common/src/main/scala/industries/sunshine/planningpoker/TestModels.scala +++ b/common/src/main/scala/industries/sunshine/planningpoker/TestModels.scala @@ -9,15 +9,15 @@ object TestModels { val horsey = Player("horsey", PlayerID(12)) val testRoomBackend = Room( - id = RoomID("testroom"), - players = List(me, birdy, pony, horsey), - owner = me.id, - password = "password", - allowedCards = List("xs", "s", "m", "l", "xl"), - round = RoundState.Viewing( - List(me.id -> "xs", pony.id -> "l", birdy.id -> "s", horsey.id -> "m") - ), - playersPasswords = Map("me" -> "nickpassword") // nickname into password + id = RoomID("testroom"), + players = List(me, birdy, pony, horsey), + owner = me.id, + password = "password", + allowedCards = List("xs", "s", "m", "l", "xl"), + round = RoundState.Viewing( + Map(me.id -> "xs", pony.id -> "l", birdy.id -> "s", horsey.id -> "m") + ), + playersPasswords = Map("me" -> "nickpassword") // nickname into password ) val testSessionId = 1L @@ -29,70 +29,71 @@ object TestModels { players = List(me), me = me.id, allowedCards = List("xs", "s", "m", "l", "xl"), - round = RoundState.Voting(myCard = None, alreadyVoted = List.empty), + round = RoundStateView.Voting(myCard = None, alreadyVoted = List.empty), canCloseRound = true ), RoomStateView( players = List(me, pony), me = me.id, allowedCards = List("xs", "s", "m", "l", "xl"), - round = RoundState.Voting(myCard = None, alreadyVoted = List.empty), + round = RoundStateView.Voting(myCard = None, alreadyVoted = List.empty), canCloseRound = true ), RoomStateView( players = List(me, birdy, pony), me = me.id, allowedCards = List("xs", "s", "m", "l", "xl"), - round = RoundState.Voting(myCard = None, alreadyVoted = List.empty), + round = RoundStateView.Voting(myCard = None, alreadyVoted = List.empty), canCloseRound = true ), RoomStateView( players = List(me, birdy, pony), me = me.id, allowedCards = List("xs", "s", "m", "l", "xl"), - round = RoundState.Voting(myCard = None, alreadyVoted = List(birdy)), + round = RoundStateView.Voting(myCard = None, alreadyVoted = List(birdy.id)), canCloseRound = true ), RoomStateView( players = List(me, birdy, pony), me = me.id, allowedCards = List("xs", "s", "m", "l", "xl"), - round = RoundState.Voting(myCard = Some("m"), alreadyVoted = List(birdy)), + round = RoundStateView.Voting(myCard = Some("m"), alreadyVoted = List(birdy.id)), canCloseRound = true ), RoomStateView( players = List(me, birdy, pony), me = me.id, allowedCards = List("xs", "s", "m", "l", "xl"), - round = RoundState.Voting(myCard = Some("m"), alreadyVoted = List(birdy)), + round = RoundStateView.Voting(myCard = Some("m"), alreadyVoted = List(birdy.id)), canCloseRound = true ), RoomStateView( players = List(me, birdy, pony, horsey), me = me.id, allowedCards = List("xs", "s", "m", "l", "xl"), - round = RoundState.Voting(myCard = Some("m"), alreadyVoted = List(birdy)), + round = RoundStateView.Voting(myCard = Some("m"), alreadyVoted = List(birdy.id)), canCloseRound = true ), RoomStateView( players = List(me, birdy, pony, horsey), me = me.id, allowedCards = List("xs", "s", "m", "l", "xl"), - round = RoundState.Voting(myCard = Some("m"), alreadyVoted = List(birdy, horsey)), + round = RoundStateView.Voting(myCard = Some("m"), alreadyVoted = List(birdy.id, horsey.id)), canCloseRound = true ), RoomStateView( players = List(me, birdy, pony, horsey), me = me.id, allowedCards = List("xs", "s", "m", "l", "xl"), - round = RoundState.Voting(myCard = Some("m"), alreadyVoted = List(birdy, horsey, pony)), + round = RoundStateView + .Voting(myCard = Some("m"), alreadyVoted = List(birdy.id, horsey.id, pony.id)), canCloseRound = true ), RoomStateView( players = List(me, birdy, pony, horsey), me = me.id, allowedCards = List("xs", "s", "m", "l", "xl"), - round = RoundState.Viewing( + round = RoundStateView.Viewing( List(me.id -> "m", pony.id -> "l", birdy.id -> "s", horsey.id -> "m") ), canCloseRound = true diff --git a/frontend/src/main/scala/industries/sunshine/planningpoker/OwnHandControls.scala b/frontend/src/main/scala/industries/sunshine/planningpoker/OwnHandControls.scala index d1c30cf..f336951 100644 --- a/frontend/src/main/scala/industries/sunshine/planningpoker/OwnHandControls.scala +++ b/frontend/src/main/scala/industries/sunshine/planningpoker/OwnHandControls.scala @@ -32,9 +32,9 @@ object OwnHandControls { private def myUnselectedCards(state: RoomStateView): List[String] = { state.round match { - case RoundState.Voting(myCard, _) => + case RoundStateView.Voting(myCard, _) => state.allowedCards.filterNot(value => myCard.contains(value)) - case RoundState.Viewing(votes) => + case RoundStateView.Viewing(votes) => state.allowedCards.filterNot(value => votes.toMap.get(state.me).contains(value)) } } diff --git a/frontend/src/main/scala/industries/sunshine/planningpoker/TableControls.scala b/frontend/src/main/scala/industries/sunshine/planningpoker/TableControls.scala index b6e973e..e568d8a 100644 --- a/frontend/src/main/scala/industries/sunshine/planningpoker/TableControls.scala +++ b/frontend/src/main/scala/industries/sunshine/planningpoker/TableControls.scala @@ -2,21 +2,19 @@ package industries.sunshine.planningpoker import scala.scalajs.js import com.raquo.laminar.api.L.{*, given} -import industries.sunshine.planningpoker.common.Models.RoundState +import industries.sunshine.planningpoker.common.Models.RoundStateView import com.raquo.airstream.core.Signal -import industries.sunshine.planningpoker.common.Models.RoundState -import industries.sunshine.planningpoker.common.Models.RoundState import io.laminext.fetch.Fetch import scala.scalajs.js.Dynamic.{global => g} import concurrent.ExecutionContext.Implicits.global object TableControls { - def render(roundSignal: Signal[RoundState]): Element = { + def render(roundSignal: Signal[RoundStateView]): Element = { div( child <-- roundSignal.map { - case RoundState.Viewing(_) => newPollButton() - case RoundState.Voting(_, _) => endPollButton() + case RoundStateView.Viewing(_) => newPollButton() + case RoundStateView.Voting(_, _) => endPollButton() } ) } diff --git a/frontend/src/main/scala/industries/sunshine/planningpoker/TableView.scala b/frontend/src/main/scala/industries/sunshine/planningpoker/TableView.scala index eff68a9..49507ef 100644 --- a/frontend/src/main/scala/industries/sunshine/planningpoker/TableView.scala +++ b/frontend/src/main/scala/industries/sunshine/planningpoker/TableView.scala @@ -39,16 +39,16 @@ object TableView { def getPlayerCardType( id: PlayerID, - state: RoundState, + state: RoundStateView, name: String, myId: PlayerID ): CardState = { state match { - case isOpen: RoundState.Voting => + case isOpen: RoundStateView.Voting => if (myId == id) { isOpen.myCard.fold(NoCard(name))(vote => Open(vote)) - } else isOpen.alreadyVoted.find(_.id == id).fold(NoCard(name))(_ => CardBack) - case isClosed: RoundState.Viewing => + } else isOpen.alreadyVoted.find(_ == id).fold(NoCard(name))(_ => CardBack) + case isClosed: RoundStateView.Viewing => isClosed.votes .find(_._1 == id) .fold {