Add a built-in deck source and the CaH base deck.
This does a lot of the work needed for #120.
This commit is contained in:
@@ -4,6 +4,7 @@ import Browser
|
||||
import Browser.Navigation as Navigation
|
||||
import Html exposing (Html)
|
||||
import Html.Attributes as HtmlA
|
||||
import Http
|
||||
import Json.Decode as Json
|
||||
import MassiveDecks.Cast.Client as Cast
|
||||
import MassiveDecks.Cast.Model as Cast
|
||||
@@ -28,6 +29,8 @@ import MassiveDecks.Pages.Route as Route exposing (Route)
|
||||
import MassiveDecks.Pages.Start as Start
|
||||
import MassiveDecks.Pages.Start.Route as Start
|
||||
import MassiveDecks.Pages.Unknown as Unknown
|
||||
import MassiveDecks.Requests.Api as Api
|
||||
import MassiveDecks.Requests.Request as Request
|
||||
import MassiveDecks.ServerConnection as ServerConnection
|
||||
import MassiveDecks.Settings as Settings
|
||||
import MassiveDecks.Settings.Messages as Settings
|
||||
@@ -85,6 +88,7 @@ init flags url key =
|
||||
, speech = speech
|
||||
, notifications = Notifications.init
|
||||
, remoteMode = remoteMode
|
||||
, sources = { builtIn = Nothing, cardcast = False }
|
||||
}
|
||||
|
||||
( page, pageCmd ) =
|
||||
@@ -93,9 +97,12 @@ init flags url key =
|
||||
|
||||
else
|
||||
( Pages.Loading, Cmd.none )
|
||||
|
||||
sourceCmd =
|
||||
Request.map (Error.Add >> ErrorMsg) never UpdateSources |> Api.sourceInfo |> Http.request
|
||||
in
|
||||
( { page = page, shared = shared, errorOverlay = Overlay.init }
|
||||
, Cmd.batch [ pageCmd, settingsCmd, speechCmd ]
|
||||
, Cmd.batch [ sourceCmd, pageCmd, settingsCmd, speechCmd ]
|
||||
)
|
||||
|
||||
|
||||
@@ -264,6 +271,13 @@ update msg model =
|
||||
in
|
||||
( { model | shared = { oldShared | notifications = notifications } }, notificationsCmd )
|
||||
|
||||
UpdateSources info ->
|
||||
let
|
||||
oldShared =
|
||||
model.shared
|
||||
in
|
||||
( { model | shared = { oldShared | sources = info } }, Cmd.none )
|
||||
|
||||
Refresh ->
|
||||
( model, Navigation.reload )
|
||||
|
||||
@@ -284,7 +298,7 @@ update msg model =
|
||||
Settings.update model.shared (Settings.ChangeLang (Just language))
|
||||
|
||||
( lobby, lobbyCmd ) =
|
||||
Lobby.initWithAuth { gameCode = auth.claims.gc, section = Just Lobby.Spectate } auth
|
||||
Lobby.initWithAuth shared { gameCode = auth.claims.gc, section = Just Lobby.Spectate } auth
|
||||
in
|
||||
( { model
|
||||
| page = Pages.Lobby lobby
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
module MassiveDecks.Card.Parts exposing
|
||||
( Part(..)
|
||||
, Parts
|
||||
, Style(..)
|
||||
, Transform(..)
|
||||
, fromList
|
||||
, map
|
||||
@@ -19,16 +20,24 @@ import MassiveDecks.Util.String as String
|
||||
{-| A transform to apply to the value in a slot.
|
||||
-}
|
||||
type Transform
|
||||
= UpperCase
|
||||
= NoTransform
|
||||
| UpperCase
|
||||
| Capitalize
|
||||
| Stay
|
||||
|
||||
|
||||
{-| A style to be applied to some text.
|
||||
-}
|
||||
type Style
|
||||
= NoStyle
|
||||
| Em
|
||||
| Strong
|
||||
|
||||
|
||||
{-| A part of a call's text. This is either just text or a position for a call to be inserted in-game.
|
||||
-}
|
||||
type Part
|
||||
= Text String
|
||||
| Slot Transform
|
||||
= Text String Style
|
||||
| Slot Transform Style
|
||||
|
||||
|
||||
{-| Represents a line as a part of a part. Between each one the text will be forced to line break.
|
||||
@@ -48,10 +57,10 @@ type Parts
|
||||
isSlot : Part -> Bool
|
||||
isSlot part =
|
||||
case part of
|
||||
Text _ ->
|
||||
Text _ _ ->
|
||||
False
|
||||
|
||||
Slot _ ->
|
||||
Slot _ _ ->
|
||||
True
|
||||
|
||||
|
||||
@@ -136,18 +145,18 @@ viewLinesString blankPhrase =
|
||||
viewLines (\s -> \p -> viewPartsString blankPhrase s p |> String.join "")
|
||||
|
||||
|
||||
viewParts : (Bool -> String -> List a) -> a -> List String -> List Part -> List a
|
||||
viewParts : (Bool -> String -> Style -> List a) -> a -> List String -> List Part -> List a
|
||||
viewParts viewText emptySlot play parts =
|
||||
case parts of
|
||||
firstPart :: restParts ->
|
||||
case firstPart of
|
||||
Text string ->
|
||||
viewText False string ++ viewParts viewText emptySlot play restParts
|
||||
Text string style ->
|
||||
viewText False string style ++ viewParts viewText emptySlot play restParts
|
||||
|
||||
Slot transform ->
|
||||
Slot transform style ->
|
||||
case play of
|
||||
firstPlay :: restPlay ->
|
||||
viewText True (applyTransform transform firstPlay) ++ viewParts viewText emptySlot restPlay restParts
|
||||
viewText True (applyTransform transform firstPlay) style ++ viewParts viewText emptySlot restPlay restParts
|
||||
|
||||
[] ->
|
||||
emptySlot :: viewParts viewText emptySlot [] restParts
|
||||
@@ -163,27 +172,38 @@ viewPartsHtml =
|
||||
|
||||
viewPartsString : String -> List String -> List Part -> List String
|
||||
viewPartsString blankPhrase =
|
||||
viewParts (\_ -> \s -> [ s ]) blankPhrase
|
||||
viewParts (\_ -> \s -> \_ -> [ s ]) blankPhrase
|
||||
|
||||
|
||||
applyTransform : Transform -> String -> String
|
||||
applyTransform transform value =
|
||||
case transform of
|
||||
NoTransform ->
|
||||
value
|
||||
|
||||
UpperCase ->
|
||||
String.toUpper value
|
||||
|
||||
Capitalize ->
|
||||
String.capitalise value
|
||||
|
||||
Stay ->
|
||||
value
|
||||
|
||||
|
||||
viewTextHtml : Bool -> String -> List (Html msg)
|
||||
viewTextHtml slot string =
|
||||
viewTextHtml : Bool -> String -> Style -> List (Html msg)
|
||||
viewTextHtml slot string style =
|
||||
let
|
||||
element =
|
||||
case style of
|
||||
NoStyle ->
|
||||
Html.span
|
||||
|
||||
Em ->
|
||||
Html.em
|
||||
|
||||
Strong ->
|
||||
Html.strong
|
||||
|
||||
words =
|
||||
string |> splitWords |> List.map (\word -> Html.span [] [ Html.text word ])
|
||||
string |> splitWords |> List.map (\word -> element [] [ Html.text word ])
|
||||
in
|
||||
if slot then
|
||||
[ Html.span [ HtmlA.class "slot" ] words ]
|
||||
|
||||
@@ -16,6 +16,7 @@ import MassiveDecks.Model exposing (Shared)
|
||||
import MassiveDecks.Pages.Lobby.Configure.Decks as Decks
|
||||
import MassiveDecks.Pages.Lobby.Configure.Model exposing (Config)
|
||||
import MassiveDecks.Util.String as String
|
||||
import Regex exposing (Regex)
|
||||
|
||||
|
||||
{-| Render the response to HTML.
|
||||
@@ -71,9 +72,23 @@ viewCustom shared config side update canonicalize attributes response fill =
|
||||
{- Private -}
|
||||
|
||||
|
||||
punctuation : Regex
|
||||
punctuation =
|
||||
-- TODO: This should probably get localized.
|
||||
Regex.fromString "[.?!]$" |> Maybe.withDefault Regex.never
|
||||
|
||||
|
||||
viewBody : Response -> ViewBody msg
|
||||
viewBody response =
|
||||
ViewBody (\() -> [ Html.p [] [ Html.span [] [ response.body |> String.capitalise |> Html.text ] ] ])
|
||||
let
|
||||
end =
|
||||
if response.body |> Regex.contains punctuation then
|
||||
[]
|
||||
|
||||
else
|
||||
[ Html.text "." ]
|
||||
in
|
||||
ViewBody (\() -> [ Html.p [] [ Html.span [] ((response.body |> String.capitalise |> Html.text) :: end) ] ])
|
||||
|
||||
|
||||
viewCustomBody : String -> (String -> msg) -> (String -> msg) -> String -> Maybe String -> ViewBody msg
|
||||
|
||||
@@ -17,6 +17,7 @@ module MassiveDecks.Card.Source exposing
|
||||
import Html exposing (Html)
|
||||
import Html.Attributes as HtmlA
|
||||
import Html.Events as HtmlE
|
||||
import MassiveDecks.Card.Source.BuiltIn as BuiltIn
|
||||
import MassiveDecks.Card.Source.Cardcast as Cardcast
|
||||
import MassiveDecks.Card.Source.Custom as Player
|
||||
import MassiveDecks.Card.Source.Fake as Fake
|
||||
@@ -27,15 +28,16 @@ import MassiveDecks.Model exposing (..)
|
||||
import MassiveDecks.Pages.Lobby.Configure.Decks.Model exposing (DeckOrError)
|
||||
import MassiveDecks.Strings as Strings exposing (MdString)
|
||||
import MassiveDecks.Strings.Languages as Lang
|
||||
import MassiveDecks.Util.Maybe as Maybe
|
||||
import Weightless as Wl
|
||||
import Weightless.Attributes as WlA
|
||||
|
||||
|
||||
{-| The default source for an editor.
|
||||
-}
|
||||
default : External
|
||||
default : Shared -> External
|
||||
default =
|
||||
Cardcast.generalMethods.empty ()
|
||||
BuiltIn.generalMethods.empty
|
||||
|
||||
|
||||
{-| Check if two sources are equal.
|
||||
@@ -57,23 +59,33 @@ externalAndEquals a b =
|
||||
False
|
||||
|
||||
|
||||
{-| Get an empty source of the given type.
|
||||
{-| Get an general methods of the given type.
|
||||
-}
|
||||
empty : String -> Maybe External
|
||||
empty n =
|
||||
generalMethods : String -> Maybe (ExternalGeneralMethods msg)
|
||||
generalMethods n =
|
||||
case n of
|
||||
"BuiltIn" ->
|
||||
BuiltIn.generalMethods |> Just
|
||||
|
||||
"Cardcast" ->
|
||||
() |> Cardcast.generalMethods.empty |> Just
|
||||
Cardcast.generalMethods |> Just
|
||||
|
||||
_ ->
|
||||
Nothing
|
||||
|
||||
|
||||
{-| Get an empty source of the given type.
|
||||
-}
|
||||
empty : Shared -> String -> Maybe External
|
||||
empty shared n =
|
||||
generalMethods n |> Maybe.map (\m -> m.empty shared)
|
||||
|
||||
|
||||
{-| An empty source of the same general type as the given one.
|
||||
-}
|
||||
emptyMatching : External -> External
|
||||
emptyMatching source =
|
||||
() |> (externalMethods source |> .empty)
|
||||
emptyMatching : Shared -> External -> External
|
||||
emptyMatching shared source =
|
||||
shared |> (externalMethods source |> .empty)
|
||||
|
||||
|
||||
{-| The name of a source.
|
||||
@@ -99,9 +111,9 @@ defaultDetails shared source =
|
||||
|
||||
{-| A tooltip for a source.
|
||||
-}
|
||||
tooltip : Source -> Maybe ( String, Html msg )
|
||||
tooltip source =
|
||||
case () |> (methods source |> .tooltip) of
|
||||
tooltip : Shared -> Source -> Maybe ( String, Html msg )
|
||||
tooltip shared source =
|
||||
case shared |> (methods source |> .tooltip) of
|
||||
Just ( id, rendered ) ->
|
||||
Just
|
||||
( id
|
||||
@@ -134,15 +146,23 @@ logo source =
|
||||
-}
|
||||
generalEditor : Shared -> List DeckOrError -> External -> (External -> msg) -> List (Html msg)
|
||||
generalEditor shared existing currentValue update =
|
||||
let
|
||||
enabledSources =
|
||||
[ shared.sources.builtIn |> Maybe.map (\_ -> BuiltIn.generalMethods)
|
||||
, Cardcast.generalMethods |> Maybe.justIf shared.sources.cardcast
|
||||
]
|
||||
|
||||
toOption source =
|
||||
Html.option [ HtmlA.value (source.id ()) ]
|
||||
[ () |> source.name |> Lang.html shared
|
||||
]
|
||||
in
|
||||
[ Wl.select
|
||||
[ HtmlA.id "source-selector"
|
||||
, WlA.outlined
|
||||
, HtmlE.onInput (empty >> Maybe.withDefault default >> update)
|
||||
]
|
||||
[ Html.option [ HtmlA.value "Cardcast" ]
|
||||
[ Strings.Cardcast |> Lang.html shared
|
||||
]
|
||||
, HtmlE.onInput (empty shared >> Maybe.withDefault (default shared) >> update)
|
||||
]
|
||||
(enabledSources |> List.filterMap (Maybe.map toOption))
|
||||
, editor shared existing currentValue update
|
||||
]
|
||||
|
||||
@@ -197,3 +217,6 @@ externalMethods external =
|
||||
case external of
|
||||
Cardcast playCode ->
|
||||
Cardcast.methods playCode
|
||||
|
||||
BuiltIn id ->
|
||||
BuiltIn.methods id
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
module MassiveDecks.Card.Source.BuiltIn exposing
|
||||
( generalMethods
|
||||
, methods
|
||||
)
|
||||
|
||||
import Html as Html exposing (Html)
|
||||
import Html.Attributes as HtmlA
|
||||
import Html.Events as HtmlE
|
||||
import MassiveDecks.Card.Source.BuiltIn.Model exposing (..)
|
||||
import MassiveDecks.Card.Source.Methods as Source
|
||||
import MassiveDecks.Card.Source.Model as Source exposing (Source)
|
||||
import MassiveDecks.Components.Form.Message exposing (Message)
|
||||
import MassiveDecks.Model exposing (..)
|
||||
import MassiveDecks.Pages.Lobby.Configure.Decks.Model as Decks exposing (DeckOrError)
|
||||
import MassiveDecks.Strings as Strings exposing (MdString)
|
||||
import MassiveDecks.Util.Html as Html
|
||||
import Weightless as Wl
|
||||
import Weightless.Attributes as WlA
|
||||
|
||||
|
||||
methods : Id -> Source.ExternalMethods msg
|
||||
methods given =
|
||||
{ name = name
|
||||
, logo = logo
|
||||
, empty = empty
|
||||
, id = id
|
||||
, problems = problems given
|
||||
, defaultDetails = details given
|
||||
, tooltip = tooltip given
|
||||
, editor = editor given
|
||||
, equals = equals given
|
||||
}
|
||||
|
||||
|
||||
generalMethods : Source.ExternalGeneralMethods msg
|
||||
generalMethods =
|
||||
{ name = name
|
||||
, logo = logo
|
||||
, empty = empty
|
||||
, id = id
|
||||
}
|
||||
|
||||
|
||||
|
||||
{- Private -}
|
||||
|
||||
|
||||
id : () -> String
|
||||
id _ =
|
||||
"BuiltIn"
|
||||
|
||||
|
||||
name : () -> MdString
|
||||
name () =
|
||||
Strings.BuiltIn
|
||||
|
||||
|
||||
empty : Shared -> Source.External
|
||||
empty shared =
|
||||
shared.sources.builtIn
|
||||
|> Maybe.andThen (.decks >> List.head)
|
||||
|> Maybe.map .id
|
||||
|> Maybe.withDefault (Id "")
|
||||
|> Source.BuiltIn
|
||||
|
||||
|
||||
equals : Id -> Source.External -> Bool
|
||||
equals (Id given) source =
|
||||
case source of
|
||||
Source.BuiltIn (Id other) ->
|
||||
given == other
|
||||
|
||||
_ ->
|
||||
False
|
||||
|
||||
|
||||
problems : Id -> () -> List (Message msg)
|
||||
problems _ () =
|
||||
[]
|
||||
|
||||
|
||||
editor : Id -> Shared -> List DeckOrError -> (Source.External -> msg) -> Html msg
|
||||
editor (Id selectedId) shared _ update =
|
||||
case shared.sources.builtIn of
|
||||
Just { decks } ->
|
||||
let
|
||||
deck deckInfo =
|
||||
case deckInfo.id of
|
||||
Id other ->
|
||||
Html.option
|
||||
[ HtmlA.selected (selectedId == other)
|
||||
, HtmlA.value other
|
||||
]
|
||||
[ Html.text deckInfo.name ]
|
||||
in
|
||||
Html.div [ HtmlA.class "primary" ]
|
||||
[ Wl.select
|
||||
[ HtmlA.id "built-in-selector"
|
||||
, WlA.outlined
|
||||
, Id >> Source.BuiltIn >> update |> HtmlE.onInput
|
||||
]
|
||||
(decks |> List.map deck)
|
||||
]
|
||||
|
||||
Nothing ->
|
||||
Html.nothing
|
||||
|
||||
|
||||
details : Id -> Shared -> Source.Details
|
||||
details (Id given) shared =
|
||||
let
|
||||
isSame deckInfo =
|
||||
case deckInfo.id of
|
||||
Id other ->
|
||||
given == other
|
||||
in
|
||||
{ name =
|
||||
shared.sources.builtIn
|
||||
|> Maybe.andThen (.decks >> List.filter isSame >> List.head >> Maybe.map .name)
|
||||
|> Maybe.withDefault ""
|
||||
, url = Nothing
|
||||
}
|
||||
|
||||
|
||||
tooltip : Id -> Shared -> Maybe ( String, Html msg )
|
||||
tooltip (Id given) shared =
|
||||
( "builtin-" ++ given, Html.span [] [ details (Id given) shared |> .name |> Html.text ] ) |> Just
|
||||
|
||||
|
||||
logo : () -> Maybe (Html msg)
|
||||
logo () =
|
||||
Nothing
|
||||
@@ -0,0 +1,17 @@
|
||||
module MassiveDecks.Card.Source.BuiltIn.Model exposing (Id(..))
|
||||
|
||||
{-| Models for the built-in source.
|
||||
-}
|
||||
|
||||
|
||||
{-| The id for a built-in deck.
|
||||
-}
|
||||
type Id
|
||||
= Id String
|
||||
|
||||
|
||||
{-| Create an id from a string.
|
||||
-}
|
||||
playCode : String -> Id
|
||||
playCode string =
|
||||
string |> Id
|
||||
@@ -25,6 +25,7 @@ methods playCode =
|
||||
{ name = name
|
||||
, logo = logo
|
||||
, empty = empty
|
||||
, id = id
|
||||
, problems = problems playCode
|
||||
, defaultDetails = details playCode
|
||||
, tooltip = tooltip playCode
|
||||
@@ -38,6 +39,7 @@ generalMethods =
|
||||
{ name = name
|
||||
, logo = logo
|
||||
, empty = empty
|
||||
, id = id
|
||||
}
|
||||
|
||||
|
||||
@@ -45,13 +47,18 @@ generalMethods =
|
||||
{- Private -}
|
||||
|
||||
|
||||
id : () -> String
|
||||
id () =
|
||||
"Cardcast"
|
||||
|
||||
|
||||
name : () -> MdString
|
||||
name () =
|
||||
Strings.Cardcast
|
||||
|
||||
|
||||
empty : () -> Source.External
|
||||
empty () =
|
||||
empty : Shared -> Source.External
|
||||
empty shared =
|
||||
"" |> playCode |> Source.Cardcast
|
||||
|
||||
|
||||
@@ -61,6 +68,9 @@ equals (PlayCode pc) source =
|
||||
Source.Cardcast (PlayCode other) ->
|
||||
pc == other
|
||||
|
||||
_ ->
|
||||
False
|
||||
|
||||
|
||||
problems : PlayCode -> () -> List (Message msg)
|
||||
problems (PlayCode pc) () =
|
||||
@@ -92,6 +102,9 @@ editor (PlayCode pc) shared existing update =
|
||||
in
|
||||
playCode |> Maybe.justIf (existing |> List.all notSameDeck)
|
||||
|
||||
_ ->
|
||||
Nothing
|
||||
|
||||
recentDeck (PlayCode recent) =
|
||||
Html.option [ HtmlA.value recent ] []
|
||||
in
|
||||
@@ -116,8 +129,8 @@ details (PlayCode pc) shared =
|
||||
}
|
||||
|
||||
|
||||
tooltip : PlayCode -> () -> Maybe ( String, Html msg )
|
||||
tooltip (PlayCode pc) () =
|
||||
tooltip : PlayCode -> Shared -> Maybe ( String, Html msg )
|
||||
tooltip (PlayCode pc) _ =
|
||||
( "cardcast-" ++ pc, Html.span [] [ logoInternal, Html.text pc ] ) |> Just
|
||||
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ methods =
|
||||
{ name = name shared
|
||||
, url = Nothing
|
||||
}
|
||||
, tooltip = \() -> Nothing
|
||||
, tooltip = \_ -> Nothing
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,5 +13,5 @@ methods =
|
||||
{ name = ""
|
||||
, url = Nothing
|
||||
}
|
||||
, tooltip = \() -> Nothing
|
||||
, tooltip = \_ -> Nothing
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ type alias ExternalGeneralMethods msg =
|
||||
-}
|
||||
type alias IsSpecific general msg =
|
||||
{ general
|
||||
| tooltip : () -> Maybe ( String, Html msg )
|
||||
| tooltip : Shared -> Maybe ( String, Html msg )
|
||||
, defaultDetails : Shared -> Details
|
||||
}
|
||||
|
||||
@@ -93,5 +93,6 @@ type alias IsSpecificExternal general msg =
|
||||
-}
|
||||
type alias IsGeneralExternal rest =
|
||||
{ rest
|
||||
| empty : () -> External
|
||||
| empty : Shared -> External
|
||||
, id : () -> String
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
module MassiveDecks.Card.Source.Model exposing
|
||||
( Details
|
||||
( BuiltInDeck
|
||||
, BuiltInInfo
|
||||
, Details
|
||||
, External(..)
|
||||
, Info
|
||||
, LoadFailureReason(..)
|
||||
, Source(..)
|
||||
, Summary
|
||||
)
|
||||
|
||||
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
|
||||
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
|
||||
|
||||
|
||||
@@ -31,7 +35,8 @@ sources are more limited and specific.
|
||||
|
||||
-}
|
||||
type External
|
||||
= Cardcast Cardcast.PlayCode
|
||||
= BuiltIn BuiltIn.Id
|
||||
| Cardcast Cardcast.PlayCode
|
||||
|
||||
|
||||
{-| A summary of the contents of the source deck.
|
||||
@@ -56,3 +61,19 @@ type alias Details =
|
||||
type LoadFailureReason
|
||||
= SourceFailure
|
||||
| NotFound
|
||||
|
||||
|
||||
{-| Information about what sources are available from the server.
|
||||
-}
|
||||
type alias Info =
|
||||
{ builtIn : Maybe BuiltInInfo
|
||||
, cardcast : Bool
|
||||
}
|
||||
|
||||
|
||||
type alias BuiltInInfo =
|
||||
{ decks : List BuiltInDeck }
|
||||
|
||||
|
||||
type alias BuiltInDeck =
|
||||
{ name : String, id : BuiltIn.Id }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
module MassiveDecks.Messages exposing (Msg(..))
|
||||
|
||||
import MassiveDecks.Card.Source.Model as Source
|
||||
import MassiveDecks.Cast.Model as Cast
|
||||
import MassiveDecks.Error.Messages as Error
|
||||
import MassiveDecks.Notifications.Model as Notifications
|
||||
@@ -27,5 +28,6 @@ type Msg
|
||||
| UpdateToken Lobby.Auth
|
||||
| CastStatusUpdate Cast.Status
|
||||
| RemoteCommand Cast.RemoteControlCommand
|
||||
| UpdateSources Source.Info
|
||||
| Refresh
|
||||
| BlockedExternalUrl
|
||||
|
||||
@@ -4,6 +4,7 @@ module MassiveDecks.Model exposing
|
||||
)
|
||||
|
||||
import Browser.Navigation as Navigation
|
||||
import MassiveDecks.Card.Source.Model as Sources
|
||||
import MassiveDecks.Cast.Model as Cast
|
||||
import MassiveDecks.Notifications.Model as Notifications
|
||||
import MassiveDecks.Settings.Model as Settings exposing (Settings)
|
||||
@@ -23,6 +24,7 @@ type alias Shared =
|
||||
, speech : Speech.Model
|
||||
, notifications : Notifications.Model
|
||||
, remoteMode : Bool
|
||||
, sources : Sources.Info
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ module MassiveDecks.Models.Decoders exposing
|
||||
, remoteControlCommand
|
||||
, revealingRound
|
||||
, settings
|
||||
, sourceInfo
|
||||
, tokenValidity
|
||||
, userId
|
||||
, userSummary
|
||||
@@ -28,6 +29,7 @@ import Json.Patch
|
||||
import MassiveDecks.Card.Model as Card exposing (Call, Response)
|
||||
import MassiveDecks.Card.Parts as Parts exposing (Part, Parts)
|
||||
import MassiveDecks.Card.Play as Play exposing (Play)
|
||||
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
|
||||
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
|
||||
import MassiveDecks.Card.Source.Model as Source exposing (Source)
|
||||
import MassiveDecks.Cast.Model as Cast
|
||||
@@ -54,6 +56,26 @@ import MassiveDecks.User as User exposing (User)
|
||||
import Set exposing (Set)
|
||||
|
||||
|
||||
sourceInfo : Json.Decoder Source.Info
|
||||
sourceInfo =
|
||||
Json.succeed Source.Info
|
||||
|> Json.optional "builtIn" (builtInInfo |> Json.map Just) Nothing
|
||||
|> Json.optional "cardcast" Json.bool False
|
||||
|
||||
|
||||
builtInInfo : Json.Decoder Source.BuiltInInfo
|
||||
builtInInfo =
|
||||
Json.succeed Source.BuiltInInfo
|
||||
|> Json.required "decks" (Json.list builtInDeck)
|
||||
|
||||
|
||||
builtInDeck : Json.Decoder Source.BuiltInDeck
|
||||
builtInDeck =
|
||||
Json.succeed Source.BuiltInDeck
|
||||
|> Json.required "name" Json.string
|
||||
|> Json.required "id" (Json.string |> Json.map BuiltIn.Id)
|
||||
|
||||
|
||||
unknownValue : String -> String -> Json.Decoder a
|
||||
unknownValue name value =
|
||||
("Unknown " ++ name ++ ": \"" ++ value ++ "\".") |> Json.fail
|
||||
@@ -182,6 +204,9 @@ externalSource =
|
||||
externalSourceByName : String -> Json.Decoder Source.External
|
||||
externalSourceByName name =
|
||||
case name of
|
||||
"BuiltIn" ->
|
||||
Json.field "id" Json.string |> Json.map (BuiltIn.Id >> Source.BuiltIn)
|
||||
|
||||
"Cardcast" ->
|
||||
Json.field "playCode" Json.string |> Json.map (Cardcast.playCode >> Source.Cardcast)
|
||||
|
||||
@@ -869,32 +894,60 @@ parts =
|
||||
part : Json.Decoder Part
|
||||
part =
|
||||
Json.oneOf
|
||||
[ Json.string |> Json.map Parts.Text
|
||||
, transform |> Json.map Parts.Slot
|
||||
[ Json.string |> Json.map (\t -> Parts.Text t Parts.NoStyle)
|
||||
, styled
|
||||
, slot
|
||||
]
|
||||
|
||||
|
||||
slot : Json.Decoder Parts.Part
|
||||
slot =
|
||||
Json.succeed Parts.Slot
|
||||
|> Json.optional "transform" transform Parts.NoTransform
|
||||
|> Json.optional "style" style Parts.NoStyle
|
||||
|
||||
|
||||
styled : Json.Decoder Parts.Part
|
||||
styled =
|
||||
Json.succeed Parts.Text
|
||||
|> Json.required "text" Json.string
|
||||
|> Json.optional "style" style Parts.NoStyle
|
||||
|
||||
|
||||
transform : Json.Decoder Parts.Transform
|
||||
transform =
|
||||
Json.maybe (Json.field "transform" Json.string) |> Json.andThen transformByName
|
||||
Json.string |> Json.andThen transformByName
|
||||
|
||||
|
||||
transformByName : Maybe String -> Json.Decoder Parts.Transform
|
||||
transformByName maybeName =
|
||||
case maybeName of
|
||||
Nothing ->
|
||||
Json.succeed Parts.Stay
|
||||
transformByName : String -> Json.Decoder Parts.Transform
|
||||
transformByName name =
|
||||
case name of
|
||||
"UpperCase" ->
|
||||
Json.succeed Parts.UpperCase
|
||||
|
||||
Just name ->
|
||||
case name of
|
||||
"UpperCase" ->
|
||||
Json.succeed Parts.UpperCase
|
||||
"Capitalize" ->
|
||||
Json.succeed Parts.Capitalize
|
||||
|
||||
"Capitalize" ->
|
||||
Json.succeed Parts.Capitalize
|
||||
_ ->
|
||||
unknownValue "transform" name
|
||||
|
||||
_ ->
|
||||
unknownValue "transform" name
|
||||
|
||||
style : Json.Decoder Parts.Style
|
||||
style =
|
||||
Json.string |> Json.andThen styleByName
|
||||
|
||||
|
||||
styleByName : String -> Json.Decoder Parts.Style
|
||||
styleByName name =
|
||||
case name of
|
||||
"Em" ->
|
||||
Json.succeed Parts.Em
|
||||
|
||||
"Strong" ->
|
||||
Json.succeed Parts.Strong
|
||||
|
||||
_ ->
|
||||
unknownValue "style" name
|
||||
|
||||
|
||||
round : Json.Decoder Round
|
||||
|
||||
@@ -23,6 +23,7 @@ module MassiveDecks.Models.Encoders exposing
|
||||
|
||||
import Dict
|
||||
import Json.Encode as Json
|
||||
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
|
||||
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
|
||||
import MassiveDecks.Card.Source.Model as Source exposing (Source)
|
||||
import MassiveDecks.Cast.Model as Cast
|
||||
@@ -326,6 +327,9 @@ source s =
|
||||
Source.Cardcast (Cardcast.PlayCode playCode) ->
|
||||
Json.object [ ( "source", "Cardcast" |> Json.string ), ( "playCode", playCode |> Json.string ) ]
|
||||
|
||||
Source.BuiltIn (BuiltIn.Id id) ->
|
||||
Json.object [ ( "source", "BuiltIn" |> Json.string ), ( "id", id |> Json.string ) ]
|
||||
|
||||
|
||||
language : Language -> Json.Value
|
||||
language l =
|
||||
|
||||
@@ -82,16 +82,16 @@ init shared r auth =
|
||||
]
|
||||
in
|
||||
fallbackAuth
|
||||
|> Maybe.map (initWithAuth r >> Route.Continue)
|
||||
|> Maybe.map (initWithAuth shared r >> Route.Continue)
|
||||
|> Maybe.withDefault (Route.Redirect (Route.Start { section = Start.Join (Just r.gameCode) }))
|
||||
|
||||
|
||||
initWithAuth : Route -> Auth -> ( Model, Cmd msg )
|
||||
initWithAuth r auth =
|
||||
initWithAuth : Shared -> Route -> Auth -> ( Model, Cmd msg )
|
||||
initWithAuth shared r auth =
|
||||
( { route = r
|
||||
, auth = auth
|
||||
, lobby = Nothing
|
||||
, configure = Configure.init
|
||||
, configure = Configure.init shared
|
||||
, notificationId = 0
|
||||
, notifications = []
|
||||
, inviteDialogOpen = False
|
||||
|
||||
@@ -56,11 +56,11 @@ import Weightless as Wl
|
||||
import Weightless.Attributes as WlA
|
||||
|
||||
|
||||
init : Model
|
||||
init =
|
||||
init : Shared -> Model
|
||||
init shared =
|
||||
{ localConfig = default
|
||||
, tab = Decks
|
||||
, decks = Decks.init
|
||||
, decks = Decks.init shared
|
||||
, privacy = Privacy.init
|
||||
, timeLimits = TimeLimits.init
|
||||
, rules = Rules.init
|
||||
|
||||
@@ -43,9 +43,9 @@ componentById id =
|
||||
all
|
||||
|
||||
|
||||
init : Model
|
||||
init =
|
||||
{ toAdd = Source.default }
|
||||
init : Shared -> Model
|
||||
init shared =
|
||||
{ toAdd = Source.default shared }
|
||||
|
||||
|
||||
default : Config
|
||||
@@ -66,7 +66,7 @@ update shared msg model =
|
||||
( settings, settingsCmd ) =
|
||||
Settings.onAddDeck source shared.settings
|
||||
in
|
||||
( { model | toAdd = Source.emptyMatching source }
|
||||
( { model | toAdd = Source.emptyMatching shared source }
|
||||
, { shared | settings = settings }
|
||||
, Cmd.batch [ Actions.configure (addDeck source), settingsCmd ]
|
||||
)
|
||||
@@ -226,7 +226,7 @@ submitDeckAction wrap existing deckToAdd =
|
||||
let
|
||||
potentialProblems =
|
||||
if List.any (getSource >> Source.equals deckToAdd) existing then
|
||||
[ Strings.DeckAlreadyAdded |> Message.error ]
|
||||
[ Strings.DeckAlreadyAdded |> Message.info ]
|
||||
|
||||
else
|
||||
Source.problems deckToAdd
|
||||
@@ -308,7 +308,7 @@ name wrap shared canEdit index source loading maybeError details =
|
||||
|> Maybe.justIf canEdit
|
||||
|
||||
( maybeId, tooltip ) =
|
||||
source |> Source.Ex |> Source.tooltip |> Maybe.decompose
|
||||
source |> Source.Ex |> Source.tooltip shared |> Maybe.decompose
|
||||
|
||||
attrs =
|
||||
maybeId |> Maybe.map (\id -> [ HtmlA.id id ]) |> Maybe.withDefault []
|
||||
|
||||
@@ -585,8 +585,13 @@ examplePick2 : Card.Call
|
||||
examplePick2 =
|
||||
Card.call
|
||||
(Parts.unsafeFromList
|
||||
[ [ Parts.Slot Parts.Stay, Parts.Text " + ", Parts.Slot Parts.Stay ]
|
||||
, [ Parts.Text " = ", Parts.Slot Parts.Stay ]
|
||||
[ [ Parts.Slot Parts.NoTransform Parts.NoStyle
|
||||
, Parts.Text " + " Parts.NoStyle
|
||||
, Parts.Slot Parts.NoTransform Parts.NoStyle
|
||||
]
|
||||
, [ Parts.Text " = " Parts.NoStyle
|
||||
, Parts.Slot Parts.NoTransform Parts.NoStyle
|
||||
]
|
||||
]
|
||||
)
|
||||
""
|
||||
|
||||
@@ -5,4 +5,4 @@ import MassiveDecks.Requests.HttpData.Messages as HttpData
|
||||
|
||||
|
||||
type Msg
|
||||
= SummaryUpdate (HttpData.Msg () (List Summary))
|
||||
= SummaryUpdate (HttpData.Msg Never (List Summary))
|
||||
|
||||
@@ -12,7 +12,7 @@ import MassiveDecks.Requests.HttpData.Model exposing (HttpData)
|
||||
{-| The model for the lobby browser.
|
||||
-}
|
||||
type alias Model =
|
||||
HttpData () (List Summary)
|
||||
HttpData Never (List Summary)
|
||||
|
||||
|
||||
{-| An external summary of a lobby.
|
||||
|
||||
@@ -9,7 +9,7 @@ import MassiveDecks.Requests.HttpData.Messages as HttpData
|
||||
type Msg
|
||||
= GameCodeChanged String
|
||||
| NameChanged String
|
||||
| StartGame (HttpData.Msg () Lobby.Auth)
|
||||
| StartGame (HttpData.Msg Never Lobby.Auth)
|
||||
| JoinGame (HttpData.Msg MdError Lobby.Auth)
|
||||
| LobbyBrowserMsg LobbyBrowser.Msg
|
||||
| PasswordChanged String
|
||||
|
||||
@@ -20,7 +20,7 @@ type alias Model =
|
||||
, lobbies : LobbyBrowser.Model
|
||||
, name : String
|
||||
, gameCode : Maybe GameCode
|
||||
, newLobbyRequest : HttpData () Lobby.Auth
|
||||
, newLobbyRequest : HttpData Never Lobby.Auth
|
||||
, joinLobbyRequest : HttpData MdError Lobby.Auth
|
||||
, password : Maybe String
|
||||
, overlay : Maybe MdString
|
||||
|
||||
@@ -3,11 +3,13 @@ module MassiveDecks.Requests.Api exposing
|
||||
, joinLobby
|
||||
, lobbySummaries
|
||||
, newLobby
|
||||
, sourceInfo
|
||||
)
|
||||
|
||||
import Dict exposing (Dict)
|
||||
import Http
|
||||
import Json.Decode as Json
|
||||
import MassiveDecks.Card.Source.Model as Source
|
||||
import MassiveDecks.Error.Model as Error
|
||||
import MassiveDecks.Models.Decoders as Decoders
|
||||
import MassiveDecks.Models.Encoders as Encoders
|
||||
@@ -25,7 +27,7 @@ import Url.Builder
|
||||
|
||||
{-| List the public lobbies.
|
||||
-}
|
||||
lobbySummaries : (Request.Response () (List LobbyBrowser.Summary) -> msg) -> Request msg
|
||||
lobbySummaries : (Request.Response Never (List LobbyBrowser.Summary) -> msg) -> Request msg
|
||||
lobbySummaries msg =
|
||||
{ method = "GET"
|
||||
, headers = []
|
||||
@@ -39,7 +41,7 @@ lobbySummaries msg =
|
||||
|
||||
{-| Create a new lobby.
|
||||
-}
|
||||
newLobby : (Request.Response () Lobby.Auth -> msg) -> Start.LobbyCreation -> Request msg
|
||||
newLobby : (Request.Response Never Lobby.Auth -> msg) -> Start.LobbyCreation -> Request msg
|
||||
newLobby msg creation =
|
||||
{ method = "POST"
|
||||
, headers = []
|
||||
@@ -51,6 +53,8 @@ newLobby msg creation =
|
||||
}
|
||||
|
||||
|
||||
{-| Join a lobby.
|
||||
-}
|
||||
joinLobby : (Request.Response MdError Lobby.Auth -> msg) -> GameCode -> User.Registration -> Request msg
|
||||
joinLobby msg gameCode registration =
|
||||
{ method = "POST"
|
||||
@@ -63,7 +67,9 @@ joinLobby msg gameCode registration =
|
||||
}
|
||||
|
||||
|
||||
checkAlive : (Request.Response () (Dict Lobby.Token Bool) -> msg) -> List Lobby.Token -> Request msg
|
||||
{-| Check if previously joined lobbies are still going.
|
||||
-}
|
||||
checkAlive : (Request.Response Never (Dict Lobby.Token Bool) -> msg) -> List Lobby.Token -> Request msg
|
||||
checkAlive msg tokens =
|
||||
{ method = "POST"
|
||||
, headers = []
|
||||
@@ -75,6 +81,20 @@ checkAlive msg tokens =
|
||||
}
|
||||
|
||||
|
||||
{-| Find out what sources the server offers.
|
||||
-}
|
||||
sourceInfo : (Request.Response Never Source.Info -> msg) -> Request msg
|
||||
sourceInfo msg =
|
||||
{ method = "GET"
|
||||
, headers = []
|
||||
, url = url [ "sources" ]
|
||||
, body = Http.emptyBody
|
||||
, expect = Request.expectResponse msg noError Decoders.sourceInfo
|
||||
, timeout = Nothing
|
||||
, tracker = Nothing
|
||||
}
|
||||
|
||||
|
||||
|
||||
{- Private -}
|
||||
|
||||
@@ -92,6 +112,6 @@ url path =
|
||||
Url.Builder.absolute ([ "api" ] ++ path) []
|
||||
|
||||
|
||||
noError : Json.Decoder ()
|
||||
noError : Json.Decoder Never
|
||||
noError =
|
||||
Json.succeed ()
|
||||
Json.fail "No specific errors are expected for this request."
|
||||
|
||||
@@ -204,6 +204,7 @@ type MdString
|
||||
| Cardcast -- The name of the Cardcast service.
|
||||
| CardcastPlayCode -- A term referring to the play code that identifies a deck on Cardcast.
|
||||
| CardcastEmptyPlayCode -- A description of the problem of the entered Cardcast play code being empty.
|
||||
| BuiltIn -- A term referring to decks of cards that are provided by this instance of the game.
|
||||
| APlayer -- A short description of a generic player in the game in the context of being the author of a card.
|
||||
| DeckAlreadyAdded -- A description of the problem of the deck already being added to the game configuration.
|
||||
| ConfigureDecks -- A name for the section of the configuration screen for changing the decks for the game.
|
||||
|
||||
@@ -4,7 +4,7 @@ module MassiveDecks.Strings.Languages.En exposing (pack)
|
||||
This is the primary language, strings here are the canonical representation, and are suitable to translate from.
|
||||
-}
|
||||
|
||||
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
|
||||
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
|
||||
import MassiveDecks.Card.Source.Model as Source
|
||||
import MassiveDecks.Strings exposing (MdString(..))
|
||||
import MassiveDecks.Strings.Translation as Translation exposing (Result(..))
|
||||
@@ -15,7 +15,7 @@ pack =
|
||||
{ code = "en"
|
||||
, name = English
|
||||
, translate = translate
|
||||
, recommended = "CAHBS" |> Cardcast.playCode |> Source.Cardcast
|
||||
, recommended = "cah-base-en" |> BuiltIn.Id |> Source.BuiltIn
|
||||
}
|
||||
|
||||
|
||||
@@ -714,6 +714,9 @@ translate mdString =
|
||||
CardcastEmptyPlayCode ->
|
||||
[ Text "Enter a ", Ref CardcastPlayCode, Text " for the deck you want to add." ]
|
||||
|
||||
BuiltIn ->
|
||||
[ Text "Built-in" ]
|
||||
|
||||
APlayer ->
|
||||
[ Text "A Player" ]
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
module MassiveDecks.Strings.Languages.It exposing (pack)
|
||||
|
||||
{- General Italian translation -}
|
||||
{- Italian translation -}
|
||||
|
||||
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
|
||||
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
|
||||
import MassiveDecks.Card.Source.Model as Source
|
||||
import MassiveDecks.Strings exposing (MdString(..))
|
||||
import MassiveDecks.Strings.Translation as Translation exposing (Result(..))
|
||||
@@ -13,7 +13,7 @@ pack =
|
||||
{ code = "it"
|
||||
, name = Italian
|
||||
, translate = translate
|
||||
, recommended = "CAHBS" |> Cardcast.playCode |> Source.Cardcast
|
||||
, recommended = "cah-base-en" |> BuiltIn.Id |> Source.BuiltIn
|
||||
}
|
||||
|
||||
|
||||
@@ -482,9 +482,11 @@ translate mdString =
|
||||
[ Text (String.fromInt numberOfCards) ]
|
||||
|
||||
-- Lobby
|
||||
-- TODO: Translate
|
||||
LobbyNameLabel ->
|
||||
[ Text "Game Name" ]
|
||||
|
||||
-- TODO: Translate
|
||||
DefaultLobbyName { owner } ->
|
||||
[ Text owner, Text "'s Game" ]
|
||||
|
||||
@@ -730,6 +732,10 @@ translate mdString =
|
||||
CardcastEmptyPlayCode ->
|
||||
[ Text "Inserisci il ", Ref CardcastPlayCode, Text " per il mazzo che vuoi aggiungere." ]
|
||||
|
||||
-- TODO: Translate
|
||||
BuiltIn ->
|
||||
[ Text "Built-in" ]
|
||||
|
||||
APlayer ->
|
||||
[ Text "Un giocatore" ]
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ module MassiveDecks.Strings.Languages.PtBR exposing (pack)
|
||||
{-| Brazilian Portuguese translation.
|
||||
-}
|
||||
|
||||
import MassiveDecks.Card.Source.Cardcast.Model as Cardcast
|
||||
import MassiveDecks.Card.Source.BuiltIn.Model as BuiltIn
|
||||
import MassiveDecks.Card.Source.Model as Source
|
||||
import MassiveDecks.Strings exposing (MdString(..))
|
||||
import MassiveDecks.Strings.Translation as Translation exposing (Result(..))
|
||||
@@ -14,7 +14,7 @@ pack =
|
||||
{ code = "ptBR"
|
||||
, name = BrazilianPortuguese
|
||||
, translate = translate
|
||||
, recommended = "CAHBS" |> Cardcast.playCode |> Source.Cardcast
|
||||
, recommended = "cah-base-en" |> BuiltIn.Id |> Source.BuiltIn
|
||||
}
|
||||
|
||||
|
||||
@@ -482,9 +482,11 @@ translate mdString =
|
||||
[ Text (String.fromInt numberOfCards) ]
|
||||
|
||||
-- Lobby
|
||||
-- TODO: Translate
|
||||
LobbyNameLabel ->
|
||||
[ Text "Game Name" ]
|
||||
|
||||
-- TODO: Translate
|
||||
DefaultLobbyName { owner } ->
|
||||
[ Text owner, Text "'s Game" ]
|
||||
|
||||
@@ -730,6 +732,10 @@ translate mdString =
|
||||
CardcastEmptyPlayCode ->
|
||||
[ Text "Digite um ", Ref CardcastPlayCode, Text " para o deck que você queira adicionar." ]
|
||||
|
||||
-- TODO: Translate
|
||||
BuiltIn ->
|
||||
[ Text "Built-in" ]
|
||||
|
||||
APlayer ->
|
||||
[ Text "Um jogador" ]
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
align-content: flex-start;
|
||||
justify-content: flex-start;
|
||||
|
||||
span {
|
||||
span, em, strong {
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: break-word;
|
||||
word-break: break-all;
|
||||
@@ -47,7 +47,7 @@
|
||||
.slot {
|
||||
display: contents;
|
||||
|
||||
span {
|
||||
span, em, strong {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
||||
@@ -124,6 +124,11 @@
|
||||
--input-padding-top-bottom: 0.9em;
|
||||
}
|
||||
|
||||
#built-in-selector {
|
||||
height: 100%;
|
||||
--input-padding-top-bottom: 0.9em;
|
||||
}
|
||||
|
||||
.house-rules {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user