From 228e08dba69183b89ab5e79bdc88aae0f3a949f7 Mon Sep 17 00:00:00 2001 From: Gareth Latty Date: Wed, 27 Jul 2016 22:26:58 +0100 Subject: [PATCH] Add ownership for configuration. --- app/massivedecks/controllers/API.scala | 8 +- app/massivedecks/lobby/Config.scala | 14 +++- app/massivedecks/lobby/Lobby.scala | 22 ++++- app/massivedecks/lobby/Players.scala | 8 -- app/massivedecks/models/Errors.scala | 2 + app/massivedecks/models/Game.scala | 2 +- app/massivedecks/models/Lobby.scala | 5 +- app/massivedecks/stores/CachedStore.scala | 4 +- app/massivedecks/stores/LobbyStore.scala | 3 +- client/src/MassiveDecks/API.elm | 4 +- client/src/MassiveDecks/Models/Game.elm | 4 +- .../src/MassiveDecks/Models/JSON/Decode.elm | 12 ++- client/src/MassiveDecks/Scenes/Config.elm | 1 + .../MassiveDecks/Scenes/Config/Messages.elm | 1 + .../src/MassiveDecks/Scenes/Config/Models.elm | 1 + client/src/MassiveDecks/Scenes/Config/UI.elm | 82 +++++++++++++------ client/src/MassiveDecks/Scenes/Lobby/UI.elm | 26 +++--- client/src/MassiveDecks/Scenes/Start.elm | 6 +- 18 files changed, 144 insertions(+), 61 deletions(-) diff --git a/app/massivedecks/controllers/API.scala b/app/massivedecks/controllers/API.scala index e10ac74..cbdc82f 100644 --- a/app/massivedecks/controllers/API.scala +++ b/app/massivedecks/controllers/API.scala @@ -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)) } } } diff --git a/app/massivedecks/lobby/Config.scala b/app/massivedecks/lobby/Config.scala index 6c12561..45ca67d 100644 --- a/app/massivedecks/lobby/Config.scala +++ b/app/massivedecks/lobby/Config.scala @@ -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) + } + } diff --git a/app/massivedecks/lobby/Lobby.scala b/app/massivedecks/lobby/Lobby.scala index db624d7..a0349ed 100644 --- a/app/massivedecks/lobby/Lobby.scala +++ b/app/massivedecks/lobby/Lobby.scala @@ -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()) + } + } diff --git a/app/massivedecks/lobby/Players.scala b/app/massivedecks/lobby/Players.scala index 4a931bf..a52e8e5 100644 --- a/app/massivedecks/lobby/Players.scala +++ b/app/massivedecks/lobby/Players.scala @@ -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) diff --git a/app/massivedecks/models/Errors.scala b/app/massivedecks/models/Errors.scala index 0de6a6f..d8409e3 100644 --- a/app/massivedecks/models/Errors.scala +++ b/app/massivedecks/models/Errors.scala @@ -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 + } diff --git a/app/massivedecks/models/Game.scala b/app/massivedecks/models/Game.scala index 1c31bd2..431279b 100644 --- a/app/massivedecks/models/Game.scala +++ b/app/massivedecks/models/Game.scala @@ -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 diff --git a/app/massivedecks/models/Lobby.scala b/app/massivedecks/models/Lobby.scala index 2bc76d1..d8689f2 100644 --- a/app/massivedecks/models/Lobby.scala +++ b/app/massivedecks/models/Lobby.scala @@ -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] } } diff --git a/app/massivedecks/stores/CachedStore.scala b/app/massivedecks/stores/CachedStore.scala index 88b20f3..fe2f624 100644 --- a/app/massivedecks/stores/CachedStore.scala +++ b/app/massivedecks/stores/CachedStore.scala @@ -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() diff --git a/app/massivedecks/stores/LobbyStore.scala b/app/massivedecks/stores/LobbyStore.scala index a304b57..4fb110a 100644 --- a/app/massivedecks/stores/LobbyStore.scala +++ b/app/massivedecks/stores/LobbyStore.scala @@ -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. diff --git a/client/src/MassiveDecks/API.elm b/client/src/MassiveDecks/API.elm index ab89b44..4fe50ea 100644 --- a/client/src/MassiveDecks/API.elm +++ b/client/src/MassiveDecks/API.elm @@ -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. diff --git a/client/src/MassiveDecks/Models/Game.elm b/client/src/MassiveDecks/Models/Game.elm index 7a9532f..c86ac9e 100644 --- a/client/src/MassiveDecks/Models/Game.elm +++ b/client/src/MassiveDecks/Models/Game.elm @@ -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 } diff --git a/client/src/MassiveDecks/Models/JSON/Decode.elm b/client/src/MassiveDecks/Models/JSON/Decode.elm index 0d12c89..c7fd8b3 100644 --- a/client/src/MassiveDecks/Models/JSON/Decode.elm +++ b/client/src/MassiveDecks/Models/JSON/Decode.elm @@ -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 diff --git a/client/src/MassiveDecks/Scenes/Config.elm b/client/src/MassiveDecks/Scenes/Config.elm index 74a14ef..422f2bf 100644 --- a/client/src/MassiveDecks/Scenes/Config.elm +++ b/client/src/MassiveDecks/Scenes/Config.elm @@ -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 = [] } diff --git a/client/src/MassiveDecks/Scenes/Config/Messages.elm b/client/src/MassiveDecks/Scenes/Config/Messages.elm index acc9daf..eba999c 100644 --- a/client/src/MassiveDecks/Scenes/Config/Messages.elm +++ b/client/src/MassiveDecks/Scenes/Config/Messages.elm @@ -43,3 +43,4 @@ type alias FailureMessage = String -} type InputId = DeckId + | Password diff --git a/client/src/MassiveDecks/Scenes/Config/Models.elm b/client/src/MassiveDecks/Scenes/Config/Models.elm index 780952b..f922358 100644 --- a/client/src/MassiveDecks/Scenes/Config/Models.elm +++ b/client/src/MassiveDecks/Scenes/Config/Models.elm @@ -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 } diff --git a/client/src/MassiveDecks/Scenes/Config/UI.elm b/client/src/MassiveDecks/Scenes/Config/UI.elm index 424b7b7..b4b6b76 100644 --- a/client/src/MassiveDecks/Scenes/Config/UI.elm +++ b/client/src/MassiveDecks/Scenes/Config/UI.elm @@ -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" ] ] diff --git a/client/src/MassiveDecks/Scenes/Lobby/UI.elm b/client/src/MassiveDecks/Scenes/Lobby/UI.elm index 45bb88c..8b55027 100644 --- a/client/src/MassiveDecks/Scenes/Lobby/UI.elm +++ b/client/src/MassiveDecks/Scenes/Lobby/UI.elm @@ -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 diff --git a/client/src/MassiveDecks/Scenes/Start.elm b/client/src/MassiveDecks/Scenes/Start.elm index d8955e7..e9b893f 100644 --- a/client/src/MassiveDecks/Scenes/Start.elm +++ b/client/src/MassiveDecks/Scenes/Start.elm @@ -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