Add ownership for configuration.
This commit is contained in:
@@ -12,6 +12,7 @@ import massivedecks.exceptions._
|
||||
import massivedecks.models.Errors
|
||||
import massivedecks.models.Game.Formatters._
|
||||
import massivedecks.models.Lobby.Formatters._
|
||||
import massivedecks.models.Lobby.GameCodeAndSecret
|
||||
import massivedecks.models.Player
|
||||
import massivedecks.models.Player.Formatters._
|
||||
import massivedecks.stores.LobbyStore
|
||||
@@ -19,11 +20,12 @@ import play.api.libs.streams.Streams
|
||||
|
||||
class API @Inject()(store: LobbyStore) (implicit context: ExecutionContext) extends Controller {
|
||||
|
||||
def createLobby() = Action {
|
||||
def createLobby() = Action(parse.json) { request: Request[JsValue] =>
|
||||
wrap {
|
||||
val gameCode = store.newLobby()
|
||||
val name = (request.body \ "name").validate[String].getOrElse(throw BadRequestException(Errors.InvalidName()))
|
||||
val gameCode = store.newLobby(name)
|
||||
store.performInLobby(gameCode) { lobby =>
|
||||
Json.toJson(lobby.lobby)
|
||||
Json.toJson(GameCodeAndSecret(lobby.gameCode, lobby.owner))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
package massivedecks.lobby
|
||||
|
||||
import massivedecks.models.Game.{Config => ConfigModel}
|
||||
import massivedecks.notifications.Notifiers
|
||||
import massivedecks.models.cardcast.CardcastDeck
|
||||
import massivedecks.notifications.Notifiers
|
||||
|
||||
class Config(notifiers: Notifiers) {
|
||||
|
||||
var decks: List[CardcastDeck] = List()
|
||||
var houseRules: Set[String] = Set()
|
||||
var password: Option[String] = None
|
||||
|
||||
def config = ConfigModel(decks.map(deck => deck.info), houseRules)
|
||||
def config = ConfigModel(decks.map(deck => deck.info), houseRules, password)
|
||||
|
||||
def addDeck(deck: CardcastDeck): Unit = {
|
||||
decks = decks :+ deck
|
||||
@@ -26,4 +27,13 @@ class Config(notifiers: Notifiers) {
|
||||
notifiers.configChange(config)
|
||||
}
|
||||
|
||||
def setPassword(newPass: Option[String]) = {
|
||||
if (newPass.forall(pw => pw.isEmpty)) {
|
||||
password = None
|
||||
} else {
|
||||
password = newPass
|
||||
}
|
||||
notifiers.configChange(config)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ object Lobby {
|
||||
* Factory for dependency injection.
|
||||
*/
|
||||
class Factory @Inject() (cardcast: CardcastAPI) (implicit context: ExecutionContext) {
|
||||
def build(gameCode: String) = new Lobby(cardcast, gameCode)
|
||||
def build(gameCode: String, ownerName: String) = new Lobby(cardcast, gameCode, ownerName)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -40,7 +40,7 @@ object Lobby {
|
||||
* @param cardcast The cardcast api.
|
||||
* @param gameCode The game code for the lobby.
|
||||
*/
|
||||
class Lobby(cardcast: CardcastAPI, val gameCode: String)(implicit context: ExecutionContext) {
|
||||
class Lobby(cardcast: CardcastAPI, val gameCode: String, ownerName: String)(implicit context: ExecutionContext) {
|
||||
|
||||
/**
|
||||
* The game in progress if there is one.
|
||||
@@ -67,10 +67,12 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String)(implicit context: Execu
|
||||
case Some(g) => GameModel.State.Playing(g.round)
|
||||
}
|
||||
|
||||
val owner = newPlayer(ownerName)
|
||||
|
||||
/**
|
||||
* @return The model for the lobby.
|
||||
*/
|
||||
def lobby = LobbyModel.Lobby(gameCode, config.config, players.players, gameState)
|
||||
def lobby = LobbyModel.Lobby(gameCode, owner.id, config.config, players.players, gameState)
|
||||
|
||||
/**
|
||||
* Add a new player to the lobby.
|
||||
@@ -95,10 +97,12 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String)(implicit context: Execu
|
||||
* @param playCode The cardcast play code for the deck.
|
||||
* @return An empty response.
|
||||
* @throws ForbiddenException with key "secret-wrong-or-not-a-player" if the secret is invalid.
|
||||
* @throws ForbiddenException with key "secret-wrong-or-not-a-player" if the secret is invalid.
|
||||
* @throws RequestFailedException with the key "cardcast-timeout" if the request to cardcast doesn't complete.
|
||||
*/
|
||||
def addDeck(secret: Player.Secret, playCode: String): JsValue = {
|
||||
players.validateSecret(secret)
|
||||
validateIsOwner(secret)
|
||||
Try(Await.ready({
|
||||
cardcast.deck(playCode).map { deck =>
|
||||
config.addDeck(deck)
|
||||
@@ -117,9 +121,11 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String)(implicit context: Execu
|
||||
*
|
||||
* @param secret The secret of the player making the request.
|
||||
* @throws ForbiddenException with key "secret-wrong-or-not-a-player" if the secret is invalid.
|
||||
* @throws ForbiddenException with key "not-owner" if the requester is not the owner.
|
||||
*/
|
||||
def newAi(secret: Player.Secret): Unit = {
|
||||
players.validateSecret(secret)
|
||||
validateIsOwner(secret)
|
||||
players.addAi()
|
||||
}
|
||||
|
||||
@@ -318,9 +324,12 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String)(implicit context: Execu
|
||||
* @param secret The secret of the player making the request.
|
||||
* @param rule The rule to enable.
|
||||
* @return An empty response.
|
||||
* @throws ForbiddenException with key "secret-wrong-or-not-a-player" if the secret is invalid.
|
||||
* @throws ForbiddenException with key "not-owner" if the requester is not the owner.
|
||||
*/
|
||||
def enableRule(secret: Player.Secret, rule: String): JsValue = {
|
||||
players.validateSecret(secret)
|
||||
validateIsOwner(secret)
|
||||
config.addHouseRule(rule)
|
||||
Json.toJson("")
|
||||
}
|
||||
@@ -331,9 +340,12 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String)(implicit context: Execu
|
||||
* @param secret The secret of the player making the request.
|
||||
* @param rule The rule to disable.
|
||||
* @return An empty response.
|
||||
* @throws ForbiddenException with key "secret-wrong-or-not-a-player" if the secret is invalid.
|
||||
* @throws ForbiddenException with key "not-owner" if the requester is not the owner.
|
||||
*/
|
||||
def disableRule(secret: Player.Secret, rule: String): JsValue = {
|
||||
players.validateSecret(secret)
|
||||
validateIsOwner(secret)
|
||||
config.removeHouseRule(rule)
|
||||
Json.toJson("")
|
||||
}
|
||||
@@ -377,4 +389,8 @@ class Lobby(cardcast: CardcastAPI, val gameCode: String)(implicit context: Execu
|
||||
case None => throw BadRequestException(Errors.NoGameInProgress())
|
||||
}
|
||||
|
||||
private def validateIsOwner(secret: Player.Secret) = {
|
||||
ForbiddenException.verify(owner == secret, Errors.NotOwner())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,11 +26,6 @@ class Players(notifiers: Notifiers) {
|
||||
*/
|
||||
var connected: Set[Player.Id] = Set()
|
||||
|
||||
/**
|
||||
* The owner of (first player in) the lobby.
|
||||
*/
|
||||
var owner: Option[Player.Id] = None
|
||||
|
||||
private var secrets: Map[Player.Id, Player.Secret] = Map()
|
||||
private var nextId: Int = 0
|
||||
private var aiNames: List[String] = Players.aiName :: Random.shuffle(Players.aiNames)
|
||||
@@ -55,9 +50,6 @@ class Players(notifiers: Notifiers) {
|
||||
def addPlayer(name: String): Player.Secret = {
|
||||
BadRequestException.verify(players.forall(player => player.name != name), Errors.NameInUse())
|
||||
val id = newId()
|
||||
if (owner.isEmpty) {
|
||||
owner = Some(id)
|
||||
}
|
||||
val player = Player(id, name)
|
||||
players = players :+ player
|
||||
val secret = Player.Secret(id)
|
||||
|
||||
@@ -63,4 +63,6 @@ object Errors {
|
||||
).toString()
|
||||
}
|
||||
case class DeckNotFound(error: String = "deck-not-found") extends SimpleErrorDetails
|
||||
case class NotOwner(error: String = "not-owner") extends SimpleErrorDetails
|
||||
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ object Game {
|
||||
|
||||
case class DeckInfo(id: String, name: String, calls: Int, responses: Int)
|
||||
|
||||
case class Config(decks: List[DeckInfo], houseRules: Set[String])
|
||||
case class Config(decks: List[DeckInfo], houseRules: Set[String], password: Option[String])
|
||||
|
||||
sealed trait State {
|
||||
def gameState: String
|
||||
|
||||
@@ -9,13 +9,16 @@ import massivedecks.models.Player.Formatters._
|
||||
*/
|
||||
object Lobby {
|
||||
|
||||
case class Lobby(gameCode: String, config: Game.Config, players: List[Player], state: Game.State)
|
||||
case class Lobby(gameCode: String, owner: Player.Id, config: Game.Config, players: List[Player], state: Game.State)
|
||||
|
||||
case class LobbyAndHand(lobby: Lobby, hand: Game.Hand)
|
||||
|
||||
case class GameCodeAndSecret(gameCode: String, secret: Player.Secret)
|
||||
|
||||
object Formatters {
|
||||
implicit val lobbyWrites: Writes[Lobby] = Json.writes[Lobby]
|
||||
implicit val lobbyAndHandWrites: Writes[LobbyAndHand] = Json.writes[LobbyAndHand]
|
||||
implicit val gameCodeAndSecretWrites: Writes[GameCodeAndSecret] = Json.writes[GameCodeAndSecret]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,11 +34,11 @@ trait CachedStore extends LobbyStore {
|
||||
*/
|
||||
protected def storeLobby(lobby: Lobby): Unit
|
||||
|
||||
override def newLobby(): String = {
|
||||
override def newLobby(ownerName: String): String = {
|
||||
val gameCode = gameCodeManager.generate()
|
||||
val lock = lockFor(gameCode)
|
||||
try {
|
||||
val lobby = lobbyFactory.build(gameCode)
|
||||
val lobby = lobbyFactory.build(gameCode, ownerName)
|
||||
saveLobby(lobby)
|
||||
} finally {
|
||||
lock.unlock()
|
||||
|
||||
@@ -9,9 +9,10 @@ trait LobbyStore {
|
||||
|
||||
/**
|
||||
* Make a new lobby.
|
||||
* @param ownerName The name of the owner (the player making the lobby).
|
||||
* @return The game code for the new lobby.
|
||||
*/
|
||||
def newLobby(): String
|
||||
def newLobby(ownerName: String): String
|
||||
|
||||
/**
|
||||
* Perform a read-only action in the lobby.
|
||||
|
||||
@@ -15,8 +15,8 @@ import MassiveDecks.Models.JSON.Encode exposing (..)
|
||||
|
||||
{-| Makes a request to create a new game lobby to the server. On success, returns that lobby.
|
||||
-}
|
||||
createLobby : Request Never Game.Lobby
|
||||
createLobby = request "POST" "/api/lobbies" Nothing [] lobbyDecoder
|
||||
createLobby : String -> Request Never Game.GameCodeAndSecret
|
||||
createLobby name = request "POST" "/api/lobbies" (Just (encodeName name)) [] gameCodeAndSecretDecoder
|
||||
|
||||
|
||||
{-| Errors specific to new player requests.
|
||||
|
||||
@@ -24,6 +24,7 @@ type alias GameCode = String
|
||||
type alias Config =
|
||||
{ decks : List DeckInfo
|
||||
, houseRules : List HouseRule.Id
|
||||
, pasword : Maybe String
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +48,7 @@ type State
|
||||
-}
|
||||
type alias Lobby =
|
||||
{ gameCode : String
|
||||
, owner : Player.Id
|
||||
, config : Config
|
||||
, players : List Player
|
||||
, game : State
|
||||
@@ -56,6 +58,6 @@ type alias Lobby =
|
||||
{-| A lobby and a player's hand.
|
||||
-}
|
||||
type alias LobbyAndHand =
|
||||
{ lobby: Lobby
|
||||
{ lobby : Lobby
|
||||
, hand: Card.Hand
|
||||
}
|
||||
|
||||
@@ -16,13 +16,20 @@ lobbyAndHandDecoder = object2 Game.LobbyAndHand
|
||||
|
||||
|
||||
lobbyDecoder : Decoder Game.Lobby
|
||||
lobbyDecoder = object4 Game.Lobby
|
||||
lobbyDecoder = object5 Game.Lobby
|
||||
("gameCode" := string)
|
||||
("owner" := playerIdDecoder)
|
||||
("config" := configDecoder)
|
||||
("players" := (list playerDecoder))
|
||||
("state" := gameStateDecoder)
|
||||
|
||||
|
||||
gameCodeAndSecretDecoder : Decoder Game.GameCodeAndSecret
|
||||
gameCodeAndSecretDecoder = object2 Game.GameCodeAndSecret
|
||||
("gameCode" := string)
|
||||
("secret" := playerSecretDecoder)
|
||||
|
||||
|
||||
deckInfoDecoder : Decoder Game.DeckInfo
|
||||
deckInfoDecoder = object4 Game.DeckInfo
|
||||
("id" := string)
|
||||
@@ -32,9 +39,10 @@ deckInfoDecoder = object4 Game.DeckInfo
|
||||
|
||||
|
||||
configDecoder : Decoder Game.Config
|
||||
configDecoder = object2 Game.Config
|
||||
configDecoder = object3 Game.Config
|
||||
("decks" := (list deckInfoDecoder))
|
||||
("houseRules" := (list houseRuleDecoder))
|
||||
(maybe ("password" := string))
|
||||
|
||||
|
||||
handDecoder : Decoder Card.Hand
|
||||
|
||||
@@ -22,6 +22,7 @@ init : Model
|
||||
init =
|
||||
{ decks = []
|
||||
, deckIdInput = Input.initWithExtra DeckId "deck-id-input" UI.deckIdInputLabel "" "Play Code" UI.addDeckButton (Util.cmd AddDeck) InputMessage
|
||||
, passwordInput = Input.init Password "password-input" UI.passwordInputLabel "" "Password" (Cmd.none) InputMessage
|
||||
, loadingDecks = []
|
||||
}
|
||||
|
||||
|
||||
@@ -43,3 +43,4 @@ type alias FailureMessage = String
|
||||
-}
|
||||
type InputId
|
||||
= DeckId
|
||||
| Password
|
||||
|
||||
@@ -10,5 +10,6 @@ import MassiveDecks.Scenes.Config.Messages exposing (Message, InputId)
|
||||
type alias Model =
|
||||
{ decks : List Game.DeckInfo
|
||||
, deckIdInput : Input.Model InputId Message
|
||||
, passwordInput : Input.Model InputId Message
|
||||
, loadingDecks : List String
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module MassiveDecks.Scenes.Config.UI exposing (view, deckIdInputLabel, addDeckButton)
|
||||
module MassiveDecks.Scenes.Config.UI exposing (view, deckIdInputLabel, passwordInputLabel, addDeckButton)
|
||||
|
||||
import String
|
||||
|
||||
@@ -25,9 +25,11 @@ view lobbyModel =
|
||||
decks = lobby.config.decks
|
||||
enoughPlayers = ((List.length lobby.players) > 1)
|
||||
enoughCards = not (List.isEmpty decks)
|
||||
canNotChangeConfig = lobbyModel.lobby.owner /= lobbyModel.secret.id
|
||||
in
|
||||
div [ id "config" ]
|
||||
[ div [ id "config-content", class "mui-panel" ]
|
||||
( (if canNotChangeConfig then infoBar else [])
|
||||
++ [ div [ id "config-content", class "mui-panel" ]
|
||||
[ invite lobbyModel.init.url lobby.gameCode
|
||||
, div [ class "mui-divider" ] []
|
||||
, h1 [] [ text "Game Setup" ]
|
||||
@@ -37,16 +39,46 @@ view lobbyModel =
|
||||
[ text "Decks" ]
|
||||
]
|
||||
, li [] [ a [ attribute "data-mui-toggle" "tab"
|
||||
, attribute "data-mui-controls" "house-rules" ] [ text "House Rules" ] ]
|
||||
]
|
||||
, attribute "data-mui-controls" "house-rules"
|
||||
] [ text "House Rules" ]
|
||||
]
|
||||
, li [] [ a [ attribute "data-mui-toggle" "tab"
|
||||
, attribute "data-mui-controls" "lobby-settings"
|
||||
] [ text "Lobby Settings" ]
|
||||
]
|
||||
]
|
||||
, div [ id "decks", class "mui-tabs__pane mui--is-active" ]
|
||||
[ deckList decks model.loadingDecks model.deckIdInput ]
|
||||
[ deckList canNotChangeConfig decks model.loadingDecks model.deckIdInput ]
|
||||
, div [ id "house-rules", class "mui-tabs__pane" ]
|
||||
([ rando ] ++ (List.map (\rule -> houseRule (List.member rule.id lobbyModel.lobby.config.houseRules) rule) houseRules))
|
||||
([ rando canNotChangeConfig ] ++ (List.map (\rule -> houseRule canNotChangeConfig (List.member rule.id lobbyModel.lobby.config.houseRules) rule) houseRules))
|
||||
, div [ id "lobby-settings", class "mui-tabs__pane" ]
|
||||
[ password model.passwordInput ]
|
||||
, div [ class "mui-divider" ] []
|
||||
, startGameButton enoughPlayers enoughCards
|
||||
, startGameButton canNotChangeConfig enoughPlayers enoughCards
|
||||
]
|
||||
]
|
||||
])
|
||||
|
||||
|
||||
infoBar : List (Html msg)
|
||||
infoBar =
|
||||
[ div [ id "info-bar", class "mui--z1" ]
|
||||
[ Icon.icon "info-circle"
|
||||
, text " "
|
||||
, text "You can't change the configuration of the game, as you are not the owner."
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
passwordInputLabel : List (Html msg)
|
||||
passwordInputLabel = [ text "If blank, no password will be needed - anyone with the game code can play." ]
|
||||
|
||||
password : Input.Model InputId Message -> Html Message
|
||||
password passwordInputModel =
|
||||
div [] [ h3 [] [ Icon.icon "key", text " Privacy" ]
|
||||
, p [] [ text "A password that players will need to enter to get in the game." ]
|
||||
, Input.view passwordInputModel
|
||||
]
|
||||
|
||||
|
||||
invite : String -> String -> Html msg
|
||||
invite appUrl lobbyId =
|
||||
@@ -78,8 +110,8 @@ addDeckButton deckId =
|
||||
]
|
||||
|
||||
|
||||
deckList : List Game.DeckInfo -> List String -> Input.Model InputId Message -> Html Message
|
||||
deckList decks loadingDecks deckId =
|
||||
deckList : Bool -> List Game.DeckInfo -> List String -> Input.Model InputId Message -> Html Message
|
||||
deckList canNotChangeConfig decks loadingDecks deckId =
|
||||
table [ class "decks mui-table" ]
|
||||
[ thead []
|
||||
[ tr []
|
||||
@@ -90,10 +122,14 @@ deckList decks loadingDecks deckId =
|
||||
]
|
||||
]
|
||||
, Util.tbody [] (List.concat
|
||||
[ emptyDeckListInfo ((List.isEmpty decks) && List.isEmpty loadingDecks)
|
||||
[ if (canNotChangeConfig && (List.isEmpty decks) ) then
|
||||
[ ("!!emptyInfo", tr [] [ td [ colspan 4 ] [ text "No decks have been added yet." ] ]) ]
|
||||
else
|
||||
[]
|
||||
, emptyDeckListInfo ((not canNotChangeConfig) && (List.isEmpty decks) && List.isEmpty loadingDecks)
|
||||
, List.map loadedDeckEntry decks
|
||||
, List.map loadingDeckEntry loadingDecks
|
||||
, [ ("!!input", tr [] [ td [ colspan 4 ] [ Input.view deckId ] ]) ]
|
||||
, if (canNotChangeConfig) then [] else [ ("!!input", tr [] [ td [ colspan 4 ] [ Input.view deckId ] ]) ]
|
||||
])
|
||||
]
|
||||
|
||||
@@ -140,8 +176,8 @@ emptyDeckListInfo display =
|
||||
[]
|
||||
|
||||
|
||||
houseRule : Bool -> HouseRule -> Html Message
|
||||
houseRule enabled rule =
|
||||
houseRule : Bool -> Bool -> HouseRule -> Html Message
|
||||
houseRule canNotChangeConfig enabled rule =
|
||||
let
|
||||
(buttonText, command) =
|
||||
if enabled then
|
||||
@@ -149,22 +185,22 @@ houseRule enabled rule =
|
||||
else
|
||||
("Enable", EnableRule rule.id)
|
||||
in
|
||||
houseRuleTemplate (HouseRule.toString rule.id) rule.name rule.icon rule.description buttonText command
|
||||
houseRuleTemplate canNotChangeConfig (HouseRule.toString rule.id) rule.name rule.icon rule.description buttonText command
|
||||
|
||||
|
||||
houseRuleTemplate : String -> String -> String -> String -> String -> msg -> Html msg
|
||||
houseRuleTemplate id' title icon description buttonText message =
|
||||
houseRuleTemplate : Bool -> String -> String -> String -> String -> String -> msg -> Html msg
|
||||
houseRuleTemplate canNotChangeConfig id' title icon description buttonText message =
|
||||
div [ id id', class "house-rule" ]
|
||||
[ div [] [ h3 [] [ Icon.icon icon, text " ", text title ]
|
||||
, button [ class "mui-btn mui-btn--small mui-btn--primary", onClick message ]
|
||||
, button [ class "mui-btn mui-btn--small mui-btn--primary", onClick message, disabled canNotChangeConfig ]
|
||||
[ text buttonText ]
|
||||
]
|
||||
, p [] [ text description ]
|
||||
]
|
||||
|
||||
|
||||
rando : Html Message
|
||||
rando = houseRuleTemplate "rando" "Rando Cardrissian" "cogs"
|
||||
rando : Bool -> Html Message
|
||||
rando canNotChangeConfig = houseRuleTemplate canNotChangeConfig "rando" "Rando Cardrissian" "cogs"
|
||||
"Every round, one random card will be played for an imaginary player named Rando Cardrissian, if he wins, all players go home in a state of everlasting shame."
|
||||
"Add an AI player" AddAi
|
||||
|
||||
@@ -174,12 +210,12 @@ startGameWarning canStart = if canStart then text "" else
|
||||
span [] [ Icon.icon "info-circle", text " You will need at least two players to start the game." ]
|
||||
|
||||
|
||||
startGameButton : Bool -> Bool -> Html Message
|
||||
startGameButton enoughPlayers enoughCards = div [ id "start-game" ]
|
||||
startGameButton : Bool -> Bool -> Bool -> Html Message
|
||||
startGameButton notOwner enoughPlayers enoughCards = div [ id "start-game" ]
|
||||
[ startGameWarning enoughPlayers
|
||||
, button
|
||||
[ class "mui-btn mui-btn--primary mui-btn--raised"
|
||||
, onClick StartGame
|
||||
, disabled (not (enoughPlayers && enoughCards))
|
||||
, disabled ((not (enoughPlayers && enoughCards)) || notOwner)
|
||||
] [ text "Start Game" ]
|
||||
]
|
||||
|
||||
@@ -46,7 +46,7 @@ view model =
|
||||
root model.sidebar.hidden
|
||||
[ appHeader header model
|
||||
, spacer
|
||||
, scores model.sidebar.shownAsOverlay players
|
||||
, scores model.secret.id model.lobby.owner model.sidebar.shownAsOverlay players
|
||||
, contentWrapper contents
|
||||
]
|
||||
|
||||
@@ -63,8 +63,8 @@ spacer : Html msg
|
||||
spacer = div [ class "mui--appbar-height" ] []
|
||||
|
||||
|
||||
scores : Bool -> List Player -> Html ConsumerMessage
|
||||
scores shownAsOverlay players =
|
||||
scores : Player.Id -> Player.Id -> Bool -> List Player -> Html ConsumerMessage
|
||||
scores client owner shownAsOverlay players =
|
||||
let
|
||||
hideMessage = LocalMessage (SidebarMessage Sidebar.Hide)
|
||||
closeLink = if shownAsOverlay then
|
||||
@@ -84,10 +84,10 @@ scores shownAsOverlay players =
|
||||
, table [ class "mui-table" ]
|
||||
[ thead [] [ tr [] [ th [ class "state", title "State" ] [ Icon.icon "tasks" ]
|
||||
, th [ class "name" ] [ text "Player" ]
|
||||
, th [ class "score", title "Score" ] [ Icon.icon "star" ]
|
||||
, th [ class "score", title "Score" ] [ Icon.icon "trophy" ]
|
||||
]
|
||||
]
|
||||
, tbody [] (List.map score players)
|
||||
, tbody [] (List.map (score client owner) players)
|
||||
]
|
||||
]
|
||||
in
|
||||
@@ -102,19 +102,23 @@ scores shownAsOverlay players =
|
||||
sidebar
|
||||
|
||||
|
||||
score : Player -> Html msg
|
||||
score player =
|
||||
score : Player.Id -> Player.Id -> Player -> Html msg
|
||||
score client owner player =
|
||||
let
|
||||
classes = classList
|
||||
[ (Player.statusName player.status, True)
|
||||
, ("disconnected", player.disconnected)
|
||||
, ("left", player.left)
|
||||
]
|
||||
prename = if player.disconnected then [ Icon.icon "minus-circle", text " " ] else []
|
||||
prename = ((if player.id == owner then [ Icon.icon "star", text " " ] else [])
|
||||
++ (if player.disconnected then [ Icon.icon "minus-circle", text " " ] else []))
|
||||
afterNameTitle = (if player.id == owner then " (Owner)" else "")
|
||||
++ (if player.id == client then " (You)" else "")
|
||||
++ (if player.disconnected then " (Disconnected)" else "")
|
||||
in
|
||||
tr [ classes ]
|
||||
[ td [ class "state", title (statusDescription player) ] [ (playerIcon player) ]
|
||||
, td [ class "name", title player.name ] (List.append prename [ text player.name ])
|
||||
, td [ class "name", title (player.name ++ afterNameTitle) ] (List.append prename [ text player.name ])
|
||||
, td [ class "score" ] [ text (toString player.score) ]
|
||||
]
|
||||
|
||||
@@ -154,13 +158,13 @@ notificationPopup notification =
|
||||
|
||||
|
||||
statusDescription : Player -> String
|
||||
statusDescription player = (case player.status of
|
||||
statusDescription player = case player.status of
|
||||
NotPlayed -> "Choosing"
|
||||
Played -> "Played"
|
||||
Czar -> "Round Czar"
|
||||
Ai -> "A Computer"
|
||||
Neutral -> ""
|
||||
Skipping -> "Being Skipped") ++ if player.disconnected then " (Disconnected)" else ""
|
||||
Skipping -> "Being Skipped"
|
||||
|
||||
|
||||
statusIcon : Status -> Html msg
|
||||
|
||||
@@ -136,7 +136,11 @@ update message model =
|
||||
(model, cmd)
|
||||
|
||||
CreateLobby ->
|
||||
({ model | buttonsEnabled = False }, Request.send' API.createLobby ErrorMessage (\lobby -> JoinGivenLobbyAsNewPlayer lobby.gameCode))
|
||||
( { model | buttonsEnabled = False }
|
||||
, Request.send'
|
||||
(API.createLobby model.nameInput.value)
|
||||
ErrorMessage
|
||||
(\gameCodeAndSecret -> StoreCredentialsAndMoveToLobby gameCodeAndSecret.gameCode gameCodeAndSecret.secret))
|
||||
|
||||
SubmitCurrentTab ->
|
||||
case model.tabs.current of
|
||||
|
||||
Reference in New Issue
Block a user