Refactored all lobby sub-scenes to modify the lobby via message rather than directly - simpler code and a single modification point.

This commit is contained in:
Gareth Latty
2016-05-19 15:17:52 +01:00
parent 84254e88a5
commit 6b61056f30
10 changed files with 111 additions and 110 deletions
+17
View File
@@ -181,6 +181,23 @@ back : String -> Player.Secret -> Request Never Game.LobbyAndHand
back = commandRequest "back" [] []
{-| Errors specific to redrawing.
* `NotEnoughPoints` - The player does not have enough points to redraw.
-}
type RedrawError
= NotEnoughPoints
{-| Make a request to redraw the players hand, losing a point.
-}
redraw : String -> Player.Secret -> Request RedrawError Game.LobbyAndHand
redraw =
commandRequest
"redraw"
[]
[ ((400, "not-enough-points-to-redraw"), Decode.succeed NotEnoughPoints)
]
{- Private -}
+23 -56
View File
@@ -9,7 +9,6 @@ import MassiveDecks.API as API
import MassiveDecks.API.Request as Request
import MassiveDecks.Components.Input as Input
import MassiveDecks.Components.Errors as Errors
import MassiveDecks.Models.Game as Game
import MassiveDecks.Scenes.Lobby.Models as Lobby
import MassiveDecks.Scenes.Config.Messages exposing (ConsumerMessage(..), Message(..), InputId(..), Deck(..))
import MassiveDecks.Scenes.Config.Models exposing (Model)
@@ -41,90 +40,58 @@ view lobbyModel = UI.view lobbyModel |> Html.map LocalMessage
{-| Handles messages and alters the model as appropriate.
-}
update : Message -> Lobby.Model -> (Lobby.Model, Cmd ConsumerMessage)
update : Message -> Lobby.Model -> (Model, Cmd ConsumerMessage)
update message lobbyModel =
let
gameCode = lobbyModel.lobbyAndHand.lobby.gameCode
gameCode = lobbyModel.lobby.gameCode
secret = lobbyModel.secret
model = lobbyModel.config
in
case message of
ConfigureDecks (Request rawDeckId) ->
let
deckId = String.toUpper rawDeckId
in
lobbyModel
|> updateConfig (\model -> ({ model | loadingDecks = model.loadingDecks ++ [ deckId ] }, Cmd.none))
:> cmd (Request.send (API.addDeck gameCode secret deckId)
(addDeckErrorHandler deckId)
ErrorMessage
((Add deckId) >> ConfigureDecks >> LocalMessage))
:> clearDeckIdError
{ model | loadingDecks = model.loadingDecks ++ [ deckId ] } !
[ Request.send (API.addDeck gameCode secret deckId) (addDeckErrorHandler deckId) ErrorMessage ((Add deckId) >> ConfigureDecks >> LocalMessage)
, inputClearErrorCmd DeckId
]
ConfigureDecks (Add deckId lobbyAndHand) ->
lobbyModel
|> updateLobbyAndHand lobbyAndHand
:> removeDeckLoadingSpinner deckId
(removeDeckLoadingSpinner deckId model, Util.cmd (LobbyUpdate lobbyAndHand))
ConfigureDecks (Fail deckId errorMessage) ->
lobbyModel
|> deckIdError errorMessage
:> removeDeckLoadingSpinner deckId
(removeDeckLoadingSpinner deckId model, inputSetErrorCmd DeckId errorMessage)
InputMessage message ->
lobbyModel
|> updateDeckIdInput (Input.update message lobbyModel.config.deckIdInput)
let
(deckIdInput, msg) = Input.update message lobbyModel.config.deckIdInput
in
({ model | deckIdInput = deckIdInput }, Cmd.map LocalMessage msg)
AddAi ->
lobbyModel
|> cmd (Request.send' (API.newAi gameCode) ErrorMessage (\_ -> LocalMessage NoOp))
(model, Request.send' (API.newAi gameCode) ErrorMessage (\_ -> LocalMessage NoOp))
StartGame ->
lobbyModel
|> cmd (Request.send (API.newGame gameCode secret) newGameErrorHandler ErrorMessage (GameStarted >> LocalMessage))
(model, Request.send (API.newGame gameCode secret) newGameErrorHandler ErrorMessage (GameStarted >> LocalMessage))
GameStarted lobbyAndHand ->
lobbyModel
|> updateLobbyAndHand lobbyAndHand
(model, Util.cmd (LobbyUpdate lobbyAndHand))
NoOp ->
(lobbyModel, Cmd.none)
(model, Cmd.none)
type alias Update = Lobby.Model -> (Lobby.Model, Cmd ConsumerMessage)
inputClearErrorCmd : InputId -> Cmd ConsumerMessage
inputClearErrorCmd inputId = (inputId, Nothing |> Input.Error) |> InputMessage |> LocalMessage |> Util.cmd
clearDeckIdError : Update
clearDeckIdError lobbyModel = (lobbyModel, (DeckId, Nothing |> Input.Error) |> InputMessage |> LocalMessage |> Util.cmd)
inputSetErrorCmd : InputId -> String -> Cmd ConsumerMessage
inputSetErrorCmd inputId error = (inputId, Just error |> Input.Error) |> InputMessage |> LocalMessage |> Util.cmd
deckIdError : String -> Update
deckIdError error lobbyModel = (lobbyModel, (DeckId, Just error |> Input.Error) |> InputMessage |> LocalMessage |> Util.cmd)
cmd : Cmd ConsumerMessage -> Update
cmd command lobbyModel = (lobbyModel, command)
updateLobbyAndHand : Game.LobbyAndHand -> Update
updateLobbyAndHand lobbyAndHand lobbyModel = ({ lobbyModel | lobbyAndHand = lobbyAndHand }, Cmd.none)
updateConfig : (Model -> (Model, Cmd ConsumerMessage)) -> Update
updateConfig update lobbyModel =
let
result = update lobbyModel.config
in
({ lobbyModel | config = fst result }, snd result)
removeDeckLoadingSpinner : String -> Update
removeDeckLoadingSpinner deckId =
updateConfig (\model -> ({ model | loadingDecks = List.filter ((/=) deckId) model.loadingDecks }, Cmd.none))
updateDeckIdInput : (Input.Model InputId Message, Cmd Message) -> Update
updateDeckIdInput update lobbyModel =
updateConfig (\model -> ({ model | deckIdInput = fst update }, snd update |> Cmd.map LocalMessage)) lobbyModel
removeDeckLoadingSpinner : String -> Model -> Model
removeDeckLoadingSpinner deckId model = { model | loadingDecks = List.filter ((/=) deckId) model.loadingDecks }
addDeckErrorHandler : String -> API.AddDeckError -> ConsumerMessage
@@ -8,7 +8,8 @@ import MassiveDecks.Models.Game as Game
{-| This type is used for all sending of messages, allowing us to send messages handled outside this scene.
-}
type ConsumerMessage
= ErrorMessage Errors.Message
= LobbyUpdate Game.LobbyAndHand
| ErrorMessage Errors.Message
| LocalMessage Message
+1 -1
View File
@@ -18,7 +18,7 @@ view : Lobby.Model -> Html Message
view lobbyModel =
let
model = lobbyModel.config
lobby = lobbyModel.lobbyAndHand.lobby
lobby = lobbyModel.lobby
decks = lobby.config.decks
enoughPlayers = ((List.length lobby.players) > 1)
enoughCards = not (List.isEmpty decks)
+28 -12
View File
@@ -32,7 +32,8 @@ import MassiveDecks.Util as Util
-}
init : Init -> Game.LobbyAndHand -> Player.Secret -> (Model, Cmd ConsumerMessage)
init init lobbyAndHand secret =
( { lobbyAndHand = lobbyAndHand
( { lobby = lobbyAndHand.lobby
, hand = lobbyAndHand.hand
, config = Config.init
, playing = Playing.init init
, secret = secret
@@ -54,11 +55,11 @@ sendSecretToWebSocket url gameCode secret = WebSocket.send (webSocketUrl url gam
subscriptions : Model -> Sub ConsumerMessage
subscriptions model =
let
delegated = case model.lobbyAndHand.lobby.round of
delegated = case model.lobby.round of
Nothing -> Config.subscriptions model.config |> Sub.map ConfigMessage
Just round -> Sub.none
websocket = WebSocket.listen (webSocketUrl model.init.url model.lobbyAndHand.lobby.gameCode) webSocketResponseDecoder
websocket = WebSocket.listen (webSocketUrl model.init.url model.lobby.gameCode) webSocketResponseDecoder
in
Sub.batch [ delegated |> Sub.map LocalMessage
, websocket |> Sub.map LocalMessage
@@ -116,28 +117,31 @@ update message model =
Config.ErrorMessage errorMessage ->
(model, ErrorMessage errorMessage |> Util.cmd)
Config.LobbyUpdate lobbyAndHand ->
model |> updateLobbyAndHand lobbyAndHand
Config.LocalMessage localMessage ->
let
(newModel, cmd) = Config.update localMessage model
(config, cmd) = Config.update localMessage model
in
(newModel, Cmd.map (LocalMessage << ConfigMessage) cmd)
({ model | config = config }, Cmd.map (LocalMessage << ConfigMessage) cmd)
PlayingMessage playingMessage ->
case playingMessage of
Playing.ErrorMessage errorMessage ->
(model, ErrorMessage errorMessage |> Util.cmd)
Playing.LobbyUpdate lobbyAndHand ->
model |> updateLobbyAndHand lobbyAndHand
Playing.LocalMessage localMessage ->
let
(newModel, cmd) = Playing.update localMessage model
(playing, cmd) = Playing.update localMessage model
in
(newModel, Cmd.map (LocalMessage << PlayingMessage) cmd)
({ model | playing = playing }, Cmd.map (LocalMessage << PlayingMessage) cmd)
LobbyUpdated lobby ->
let
lobbyAndHand = model.lobbyAndHand
in
({ model | lobbyAndHand = { lobbyAndHand | lobby = lobby } }, Cmd.none)
model |> updateLobbyAndHand { lobby = lobby, hand = model.hand }
DismissNotification notification ->
let
@@ -151,7 +155,7 @@ update message model =
GameEvent event ->
let
players = model.lobbyAndHand.lobby.players
players = model.lobby.players
in
case event of
Event.RoundEnd call czar responses playedByAndWinner ->
@@ -180,6 +184,18 @@ update message model =
(model, Cmd.none)
type alias Update = Model -> (Model, Cmd ConsumerMessage)
updateLobbyAndHand : Game.LobbyAndHand -> Update
updateLobbyAndHand lobbyAndHand model =
let
events = Event.events model.lobby lobbyAndHand.lobby |> List.map (GameEvent >> LocalMessage >> Util.cmd)
in
{ model | lobby = lobbyAndHand.lobby
, hand = lobbyAndHand.hand} ! events
{-| Handles a change to the displayed notification.
-}
notificationChange : Model -> Maybe Notification -> (Model, Cmd ConsumerMessage)
@@ -3,6 +3,7 @@ module MassiveDecks.Scenes.Lobby.Models exposing (Model)
import MassiveDecks.Models exposing (Init)
import MassiveDecks.Models.Game as Game
import MassiveDecks.Models.Player as Player
import MassiveDecks.Models.Card as Card
import MassiveDecks.Models.Notification as Notification exposing (Notification)
import MassiveDecks.Scenes.Config.Models as Config
import MassiveDecks.Scenes.Playing.Models as Playing
@@ -11,7 +12,8 @@ import MassiveDecks.Scenes.Playing.Models as Playing
{-| The state of the lobby.
-}
type alias Model =
{ lobbyAndHand : Game.LobbyAndHand
{ lobby : Game.Lobby
, hand : Card.Hand
, config : Config.Model
, playing : Playing.Model
, secret : Player.Secret
+1 -1
View File
@@ -19,7 +19,7 @@ import MassiveDecks.Util as Util
view : Model -> Html ConsumerMessage
view model =
let
lobby = model.lobbyAndHand.lobby
lobby = model.lobby
url = model.init.url
gameCode = lobby.gameCode
players = lobby.players
+31 -34
View File
@@ -59,11 +59,11 @@ view model =
{-| Handles messages and alters the model as appropriate.
-}
update : Message -> Lobby.Model -> (Lobby.Model, Cmd ConsumerMessage)
update : Message -> Lobby.Model -> (Model, Cmd ConsumerMessage)
update message lobbyModel =
let
model = lobbyModel.playing
lobby = lobbyModel.lobbyAndHand.lobby
lobby = lobbyModel.lobby
secret = lobbyModel.secret
gameCode = lobby.gameCode
in
@@ -78,62 +78,61 @@ update message lobbyModel =
) lobby.round)
in
if playing && canPlay then
lobbyModel |> updateModel (\model -> { model | picked = model.picked ++ [ cardId ] })
({ model | picked = model.picked ++ [ cardId ] }, Cmd.none)
else
(lobbyModel, Cmd.none)
(model, Cmd.none)
Withdraw cardId ->
lobbyModel |> updateModel (\model -> { model | picked = List.filter ((/=) cardId) model.picked })
({ model | picked = List.filter ((/=) cardId) model.picked }, Cmd.none)
Play ->
lobbyModel
|> updateModel (\model -> { model | picked = [] })
:> cmd (Request.send (API.play gameCode secret model.picked) playErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
( { model | picked = [] }
, Request.send (API.play gameCode secret model.picked) playErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage)
)
Consider potentialWinnerIndex ->
lobbyModel |> updateModel (\model -> { model | considering = Just potentialWinnerIndex })
( { model | considering = Just potentialWinnerIndex }
, Cmd.none
)
Choose winnerIndex ->
lobbyModel
|> updateModel (\model -> { model | considering = Nothing })
:> cmd (Request.send (API.choose gameCode secret winnerIndex) chooseErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
( { model | considering = Nothing }
, Request.send (API.choose gameCode secret winnerIndex) chooseErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage)
)
NextRound ->
lobbyModel |> updateModel (\model -> { model | considering = Nothing
, finishedRound = Nothing
})
( { model | considering = Nothing
, finishedRound = Nothing
}
, Cmd.none
)
CheckForPlayedCardsToAnimate ->
lobbyModel
|> cmd (if List.isEmpty model.shownPlayed.toAnimate then Cmd.none else Util.cmd (LocalMessage AnimatePlayedCards))
( model
, if List.isEmpty model.shownPlayed.toAnimate then Cmd.none else Util.cmd (LocalMessage AnimatePlayedCards)
)
AnimatePlayedCards ->
let
(shownPlayed, seed) = updatePositioning model.shownPlayed model.seed
in
lobbyModel |> updateModel (\model -> { model | seed = seed
, shownPlayed = shownPlayed
})
( { model | seed = seed
, shownPlayed = shownPlayed
}
, Cmd.none
)
Skip playerIds ->
lobbyModel |> cmd (Request.send (API.skip gameCode secret playerIds) skipErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
(model, Request.send (API.skip gameCode secret playerIds) skipErrorHandler ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
Back ->
lobbyModel |> cmd (Request.send' (API.back gameCode secret) ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
(model, Request.send' (API.back gameCode secret) ErrorMessage (UpdateLobbyAndHand >> LocalMessage))
UpdateLobbyAndHand lobbyAndHand ->
lobbyModel |> updateLobbyAndHand lobbyAndHand
type alias Update = Lobby.Model -> (Lobby.Model, Cmd ConsumerMessage)
updateModel : (Model -> Model) -> Update
updateModel update lobbyModel = ({ lobbyModel | playing = update lobbyModel.playing }, Cmd.none)
cmd : Cmd ConsumerMessage -> Update
cmd command lobbyModel = (lobbyModel, command)
type alias Update = Lobby.Model -> (Model, Cmd ConsumerMessage)
updateLobbyAndHand : Game.LobbyAndHand -> Update
@@ -160,9 +159,7 @@ updateLobbyAndHand lobbyAndHand lobbyModel =
newModel = { model | shownPlayed = newShownPlayed
, seed = seed}
in
({ lobbyModel | lobbyAndHand = lobbyAndHand
, playing = newModel
}, Cmd.none)
(newModel, Util.cmd (LobbyUpdate lobbyAndHand))
chooseErrorHandler : API.ChooseError -> ConsumerMessage
@@ -8,7 +8,8 @@ import MassiveDecks.Models.Game as Game
{-| This type is used for all sending of messages, allowing us to send messages handled outside this scene.
-}
type ConsumerMessage
= ErrorMessage Errors.Message
= LobbyUpdate Game.LobbyAndHand
| ErrorMessage Errors.Message
| LocalMessage Message
@@ -17,7 +17,7 @@ view : Lobby.Model -> (List (Html Message), List (Html Message))
view lobbyModel =
let
model = lobbyModel.playing
lobby = lobbyModel.lobbyAndHand.lobby
lobby = lobbyModel.lobby
in
case model.finishedRound of
Just round ->
@@ -35,8 +35,8 @@ view lobbyModel =
roundContents : Lobby.Model -> Game.Round -> List (Html Message)
roundContents lobbyModel round =
let
lobby = lobbyModel.lobbyAndHand.lobby
hand = lobbyModel.lobbyAndHand.hand.hand
lobby = lobbyModel.lobby
hand = lobbyModel.hand.hand
model = lobbyModel.playing
pickedWithIndex = Util.getAllWithIndex hand model.picked
picked = List.map snd pickedWithIndex