Compare commits

...

3 Commits

Author SHA1 Message Date
efim a87f4f99c0 add display of the name on the open card
to make disambiguation on the viewing round simpler
will style this later
2023-04-28 11:58:48 +04:00
efim d7d4e2be9d bugfix: need to recognize owner after relogin
playerid is not stable right now, need to use nickname
2023-04-28 11:54:51 +04:00
efim 3158a75f5d bugfix: leaving room needs to clear votes 2023-04-28 11:43:59 +04:00
5 changed files with 56 additions and 37 deletions

View File

@ -82,6 +82,6 @@ object Auth {
def make[F[_]: Sync](): F[Auth[F]] =
for {
sessionsMap <- Ref.of[F, SessionsMap](TestModels.testSessions)
sessionsMap <- Ref.of[F, SessionsMap](Map.empty)
} yield new SimpleAuth(sessionsMap)
}

View File

@ -59,7 +59,7 @@ class InMemoryRoomService[F[_]: Concurrent](stateRef: Ref[F, Map[RoomID, (Room,
val newRoom = Room(
roomId,
players = List(ownerPlayer),
owner = ownerPlayer.id,
owner = ownerPlayer.name,
password = roomPassword,
allowedCards = List("XS", "S", "M", "L", "XL"), // TODO accept from front
round = RoundState.Voting(Map.empty),
@ -105,8 +105,8 @@ class InMemoryRoomService[F[_]: Concurrent](stateRef: Ref[F, Map[RoomID, (Room,
roomID,
room =>
room.round match {
case RoundState.Viewing(_) => room
case RoundState.Voting(votes) => room.copy(round = RoundState.Viewing(votes))
case RoundState.Viewing(_) => room
case RoundState.Voting(votes) => room.copy(round = RoundState.Viewing(votes))
}
)
override def startNewPoll(roomID: RoomID, playerID: PlayerID): F[Unit] = updateRoom(
@ -122,7 +122,11 @@ class InMemoryRoomService[F[_]: Concurrent](stateRef: Ref[F, Map[RoomID, (Room,
*/
override def leaveRoom(roomID: RoomID, playerID: PlayerID): F[Unit] = updateRoom(
roomID,
room => room.copy(players = room.players.filterNot(_.id == playerID))
room =>
room.copy(
players = room.players.filterNot(_.id == playerID),
round = room.round.removePlayer(playerID)
)
)
override def deleteRoom(roomID: RoomID): F[Unit] = {
@ -159,7 +163,7 @@ class InMemoryRoomService[F[_]: Concurrent](stateRef: Ref[F, Map[RoomID, (Room,
room.players.find(_.name == nickName) match {
case Some(player) => player.id -> room
case None => // player is not present, but potentially was previously
val addingPlayer = Player.create(nickPassword)
val addingPlayer = Player.create(nickName)
val roomWithPlayer = room.copy(players = addingPlayer :: room.players)
room.playersPasswords.get(nickName) match {
case Some(_) => addingPlayer.id -> roomWithPlayer

View File

@ -59,7 +59,7 @@ object Models {
final case class Room(
id: RoomID,
players: List[Player],
owner: PlayerID, // TODO switch to nickname
owner: String, // TODO switch to nickname
password: String,
allowedCards: List[String],
round: RoundState,
@ -74,7 +74,7 @@ object Models {
me.id,
allowedCards,
round.toViewFor(playerId),
playerId == owner
me.name == owner
)
)
}
@ -83,18 +83,23 @@ object Models {
// no need to send to the front end, no deed to derive codec, cool
sealed trait RoundState {
def toViewFor(player: PlayerID): RoundStateView
def removePlayer(id: PlayerID): RoundState
}
object RoundState {
final case class Voting(votes: Map[PlayerID, String]) extends RoundState {
def toViewFor(playerId: PlayerID): RoundStateView.Voting = RoundStateView.Voting(
override def toViewFor(playerId: PlayerID): RoundStateView.Voting = RoundStateView.Voting(
myCard = votes.get(playerId),
alreadyVoted = votes.filterKeys(id => id != playerId).keys.toList
)
override def removePlayer(id: PlayerID): RoundState.Voting =
RoundState.Voting(votes.filterKeys(_ != id).toMap)
}
final case class Viewing(votes: Map[PlayerID, String]) extends RoundState {
def toViewFor(player: PlayerID): RoundStateView.Viewing =
override def toViewFor(player: PlayerID): RoundStateView.Viewing =
RoundStateView.Viewing(votes.toList)
override def removePlayer(id: PlayerID): RoundState.Viewing =
RoundState.Viewing(votes.filterKeys(_ != id).toMap)
}
}
}

View File

@ -8,21 +8,21 @@ object TestModels {
val birdy = Player("birdy", PlayerID(11))
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(
Map(me.id -> "xs", pony.id -> "l", birdy.id -> "s", horsey.id -> "m")
),
playersPasswords = Map("me" -> "nickpassword") // nickname into password
)
// 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(
// Map(me.id -> "xs", pony.id -> "l", birdy.id -> "s", horsey.id -> "m")
// ),
// playersPasswords = Map("me" -> "nickpassword") // nickname into password
// )
val testSessionId = 1L
val testSessions = Map(testSessionId -> (testRoomBackend.id, me.id))
val testRooms = Map(testRoomBackend.id -> testRoomBackend)
// val testSessionId = 1L
// val testSessions = Map(testSessionId -> (testRoomBackend.id, me.id))
// val testRooms = Map(testRoomBackend.id -> testRoomBackend)
val testChangesList = List(
RoomStateView(

View File

@ -34,8 +34,8 @@ object TableView {
trait CardState
case class NoCard(name: String) extends CardState
case object CardBack extends CardState
case class Open(value: String) extends CardState
case class CardBack(name: String) extends CardState
case class Open(name: String, value: String) extends CardState
def getPlayerCardType(
id: PlayerID,
@ -46,36 +46,46 @@ object TableView {
state match {
case isOpen: RoundStateView.Voting =>
if (myId == id) {
isOpen.myCard.fold(NoCard(name))(vote => Open(vote))
} else isOpen.alreadyVoted.find(_ == id).fold(NoCard(name))(_ => CardBack)
isOpen.myCard.fold(NoCard(name))(vote => Open(name, vote))
} else isOpen.alreadyVoted.find(_ == id).fold(NoCard(name))(_ => CardBack(name))
case isClosed: RoundStateView.Viewing =>
isClosed.votes
.find(_._1 == id)
.fold {
g.console.error(s"missing vote for player $name")
Open("error")
} { case (_, vote) => Open(vote) }
Open(name, "error")
} { case (_, vote) => Open(name, vote) }
}
}
def renderPlayerCard(state: Signal[CardState]): Element = {
val cardTypeStyle = state.map {
case NoCard(_) => "bg-green-100 text-black border-2 border-black"
case CardBack => "bg-green-500 border-4 border-green-700"
case Open(_) => "text-black bg-gray-50 border-black border-2"
case NoCard(_) => "bg-green-100 text-black border-2 border-black"
case CardBack(_) => "bg-green-500 border-4 border-green-700"
case Open(_, _) => "text-black bg-gray-50 border-black border-2"
}
div(
className := "w-20 h-40 m-1 rounded flex justify-center items-center m-3",
className := "w-20 h-40 m-1 rounded flex flex-col justify-center items-center m-3",
className <-- cardTypeStyle,
// the diagonal card value \ place text
div(
className := "-rotate-45 text-xl",
child.text <-- state.map {
case NoCard(name) => name
case CardBack => ""
case Open(vote) => vote
case NoCard(name) => name
case CardBack(name) => name
case Open(_, vote) => vote
}
),
// name under viewing the votes
div(
className := "text-xl",
child.text <-- state.map {
case Open(name, _) => name
case _ => ""
}
)
)
}