Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add in-game chat #245

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions client/src/elm/MassiveDecks/Models/Decoders.elm
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import MassiveDecks.Game.Time as Time
import MassiveDecks.Model exposing (..)
import MassiveDecks.Models.MdError as MdError exposing (MdError)
import MassiveDecks.Notifications.Model as Notifications
import MassiveDecks.Pages.Lobby.Chat as Chat
import MassiveDecks.Pages.Lobby.Configure.Decks.Model as DeckConfig
import MassiveDecks.Pages.Lobby.Configure.Model as Configure
import MassiveDecks.Pages.Lobby.Configure.Privacy.Model as PrivacyConfig
Expand Down Expand Up @@ -196,6 +197,7 @@ settings =
Json.succeed Settings
|> Json.required "tokens" (Json.dict lobbyToken)
|> Json.required "openUserList" Json.bool
|> Json.required "openChat" Json.bool
|> Json.optional "lastUsedName" (Json.string |> Json.map Just) Nothing
|> Json.required "recentDecks" (Json.list externalSource)
|> Json.optional "chosenLanguage" (language |> Json.map Just) Nothing
Expand Down Expand Up @@ -316,10 +318,18 @@ lobby ld calls =
|> Json.required "users" users
|> Json.required "owner" userId
|> Json.required "config" config
|> Json.required "messages" (Json.list message)
|> Json.optional "game" (game ld calls |> Json.map (Game.emptyModel >> Just)) Nothing
|> Json.optional "errors" (Json.list gameStateError) []


message : Json.Decoder Chat.Message
message =
Json.succeed Chat.Message
|> Json.required "content" Json.string
|> Json.required "author" Json.string


game : Maybe LikeDetail -> Maybe (List Card.Call) -> Json.Decoder Game
game ld calls =
Json.succeed Game
Expand Down Expand Up @@ -776,6 +786,9 @@ eventByName name =
"GameEnded" ->
gameEvent ended

"ReceiveChatMessage" ->
receiveChatMessage

"ErrorEncountered" ->
errorEncountered

Expand Down Expand Up @@ -809,6 +822,12 @@ ended =
(Json.field "winner" (Json.list userId |> Json.map Set.fromList))


receiveChatMessage : Json.Decoder Events.Event
receiveChatMessage =
Json.map (\m -> Events.ReceiveChatMessage { message = m })
(Json.field "message" message)


stageTimerDone : Json.Decoder Events.GameEvent
stageTimerDone =
Json.map2 (\r -> \s -> Events.StageTimerDone { round = r, stage = s })
Expand Down
1 change: 1 addition & 0 deletions client/src/elm/MassiveDecks/Models/Encoders.elm
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ settings s =
List.concat
[ [ ( "tokens", s.tokens |> Dict.toList |> List.map (\( gc, t ) -> ( gc, Json.string t )) |> Json.object )
, ( "openUserList", Json.bool s.openUserList )
, ( "openChat", Json.bool s.openChat )
, ( "recentDecks", Json.list source s.recentDecks )
, ( "compactCards", s.cardSize |> cardSize )
, ( "speech", s.speech |> speech )
Expand Down
68 changes: 62 additions & 6 deletions client/src/elm/MassiveDecks/Pages/Lobby.elm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Html exposing (Html)
import Html.Attributes as HtmlA
import Html.Events as HtmlE
import Html.Keyed as HtmlK
import Json.Decode as Json
import Json.Patch as Json
import MassiveDecks.Animated as Animated exposing (Animated)
import MassiveDecks.Card.Model as Card
Expand All @@ -38,6 +39,7 @@ import MassiveDecks.Icon as Icon
import MassiveDecks.Model exposing (..)
import MassiveDecks.Models.MdError as MdError
import MassiveDecks.Pages.Lobby.Actions as Actions
import MassiveDecks.Pages.Lobby.Chat as Chat
import MassiveDecks.Pages.Lobby.Configure as Configure
import MassiveDecks.Pages.Lobby.Configure.Model as Configure
import MassiveDecks.Pages.Lobby.Events as Events
Expand All @@ -60,7 +62,6 @@ import MassiveDecks.User as User exposing (User)
import MassiveDecks.Util.Html as Html
import MassiveDecks.Util.Html.Attributes as HtmlA
import MassiveDecks.Util.Maybe as Maybe
import MassiveDecks.Util.NeList as NeList
import Material.Button as Button
import Material.Card as Card
import Material.IconButton as IconButton
Expand Down Expand Up @@ -102,6 +103,7 @@ initWithAuth _ r auth =
, spectate = Spectate.init
, gameMenu = Menu.Closed
, userMenu = Nothing
, chatInput = ""
}
, ServerConnection.connect auth.claims.gc auth.token
)
Expand Down Expand Up @@ -343,6 +345,13 @@ update wrap shared msg model =
, Cmd.none
)

Events.ReceiveChatMessage message ->
let
m =
lobby.messages ++ [ message.message ]
in
( Stay { model | lobbyAndConfigure = model.lobbyAndConfigure |> Maybe.map (\l -> { l | lobby = { lobby | messages = m } }) }, shared, Cmd.none )

Nothing ->
case event of
Events.Sync { state, hand, play, partialTimeAnchor } ->
Expand Down Expand Up @@ -421,6 +430,18 @@ update wrap shared msg model =
Copy id ->
( Stay model, shared, Ports.copyText id )

ChatMsg m ->
case m of
Chat.KeyDown key ->
if key == 13 then
( Stay { model | chatInput = "" }, shared, Actions.sendChatMessage model.chatInput )

else
( Stay model, shared, Cmd.none )

Chat.Input content ->
( Stay { model | chatInput = content }, shared, Cmd.none )

ChangeSection s ->
let
r =
Expand Down Expand Up @@ -522,6 +543,9 @@ viewWithUsers wrap wrapSettings shared s viewContent model =
usersShown =
shared.settings.settings.openUserList

chatShown =
shared.settings.settings.openChat

castAttrs =
case shared.castStatus of
Cast.NoDevicesAvailable ->
Expand All @@ -548,6 +572,13 @@ viewWithUsers wrap wrapSettings shared s viewContent model =
else
Icon.users

chatIcon =
if chatShown then
Icon.hide

else
Icon.facebookMessenger

lobby =
model.lobbyAndConfigure |> Maybe.map .lobby

Expand All @@ -568,7 +599,7 @@ viewWithUsers wrap wrapSettings shared s viewContent model =
in
[ Html.div
[ HtmlA.id "lobby"
, HtmlA.classList [ ( "collapsed-users", not usersShown ) ]
, HtmlA.classList [ ( "collapsed-users", not usersShown ), ( "collapsed-chat", not chatShown ) ]
, shared.settings.settings.cardSize |> cardSizeToAttr
]
(Html.div [ HtmlA.id "top-bar" ]
Expand All @@ -578,6 +609,10 @@ viewWithUsers wrap wrapSettings shared s viewContent model =
(usersIcon |> Icon.styled [ Icon.lg ] |> Icon.view)
(Strings.ToggleUserList |> Lang.string shared)
(usersShown |> not |> Settings.ChangeOpenUserList |> wrapSettings |> Just)
, IconButton.view
(chatIcon |> Icon.styled [ Icon.lg ] |> Icon.view)
(Strings.ToggleChat |> Lang.string shared)
(chatShown |> not |> Settings.ChangeOpenChat |> wrapSettings |> Just)
, lobbyMenu wrap shared model.gameMenu model.route s audienceMode localUser localPlayer (maybeGame |> Maybe.map .game)
]
, castButton
Expand All @@ -587,7 +622,7 @@ viewWithUsers wrap wrapSettings shared s viewContent model =
]
:: HtmlK.ol [ HtmlA.class "notifications" ] notifications
:: (model.lobbyAndConfigure
|> Maybe.map2 (viewLobby wrap shared model.auth model.userMenu viewContent) model.timeAnchor
|> Maybe.map2 (viewLobby wrap shared model.auth model.userMenu viewContent model) model.timeAnchor
|> Maybe.withDefault
[ Html.div [ HtmlA.class "loading" ]
[ Icon.loading |> Icon.styled [ Icon.fa3x ] |> Icon.view ]
Expand All @@ -603,8 +638,8 @@ viewWithUsers wrap wrapSettings shared s viewContent model =
]


viewLobby : (Msg -> msg) -> Shared -> Auth -> Maybe User.Id -> ViewContent msg -> Time.Anchor -> LobbyAndConfigure -> List (Html msg)
viewLobby wrap shared auth openUserMenu viewContent timeAnchor lobbyAndConfigure =
viewLobby : (Msg -> msg) -> Shared -> Auth -> Maybe User.Id -> ViewContent msg -> Model -> Time.Anchor -> LobbyAndConfigure -> List (Html msg)
viewLobby wrap shared auth openUserMenu viewContent model timeAnchor lobbyAndConfigure =
let
lobby =
lobbyAndConfigure.lobby
Expand Down Expand Up @@ -632,6 +667,7 @@ viewLobby wrap shared auth openUserMenu viewContent timeAnchor lobbyAndConfigure
in
[ Html.div [ HtmlA.id "lobby-content" ]
[ viewUsers wrap shared auth.claims.uid lobby openUserMenu game
, viewChat wrap lobby model
, Html.div [ HtmlA.id "scroll-frame" ] [ viewContent configDisabledReason auth timeAnchor lobbyAndConfigure ]
, lobby.errors |> viewErrors shared
]
Expand Down Expand Up @@ -930,7 +966,27 @@ viewUsers wrap shared localUserId lobby openUserMenu game =
groups =
List.concat [ activeGroups, inactiveGroup ]
in
Card.view [ HtmlA.id "users" ] [ Html.div [ HtmlA.class "collapsible" ] [ HtmlK.ol [] groups ] ]
Card.view [ HtmlA.id "users" ]
[ Html.div [ HtmlA.class "collapsible" ]
[ HtmlK.ol [] groups ]
]


viewChat : (Msg -> msg) -> Lobby -> Model -> Html msg
viewChat wrap lobby model =
let
users =
lobby.users

messages =
lobby.messages |> List.map (\message -> (users |> Dict.get message.author |> Maybe.map .name |> Maybe.withDefault "Unknown User") ++ ": " ++ message.content) |> List.map (Html.text >> (\t -> [ t ]) >> Html.p [ HtmlA.class "message" ])
in
Card.view [ HtmlA.id "chat" ]
[ Html.div [ HtmlA.class "collapsible" ]
[ Html.ol [] messages
, Html.input [ HtmlA.placeholder "Message", HtmlE.on "keydown" (Json.map (Chat.KeyDown >> ChatMsg >> wrap) HtmlE.keyCode), HtmlE.onInput (Chat.Input >> ChatMsg >> wrap), HtmlA.value model.chatInput ] []
]
]


viewRoleGroup : (Msg -> msg) -> Shared -> User.Id -> User.Privilege -> Bool -> Maybe User.Id -> Maybe Game -> ( User.Role, List ( User.Id, User ) ) -> ( String, Html msg )
Expand Down
6 changes: 6 additions & 0 deletions client/src/elm/MassiveDecks/Pages/Lobby/Actions.elm
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ module MassiveDecks.Pages.Lobby.Actions exposing
, pickCall
, redraw
, reveal
, sendChatMessage
, setPlayerAway
, setPresence
, setPrivilege
Expand Down Expand Up @@ -142,6 +143,11 @@ enforceTimeLimit round stage =
]


sendChatMessage : String -> Cmd msg
sendChatMessage message =
action "SendChatMessage" [ ( "message", message |> Json.string ) ]



{- Private -}

Expand Down
14 changes: 14 additions & 0 deletions client/src/elm/MassiveDecks/Pages/Lobby/Chat.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module MassiveDecks.Pages.Lobby.Chat exposing (..)

import MassiveDecks.User as User


type alias Message =
{ content : String
, author : User.Id
}


type Msg
= KeyDown Int
| Input String
2 changes: 2 additions & 0 deletions client/src/elm/MassiveDecks/Pages/Lobby/Events.elm
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import MassiveDecks.Card.Play as Play
import MassiveDecks.Game.Round as Round exposing (Round)
import MassiveDecks.Game.Time as Time exposing (Time)
import MassiveDecks.Models.MdError as MdError
import MassiveDecks.Pages.Lobby.Chat as Chat
import MassiveDecks.Pages.Lobby.Model exposing (Lobby)
import MassiveDecks.User as User
import Set exposing (Set)
Expand All @@ -38,6 +39,7 @@ type Event
| PrivilegeChanged { user : User.Id, privilege : User.Privilege }
| UserRoleChanged { user : User.Id, role : User.Role, hand : Maybe (List Card.Response) }
| ErrorEncountered { error : MdError.GameStateError }
| ReceiveChatMessage { message : Chat.Message }


{-| The user's intentional presence in the lobby.
Expand Down
2 changes: 2 additions & 0 deletions client/src/elm/MassiveDecks/Pages/Lobby/Messages.elm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import MassiveDecks.Animated as Animated
import MassiveDecks.Game.Messages as Game
import MassiveDecks.Game.Time as Time
import MassiveDecks.Models.MdError exposing (MdError)
import MassiveDecks.Pages.Lobby.Chat as Chat
import MassiveDecks.Pages.Lobby.Configure.Messages as Configure
import MassiveDecks.Pages.Lobby.Events exposing (Event)
import MassiveDecks.Pages.Lobby.Model exposing (..)
Expand Down Expand Up @@ -33,4 +34,5 @@ type Msg
| SetGameMenuState Menu.State
| SetUserMenuState User.Id Menu.State
| EndGame
| ChatMsg Chat.Msg
| NoOp
3 changes: 3 additions & 0 deletions client/src/elm/MassiveDecks/Pages/Lobby/Model.elm
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import MassiveDecks.Error.Model exposing (Error)
import MassiveDecks.Game.Model as Game
import MassiveDecks.Game.Time as Time
import MassiveDecks.Models.MdError exposing (GameStateError, MdError)
import MassiveDecks.Pages.Lobby.Chat as Chat
import MassiveDecks.Pages.Lobby.Configure.Model as Configure
import MassiveDecks.Pages.Lobby.GameCode exposing (GameCode)
import MassiveDecks.Pages.Lobby.Route exposing (..)
Expand Down Expand Up @@ -49,6 +50,7 @@ type alias Model =
, spectate : Spectate.Model
, gameMenu : Menu.State
, userMenu : Maybe User.Id
, chatInput : String
}


Expand All @@ -64,6 +66,7 @@ type alias Lobby =
{ users : Dict User.Id User
, owner : User.Id
, config : Configure.Config
, messages : List Chat.Message
, game : Maybe Game.Model
, errors : List GameStateError
}
Expand Down
4 changes: 4 additions & 0 deletions client/src/elm/MassiveDecks/Settings.elm
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ defaults =
{ tokens = Dict.empty
, lastUsedName = Nothing
, openUserList = False
, openChat = False
, recentDecks = []
, chosenLanguage = Nothing
, cardSize = Full
Expand Down Expand Up @@ -110,6 +111,9 @@ update shared msg =
ChangeOpenUserList open ->
changeSettings (\s -> { s | openUserList = open }) model

ChangeOpenChat open ->
changeSettings (\s -> { s | openChat = open }) model

RemoveInvalid tokenValidity ->
let
newTokens =
Expand Down
1 change: 1 addition & 0 deletions client/src/elm/MassiveDecks/Settings/Messages.elm
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type Msg
= ChangeLang (Maybe Language)
| ChangeCardSize CardSize
| ChangeOpenUserList Bool
| ChangeOpenChat Bool
| ToggleOpen
| RemoveInvalid (List Lobby.Token)
| ToggleSpeech Bool
Expand Down
1 change: 1 addition & 0 deletions client/src/elm/MassiveDecks/Settings/Model.elm
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ This is really more than just user settings, it's any persistent data we store i
type alias Settings =
{ tokens : Dict String Lobby.Token
, openUserList : Bool
, openChat : Bool
, lastUsedName : Maybe String
, recentDecks : List Source.External
, chosenLanguage : Maybe Language
Expand Down
1 change: 1 addition & 0 deletions client/src/elm/MassiveDecks/Strings.elm
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ type MdString
| Likes { total : Int } -- A display of a number of likes.
| LikesDescription -- A description of the number of likes a play received or a player has recieved.
| ToggleUserList -- A description of the action of showing or hiding the user list.
| ToggleChat -- A description of the action of showing or hiding the chat.
| GameMenu -- A description of the game menu.
| UnknownUser -- A name for a user that doesn't have a known name.
| InvitePlayers -- A short term for inviting players to the game.
Expand Down
4 changes: 4 additions & 0 deletions client/src/elm/MassiveDecks/Strings/Languages/De.elm
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,10 @@ translate _ mdString =
ToggleUserList ->
[ Text "Anzeigen oder Ausblenden der Anzeigetafel." ]

-- TODO: Translate
ToggleChat ->
[ Missing ]

GameMenu ->
[ Text "Spiel-Menü." ]

Expand Down
4 changes: 4 additions & 0 deletions client/src/elm/MassiveDecks/Strings/Languages/DeXInformal.elm
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,10 @@ translate _ mdString =
ToggleUserList ->
[ Text "Anzeigen oder Ausblenden der Anzeigetafel." ]

-- TODO: Translate
ToggleChat ->
[ Missing ]

GameMenu ->
[ Text "Spiel-Menü." ]

Expand Down
3 changes: 3 additions & 0 deletions client/src/elm/MassiveDecks/Strings/Languages/En/Internal.elm
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,9 @@ translate _ mdString =
ToggleUserList ->
[ Text "Show or hide the scoreboard." ]

ToggleChat ->
[ Text "Show or hide the chat." ]

GameMenu ->
[ Text "Game menu." ]

Expand Down
Loading