|
@@ -1,17 +1,22 @@
|
|
|
-module Main exposing (..)
|
|
|
|
|
|
|
+port module Main exposing (..)
|
|
|
|
|
|
|
|
|
|
+import API
|
|
|
import Browser exposing (Document)
|
|
import Browser exposing (Document)
|
|
|
import Card exposing (CardData, CardPerformanceDistributions, calculatePerformanceDistributions, manaCostToSymbol)
|
|
import Card exposing (CardData, CardPerformanceDistributions, calculatePerformanceDistributions, manaCostToSymbol)
|
|
|
import Chart as C
|
|
import Chart as C
|
|
|
import Chart.Attributes as CA
|
|
import Chart.Attributes as CA
|
|
|
|
|
+import Components.Button as Button
|
|
|
import Database
|
|
import Database
|
|
|
import Deck
|
|
import Deck
|
|
|
|
|
+import Dict exposing (Dict)
|
|
|
import Draft exposing (Draft)
|
|
import Draft exposing (Draft)
|
|
|
-import Html exposing (Html, a, button, div, img, li, span, text, ul)
|
|
|
|
|
|
|
+import Html exposing (Html, a, button, div, img, li, p, span, text, ul)
|
|
|
import Html.Attributes exposing (alt, class, classList, disabled, src)
|
|
import Html.Attributes exposing (alt, class, classList, disabled, src)
|
|
|
import Html.Events as Events exposing (onClick, onMouseEnter)
|
|
import Html.Events as Events exposing (onClick, onMouseEnter)
|
|
|
import Html.Keyed as Keyed
|
|
import Html.Keyed as Keyed
|
|
|
import Icon exposing (chevronDown, chevronUp)
|
|
import Icon exposing (chevronDown, chevronUp)
|
|
|
|
|
+import Json.Decode exposing (decodeString)
|
|
|
|
|
+import Json.Encode as Encode
|
|
|
import List.Extra as List
|
|
import List.Extra as List
|
|
|
import Round
|
|
import Round
|
|
|
import Signals
|
|
import Signals
|
|
@@ -25,12 +30,13 @@ main =
|
|
|
{ init = init
|
|
{ init = init
|
|
|
, update = update
|
|
, update = update
|
|
|
, view = view
|
|
, view = view
|
|
|
- , subscriptions = \_ -> Sub.none
|
|
|
|
|
|
|
+ , subscriptions = subscriptions
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
type Model
|
|
type Model
|
|
|
- = Ready ReadyModel
|
|
|
|
|
|
|
+ = ChooseSet ChooseSetModel
|
|
|
|
|
+ | Ready ReadyModel
|
|
|
| Error ErrorModel
|
|
| Error ErrorModel
|
|
|
|
|
|
|
|
|
|
|
|
@@ -51,6 +57,19 @@ type alias ToolboxAccordion =
|
|
|
{ cmc : Bool, signals : Bool, signalsDelta : Bool, deckList : Bool }
|
|
{ cmc : Bool, signals : Bool, signalsDelta : Bool, deckList : Bool }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+type SetLoadStatus
|
|
|
|
|
+ = CheckingLocalData
|
|
|
|
|
+ | NoLocalData
|
|
|
|
|
+ | HasLocalData Database.Database
|
|
|
|
|
+ | FetchingRemoteData
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+type alias ChooseSetModel =
|
|
|
|
|
+ { draftData : String
|
|
|
|
|
+ , sets : Dict String SetLoadStatus
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
type alias ReadyModel =
|
|
type alias ReadyModel =
|
|
|
{ draft : Draft
|
|
{ draft : Draft
|
|
|
, database : Database.Database
|
|
, database : Database.Database
|
|
@@ -69,10 +88,52 @@ type alias ErrorModel =
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
-init : { setData : String, draftData : String, cardRatings : String } -> ( Model, Cmd Msg )
|
|
|
|
|
|
|
+init : { sets : List String, draftData : String } -> ( Model, Cmd Msg )
|
|
|
init flags =
|
|
init flags =
|
|
|
- case ( Draft.decode flags.draftData, Database.decode flags.setData flags.cardRatings ) of
|
|
|
|
|
- ( Ok draftData, Ok database ) ->
|
|
|
|
|
|
|
+ let
|
|
|
|
|
+ setStatus : Dict String SetLoadStatus
|
|
|
|
|
+ setStatus =
|
|
|
|
|
+ flags.sets
|
|
|
|
|
+ |> List.map (\s -> ( s, CheckingLocalData ))
|
|
|
|
|
+ |> Dict.fromList
|
|
|
|
|
+
|
|
|
|
|
+ setCmds : List (Cmd Msg)
|
|
|
|
|
+ setCmds =
|
|
|
|
|
+ List.map
|
|
|
|
|
+ (\s -> sendDoesSetHaveLocalData s)
|
|
|
|
|
+ flags.sets
|
|
|
|
|
+ in
|
|
|
|
|
+ ( ChooseSet
|
|
|
|
|
+ { draftData = flags.draftData
|
|
|
|
|
+ , sets = setStatus
|
|
|
|
|
+ }
|
|
|
|
|
+ , Cmd.batch (API.getSets IOGotSets :: setCmds)
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+type Msg
|
|
|
|
|
+ = Increment
|
|
|
|
|
+ | Decrement
|
|
|
|
|
+ | Highlight String
|
|
|
|
|
+ | FlipHighlightedCard
|
|
|
|
|
+ | SetFocusStat FocusStat
|
|
|
|
|
+ | SetDeckProgress DeckProgress
|
|
|
|
|
+ | ToggleCMCChart
|
|
|
|
|
+ | ToggleSignalsChart
|
|
|
|
|
+ | ToggleSignalsDeltaChart
|
|
|
|
|
+ | ToggleDeckList
|
|
|
|
|
+ | SetDeckSortMethod Deck.DeckSortMethod
|
|
|
|
|
+ | IOGotSets (Result String (List String))
|
|
|
|
|
+ | IOFetchSetData String
|
|
|
|
|
+ | IOGotSetData (Result String ( String, Maybe Database.Database ))
|
|
|
|
|
+ | PortReceiveDoesSetHaveLocalData String
|
|
|
|
|
+ | StartDraft String Database.Database
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+startDraft : ChooseSetModel -> Database.Database -> ( Model, Cmd Msg )
|
|
|
|
|
+startDraft initFlags database =
|
|
|
|
|
+ case Draft.decode initFlags.draftData of
|
|
|
|
|
+ Ok draftData ->
|
|
|
( Ready
|
|
( Ready
|
|
|
{ draft = draftData
|
|
{ draft = draftData
|
|
|
, database = database
|
|
, database = database
|
|
@@ -92,33 +153,90 @@ init flags =
|
|
|
, Cmd.none
|
|
, Cmd.none
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- ( Err err, Ok _ ) ->
|
|
|
|
|
|
|
+ Err err ->
|
|
|
( Error { error = "Error decoding draft data: " ++ err }, Cmd.none )
|
|
( Error { error = "Error decoding draft data: " ++ err }, Cmd.none )
|
|
|
|
|
|
|
|
- ( Ok _, Err err ) ->
|
|
|
|
|
- ( Error { error = "Error decoding set data: " ++ err }, Cmd.none )
|
|
|
|
|
|
|
|
|
|
- ( Err draftError, Err databaseError ) ->
|
|
|
|
|
- ( Error { error = "Error decoding draft data: " ++ draftError ++ ", set data: " ++ databaseError }, Cmd.none )
|
|
|
|
|
|
|
+update : Msg -> Model -> ( Model, Cmd Msg )
|
|
|
|
|
+update msg model =
|
|
|
|
|
+ case model of
|
|
|
|
|
+ ChooseSet mdl ->
|
|
|
|
|
+ case msg of
|
|
|
|
|
+ StartDraft setCode database ->
|
|
|
|
|
+ startDraft mdl database
|
|
|
|
|
|
|
|
|
|
+ IOGotSets (Ok remoteData) ->
|
|
|
|
|
+ -- Merge any new sets into the local sets
|
|
|
|
|
+ let
|
|
|
|
|
+ remoteSets =
|
|
|
|
|
+ remoteData
|
|
|
|
|
+ |> List.map (\s -> ( s, CheckingLocalData ))
|
|
|
|
|
+ |> Dict.fromList
|
|
|
|
|
+
|
|
|
|
|
+ newRemoteSets =
|
|
|
|
|
+ Dict.diff remoteSets mdl.sets
|
|
|
|
|
+
|
|
|
|
|
+ setStatus : Dict String SetLoadStatus
|
|
|
|
|
+ setStatus =
|
|
|
|
|
+ Dict.union
|
|
|
|
|
+ mdl.sets
|
|
|
|
|
+ newRemoteSets
|
|
|
|
|
+
|
|
|
|
|
+ remoteSetCmds : List (Cmd Msg)
|
|
|
|
|
+ remoteSetCmds =
|
|
|
|
|
+ List.map
|
|
|
|
|
+ (\s -> sendDoesSetHaveLocalData s)
|
|
|
|
|
+ (Dict.keys newRemoteSets)
|
|
|
|
|
+ in
|
|
|
|
|
+ ( ChooseSet { mdl | sets = setStatus }
|
|
|
|
|
+ , Cmd.batch remoteSetCmds
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
-type Msg
|
|
|
|
|
- = Increment
|
|
|
|
|
- | Decrement
|
|
|
|
|
- | Highlight String
|
|
|
|
|
- | FlipHighlightedCard
|
|
|
|
|
- | SetFocusStat FocusStat
|
|
|
|
|
- | SetDeckProgress DeckProgress
|
|
|
|
|
- | ToggleCMCChart
|
|
|
|
|
- | ToggleSignalsChart
|
|
|
|
|
- | ToggleSignalsDeltaChart
|
|
|
|
|
- | ToggleDeckList
|
|
|
|
|
- | SetDeckSortMethod Deck.DeckSortMethod
|
|
|
|
|
|
|
+ IOGotSets (Err e) ->
|
|
|
|
|
+ ( Error { error = "Error fetching sets (" ++ e ++ ")" }, Cmd.none )
|
|
|
|
|
|
|
|
|
|
+ PortReceiveDoesSetHaveLocalData unparsedData ->
|
|
|
|
|
+ let
|
|
|
|
|
+ markSetDataLoaded :
|
|
|
|
|
+ String
|
|
|
|
|
+ -> Database.Database
|
|
|
|
|
+ -> Dict String SetLoadStatus
|
|
|
|
|
+ -> Dict String SetLoadStatus
|
|
|
|
|
+ markSetDataLoaded setCode db =
|
|
|
|
|
+ Dict.insert setCode (HasLocalData db)
|
|
|
|
|
+
|
|
|
|
|
+ markSetDataNotAvailable : String -> Dict String SetLoadStatus -> Dict String SetLoadStatus
|
|
|
|
|
+ markSetDataNotAvailable setCode =
|
|
|
|
|
+ Dict.insert setCode NoLocalData
|
|
|
|
|
+ in
|
|
|
|
|
+ case Database.decode unparsedData of
|
|
|
|
|
+ Ok ( setCode, Just db ) ->
|
|
|
|
|
+ ( ChooseSet { mdl | sets = markSetDataLoaded setCode db mdl.sets }, Cmd.none )
|
|
|
|
|
+
|
|
|
|
|
+ Ok ( setCode, Nothing ) ->
|
|
|
|
|
+ ( ChooseSet { mdl | sets = markSetDataNotAvailable setCode mdl.sets }
|
|
|
|
|
+ , Cmd.none
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ Err e ->
|
|
|
|
|
+ ( Error { error = "Error decoding local set data (" ++ e ++ ")" }, Cmd.none )
|
|
|
|
|
+
|
|
|
|
|
+ IOFetchSetData setCode ->
|
|
|
|
|
+ ( ChooseSet { mdl | sets = Dict.insert setCode FetchingRemoteData mdl.sets }
|
|
|
|
|
+ , API.getSetData setCode IOGotSetData
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ IOGotSetData (Ok ( setCode, Just database )) ->
|
|
|
|
|
+ ( ChooseSet { mdl | sets = Dict.insert setCode (HasLocalData database) mdl.sets }
|
|
|
|
|
+ , sendSaveLocalData (Database.encode ( setCode, database ))
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ IOGotSetData (Err e) ->
|
|
|
|
|
+ ( Error { error = "Error fetching remote set data (" ++ e ++ ")" }, Cmd.none )
|
|
|
|
|
+
|
|
|
|
|
+ _ ->
|
|
|
|
|
+ ( ChooseSet mdl, Cmd.none )
|
|
|
|
|
|
|
|
-update : Msg -> Model -> ( Model, Cmd Msg )
|
|
|
|
|
-update msg model =
|
|
|
|
|
- case model of
|
|
|
|
|
Ready mdl ->
|
|
Ready mdl ->
|
|
|
case msg of
|
|
case msg of
|
|
|
Increment ->
|
|
Increment ->
|
|
@@ -176,6 +294,21 @@ update msg model =
|
|
|
SetDeckSortMethod method ->
|
|
SetDeckSortMethod method ->
|
|
|
( Ready { mdl | deckSortOrder = method }, Cmd.none )
|
|
( Ready { mdl | deckSortOrder = method }, Cmd.none )
|
|
|
|
|
|
|
|
|
|
+ IOGotSets _ ->
|
|
|
|
|
+ ( Ready mdl, Cmd.none )
|
|
|
|
|
+
|
|
|
|
|
+ IOGotSetData _ ->
|
|
|
|
|
+ ( Ready mdl, Cmd.none )
|
|
|
|
|
+
|
|
|
|
|
+ IOFetchSetData _ ->
|
|
|
|
|
+ ( Ready mdl, Cmd.none )
|
|
|
|
|
+
|
|
|
|
|
+ PortReceiveDoesSetHaveLocalData _ ->
|
|
|
|
|
+ ( Ready mdl, Cmd.none )
|
|
|
|
|
+
|
|
|
|
|
+ StartDraft _ _ ->
|
|
|
|
|
+ ( Ready mdl, Cmd.none )
|
|
|
|
|
+
|
|
|
Error mdl ->
|
|
Error mdl ->
|
|
|
( Error mdl, Cmd.none )
|
|
( Error mdl, Cmd.none )
|
|
|
|
|
|
|
@@ -185,6 +318,9 @@ view model =
|
|
|
{ title = "Drafter"
|
|
{ title = "Drafter"
|
|
|
, body =
|
|
, body =
|
|
|
[ case model of
|
|
[ case model of
|
|
|
|
|
+ ChooseSet mdl ->
|
|
|
|
|
+ viewChooseSet mdl
|
|
|
|
|
+
|
|
|
Ready mdl ->
|
|
Ready mdl ->
|
|
|
viewReady mdl
|
|
viewReady mdl
|
|
|
|
|
|
|
@@ -194,6 +330,45 @@ view model =
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+viewChooseSet : ChooseSetModel -> Html Msg
|
|
|
|
|
+viewChooseSet model =
|
|
|
|
|
+ let
|
|
|
|
|
+ viewLoadStatus : String -> SetLoadStatus -> Html Msg
|
|
|
|
|
+ viewLoadStatus setCode s =
|
|
|
|
|
+ case s of
|
|
|
|
|
+ FetchingRemoteData ->
|
|
|
|
|
+ text "Loading..."
|
|
|
|
|
+
|
|
|
|
|
+ CheckingLocalData ->
|
|
|
|
|
+ text "Loading..."
|
|
|
|
|
+
|
|
|
|
|
+ NoLocalData ->
|
|
|
|
|
+ Button.make "Download" (IOFetchSetData setCode) |> Button.view
|
|
|
|
|
+
|
|
|
|
|
+ HasLocalData database ->
|
|
|
|
|
+ Button.make "Open" (StartDraft setCode database) |> Button.view
|
|
|
|
|
+ in
|
|
|
|
|
+ div [ class "w-full h-full bg-slate-100 flex justify-center items-center" ]
|
|
|
|
|
+ [ div [ class "max-w-2xl max-h-2xl bg-slate-500 rounded-lg p-6 shadow-xl" ]
|
|
|
|
|
+ [ ul [ class "divide-y divide-slate-600" ]
|
|
|
|
|
+ (List.map
|
|
|
|
|
+ (\s ->
|
|
|
|
|
+ li [ class "py-2 text-white flex gap-2 items-center space-between w-full" ] <|
|
|
|
|
|
+ case Dict.get s model.sets of
|
|
|
|
|
+ Just setStatus ->
|
|
|
|
|
+ [ span [ class "grow" ] [ text (String.toUpper s) ]
|
|
|
|
|
+ , viewLoadStatus s setStatus
|
|
|
|
|
+ ]
|
|
|
|
|
+
|
|
|
|
|
+ Nothing ->
|
|
|
|
|
+ [ text "Loading..." ]
|
|
|
|
|
+ )
|
|
|
|
|
+ (Dict.keys model.sets)
|
|
|
|
|
+ )
|
|
|
|
|
+ ]
|
|
|
|
|
+ ]
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
viewReady : ReadyModel -> Html Msg
|
|
viewReady : ReadyModel -> Html Msg
|
|
|
viewReady model =
|
|
viewReady model =
|
|
|
div [ class "grid grid-cols-12 gap-6 h-full bg-slate-100" ]
|
|
div [ class "grid grid-cols-12 gap-6 h-full bg-slate-100" ]
|
|
@@ -698,3 +873,21 @@ viewKeyedCard model wasChosen { name, frontImage, backImage } =
|
|
|
, viewFocusStat focusStat
|
|
, viewFocusStat focusStat
|
|
|
]
|
|
]
|
|
|
)
|
|
)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+subscriptions : Model -> Sub Msg
|
|
|
|
|
+subscriptions _ =
|
|
|
|
|
+ receiveDoesSetHaveLocalData PortReceiveDoesSetHaveLocalData
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+-- PORTS
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+port sendDoesSetHaveLocalData : String -> Cmd msg
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+port receiveDoesSetHaveLocalData : (String -> msg) -> Sub msg
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+port sendSaveLocalData : Encode.Value -> Cmd msg
|