1
0

4 Коммиты 4d2a94be31 ... 8d74d8a701

Автор SHA1 Сообщение Дата
  Cadel Watson 8d74d8a701 Add sorting in card explorer 4 месяцев назад
  Cadel Watson 58de406cc8 Support deleting local data 4 месяцев назад
  Cadel Watson a869a6334d Add card sorting 4 месяцев назад
  Cadel Watson a1e4bd2949 Add card explorer 4 месяцев назад
6 измененных файлов с 1040 добавлено и 18 удалено
  1. 20 0
      js/app.js
  2. 752 13
      package-lock.json
  3. 1 0
      package.json
  4. 64 0
      src/Card.elm
  5. 24 1
      src/Database.elm
  6. 179 4
      src/Main.elm

+ 20 - 0
js/app.js

@@ -20,6 +20,20 @@ function getSetData(db, setCode, callback) {
     };
 }
 
+function deleteSetData(db, setCode, callback) {
+    const transaction = db.transaction(["sets"], "readwrite");
+    const objectStore = transaction.objectStore("sets");
+    const request = objectStore.delete(setCode);
+
+    request.onerror = (event) => {
+        alert("Database error")
+    };
+
+    request.onsuccess = (event) => {
+        callback(setCode)
+    }
+}
+
 function saveSetData(db, setData) {
     const transaction = db.transaction(["sets"], "readwrite");
 
@@ -67,6 +81,8 @@ openDBRequest.onsuccess = (event) => {
             }
         });
 
+        console.log(app.ports);
+
         app.ports.sendDoesSetHaveLocalData.subscribe((setCode) => {
             getSetData(database, setCode, (data) => {
                 app.ports.receiveDoesSetHaveLocalData.send(JSON.stringify(data));
@@ -77,6 +93,10 @@ openDBRequest.onsuccess = (event) => {
             saveSetData(database, setData);
         })
 
+        app.ports.sendDeleteLocalData.subscribe((setCode) => {
+            deleteSetData(database, setCode, (setCode) => app.ports.receiveDidDeleteLocalData.send(setCode))
+        })
+
     })
 };
 

Разница между файлами не показана из-за своего большого размера
+ 752 - 13
package-lock.json


+ 1 - 0
package.json

@@ -15,6 +15,7 @@
   },
   "dependencies": {
     "elm-format": "^0.8.7",
+    "elm-review": "^2.13.3",
     "elm-test": "^0.19.1-revision12"
   }
 }

+ 64 - 0
src/Card.elm

@@ -7,15 +7,18 @@ module Card exposing
     , ManaColor(..)
     , ManaCost(..)
     , Power(..)
+    , Rarity(..)
     , alpa
     , alsa
     , calculatePerformanceDistributions
+    , colorsSortOrder
     , gihwr
     , iwd
     , manaCostToSymbol
     , parseManaCost
     , parsePower
     , pickRate
+    , raritySortOrder
     )
 
 import Parser as P exposing ((|.), (|=), Parser, Trailing(..))
@@ -48,6 +51,14 @@ type Power
     | VariablePower
 
 
+type Rarity
+    = Common
+    | Uncommon
+    | Rare
+    | Mythic
+    | NoRarity
+
+
 type alias CardData =
     { details : CardDetails
     , performance : CardPerformanceData
@@ -66,6 +77,7 @@ type alias CardDetails =
     , rawManaCost : String
     , manaCost : Maybe (List ManaCost)
     , imageUrl : String
+    , rarity : Rarity
     }
 
 
@@ -399,3 +411,55 @@ powerP =
         , constantPlusVariablePowerP
         , constantPowerP
         ]
+
+
+raritySortOrder : Rarity -> Int
+raritySortOrder r =
+    case r of
+        Mythic ->
+            0
+
+        Rare ->
+            1
+
+        Uncommon ->
+            2
+
+        Common ->
+            3
+
+        NoRarity ->
+            4
+
+
+colorsSortOrder : List ManaColor -> Int
+colorsSortOrder cs =
+    case cs of
+        -- Colorless
+        [] ->
+            5
+
+        -- Monocolor
+        [ x ] ->
+            case x of
+                Red ->
+                    0
+
+                Green ->
+                    1
+
+                Blue ->
+                    2
+
+                Black ->
+                    3
+
+                White ->
+                    4
+
+                Colorless ->
+                    5
+
+        -- Multicolor
+        _ ->
+            6

+ 24 - 1
src/Database.elm

@@ -1,6 +1,6 @@
 module Database exposing (Database, decode, decoder, encode, fromCardData, get, getAll)
 
-import Card exposing (CardData, CardDetails, CardPerformanceData, CardType(..), ManaColor(..), Power(..), parseManaCost, parsePower)
+import Card exposing (CardData, CardDetails, CardPerformanceData, CardType(..), ManaColor(..), Power(..), Rarity(..), parseManaCost, parsePower)
 import Dict exposing (Dict)
 import Json.Decode as Decode exposing (Decoder, decodeString)
 import Json.Decode.Pipeline exposing (custom, optional, required)
@@ -278,6 +278,7 @@ decodeCardDetails =
                         )
                 )
             |> required "image_uris" (Decode.field "large" Decode.string)
+            |> optional "rarity" decodeRarity NoRarity
         )
 
 
@@ -391,3 +392,25 @@ decodeCardType =
                 else
                     Other
             )
+
+
+decodeRarity : Decoder Rarity
+decodeRarity =
+    Decode.string
+        |> Decode.map
+            (\r ->
+                if String.contains "mythic" r then
+                    Mythic
+
+                else if String.contains "rare" r then
+                    Rare
+
+                else if String.contains "uncommon" r then
+                    Uncommon
+
+                else if String.contains "common" r then
+                    Common
+
+                else
+                    NoRarity
+            )

+ 179 - 4
src/Main.elm

@@ -2,7 +2,7 @@ port module Main exposing (..)
 
 import API
 import Browser exposing (Document)
-import Card exposing (CardData, CardPerformanceDistributions, calculatePerformanceDistributions, manaCostToSymbol)
+import Card exposing (CardData, CardPerformanceDistributions, CardType(..), calculatePerformanceDistributions, colorsSortOrder, manaCostToSymbol, raritySortOrder)
 import Chart as C
 import Chart.Attributes as CA
 import Components.Button as Button
@@ -37,6 +37,7 @@ main =
 type Model
     = ChooseSet ChooseSetModel
     | Ready ReadyModel
+    | CardExplorer CardExplorerModel
     | Error ErrorModel
 
 
@@ -53,6 +54,12 @@ type FocusStat
     | FocusIWD
 
 
+type SortOrder
+    = SortOrderDefault
+    | SortOrderRarity
+    | SortOrderName
+
+
 type alias ToolboxAccordion =
     { cmc : Bool, signals : Bool, signalsDelta : Bool, deckList : Bool }
 
@@ -62,6 +69,7 @@ type SetLoadStatus
     | NoLocalData
     | HasLocalData Database.Database
     | FetchingRemoteData
+    | DeletingLocalData
 
 
 type alias ChooseSetModel =
@@ -83,6 +91,15 @@ type alias ReadyModel =
     }
 
 
+type alias CardExplorerModel =
+    { database : Database.Database
+    , highlighted : Maybe CardData
+    , flipHighlighted : Bool
+    , performanceDistributions : CardPerformanceDistributions
+    , sortOrder : SortOrder
+    }
+
+
 type alias ErrorModel =
     { error : String
     }
@@ -117,6 +134,7 @@ type Msg
     | Highlight String
     | FlipHighlightedCard
     | SetFocusStat FocusStat
+    | SetSortOrder SortOrder
     | SetDeckProgress DeckProgress
     | ToggleCMCChart
     | ToggleSignalsChart
@@ -126,8 +144,11 @@ type Msg
     | IOGotSets (Result String (List String))
     | IOFetchSetData String
     | IOGotSetData (Result String ( String, Maybe Database.Database ))
+    | IODeleteSetData String -- Delete by set code
+    | IOGotDeleteSetData String -- Successful deletion by set code
     | PortReceiveDoesSetHaveLocalData String
     | StartDraft String Database.Database
+    | OpenCardExplorer String Database.Database
 
 
 startDraft : ChooseSetModel -> Database.Database -> ( Model, Cmd Msg )
@@ -157,6 +178,19 @@ startDraft initFlags database =
             ( Error { error = "Error decoding draft data: " ++ err }, Cmd.none )
 
 
+openCardExplorer : ChooseSetModel -> Database.Database -> ( Model, Cmd Msg )
+openCardExplorer initFlags database =
+    ( CardExplorer
+        { database = database
+        , performanceDistributions = calculatePerformanceDistributions (Database.getAll database)
+        , highlighted = Nothing
+        , flipHighlighted = False
+        , sortOrder = SortOrderDefault
+        }
+    , Cmd.none
+    )
+
+
 update : Msg -> Model -> ( Model, Cmd Msg )
 update msg model =
     case model of
@@ -165,6 +199,9 @@ update msg model =
                 StartDraft setCode database ->
                     startDraft mdl database
 
+                OpenCardExplorer setCode database ->
+                    openCardExplorer mdl database
+
                 IOGotSets (Ok remoteData) ->
                     -- Merge any new sets into the local sets
                     let
@@ -226,6 +263,16 @@ update msg model =
                     , API.getSetData setCode IOGotSetData
                     )
 
+                IODeleteSetData setCode ->
+                    ( ChooseSet { mdl | sets = Dict.insert setCode DeletingLocalData mdl.sets }
+                    , sendDeleteLocalData (Encode.string setCode)
+                    )
+
+                IOGotDeleteSetData setCode ->
+                    ( ChooseSet { mdl | sets = Dict.insert setCode NoLocalData mdl.sets }
+                    , Cmd.none
+                    )
+
                 IOGotSetData (Ok ( setCode, Just database )) ->
                     ( ChooseSet { mdl | sets = Dict.insert setCode (HasLocalData database) mdl.sets }
                     , sendSaveLocalData (Database.encode ( setCode, database ))
@@ -260,6 +307,9 @@ update msg model =
                 SetFocusStat stat ->
                     ( Ready { mdl | focusStat = stat }, Cmd.none )
 
+                SetSortOrder _ ->
+                    ( Ready mdl, Cmd.none )
+
                 SetDeckProgress progress ->
                     ( Ready { mdl | deckProgress = progress }, Cmd.none )
 
@@ -303,12 +353,38 @@ update msg model =
                 IOFetchSetData _ ->
                     ( Ready mdl, Cmd.none )
 
+                IODeleteSetData setCode ->
+                    ( Ready mdl, Cmd.none )
+
+                IOGotDeleteSetData setCode ->
+                    ( Ready mdl, Cmd.none )
+
                 PortReceiveDoesSetHaveLocalData _ ->
                     ( Ready mdl, Cmd.none )
 
                 StartDraft _ _ ->
                     ( Ready mdl, Cmd.none )
 
+                OpenCardExplorer _ _ ->
+                    ( Ready mdl, Cmd.none )
+
+        CardExplorer mdl ->
+            case msg of
+                Highlight card ->
+                    ( CardExplorer
+                        { mdl
+                            | highlighted = Database.get card mdl.database
+                            , flipHighlighted = False
+                        }
+                    , Cmd.none
+                    )
+
+                SetSortOrder sortOrder ->
+                    ( CardExplorer { mdl | sortOrder = sortOrder }, Cmd.none )
+
+                _ ->
+                    ( CardExplorer mdl, Cmd.none )
+
         Error mdl ->
             ( Error mdl, Cmd.none )
 
@@ -324,6 +400,9 @@ view model =
             Ready mdl ->
                 viewReady mdl
 
+            CardExplorer mdl ->
+                viewCardExplorer mdl
+
             Error mdl ->
                 viewError mdl
         ]
@@ -342,11 +421,18 @@ viewChooseSet model =
                 CheckingLocalData ->
                     text "Loading..."
 
+                DeletingLocalData ->
+                    text "Deleting..."
+
                 NoLocalData ->
                     Button.make "Download" (IOFetchSetData setCode) |> Button.view
 
                 HasLocalData database ->
-                    Button.make "Open" (StartDraft setCode database) |> Button.view
+                    div [ class "flex gap-2" ]
+                        [ Button.make "Explore" (OpenCardExplorer setCode database) |> Button.view
+                        , Button.make "View draft" (StartDraft setCode database) |> Button.view
+                        , Button.make "Delete" (IODeleteSetData setCode) |> 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" ]
@@ -378,6 +464,14 @@ viewReady model =
         ]
 
 
+viewCardExplorer : CardExplorerModel -> Html Msg
+viewCardExplorer model =
+    div [ class "grid grid-cols-12 gap-6 h-full bg-slate-100" ]
+        [ viewAllCards model
+        , viewHighlightedCard model
+        ]
+
+
 viewSidebar : ReadyModel -> Html Msg
 viewSidebar model =
     div [ class "col-span-2 p-6 bg-slate-600" ]
@@ -697,7 +791,79 @@ viewDraft model =
         ]
 
 
-viewHighlightedCard : ReadyModel -> Html Msg
+viewAllCards : CardExplorerModel -> Html Msg
+viewAllCards model =
+    let
+        allCards : List CardData
+        allCards =
+            Database.getAll model.database
+                |> (case model.sortOrder of
+                        SortOrderDefault ->
+                            List.sortBy
+                                (\c ->
+                                    ( if
+                                        c.details.cardType
+                                            /= Land
+                                      then
+                                        0
+
+                                      else
+                                        1
+                                    , colorsSortOrder
+                                        c.details.colors
+                                    , raritySortOrder c.details.rarity
+                                    )
+                                )
+
+                        SortOrderRarity ->
+                            List.sortBy (\c -> raritySortOrder c.details.rarity)
+
+                        SortOrderName ->
+                            List.sortBy (\c -> c.details.name)
+                   )
+
+        viewCard : CardData -> ( String, Html Msg )
+        viewCard card =
+            ( card.details.name
+            , div
+                [ classList
+                    [ ( "relative border-4 hover:border-4 hover:border-yellow-500", True )
+                    ]
+                , Events.onMouseEnter (Highlight card.details.name)
+                ]
+                [ img [ src card.details.imageUrl, alt card.details.name ] []
+                ]
+            )
+
+        viewSortOrderButton name sortOrder =
+            button
+                [ onClick (SetSortOrder sortOrder)
+                , classList
+                    [ ( "rounded text-white font-medium p-2 shadow mr-2 mb-2", True )
+                    , ( "bg-slate-300 text-slate-900 shadow-inset", model.sortOrder == sortOrder )
+                    , ( "bg-slate-900", model.sortOrder /= sortOrder )
+                    ]
+                ]
+                [ text name
+                ]
+    in
+    div [ class "col-span-10 shadow-xl bg-slate-600 p-6 h-full overflow-y-scroll" ]
+        [ div []
+            [ viewSortOrderButton "Sort: default" SortOrderDefault
+            , viewSortOrderButton "Sort: rarity" SortOrderRarity
+            , viewSortOrderButton "Sort: name" SortOrderName
+            ]
+        , -- Making this a keyed node forces Elm to recreate each card when the card name changes,
+          -- so the old image doesn't hang around during loading of the new card image
+          div [ class "flex flex-col space-between col-span-8 " ]
+            [ Keyed.node "div"
+                [ class "flex-grow grid grid-cols-8 auto-rows-min gap-6 p-6" ]
+                (List.map viewCard allCards)
+            ]
+        ]
+
+
+viewHighlightedCard : { a | highlighted : Maybe CardData, flipHighlighted : Bool, performanceDistributions : CardPerformanceDistributions } -> Html Msg
 viewHighlightedCard model =
     div [ class "col-span-2 shadow-xl bg-slate-600 p-6" ]
         [ case model.highlighted of
@@ -877,7 +1043,10 @@ viewKeyedCard model wasChosen { name, frontImage, backImage } =
 
 subscriptions : Model -> Sub Msg
 subscriptions _ =
-    receiveDoesSetHaveLocalData PortReceiveDoesSetHaveLocalData
+    Sub.batch
+        [ receiveDoesSetHaveLocalData PortReceiveDoesSetHaveLocalData
+        , receiveDidDeleteLocalData IOGotDeleteSetData
+        ]
 
 
 
@@ -891,3 +1060,9 @@ port receiveDoesSetHaveLocalData : (String -> msg) -> Sub msg
 
 
 port sendSaveLocalData : Encode.Value -> Cmd msg
+
+
+port sendDeleteLocalData : Encode.Value -> Cmd msg
+
+
+port receiveDidDeleteLocalData : (String -> msg) -> Sub msg

Некоторые файлы не были показаны из-за большого количества измененных файлов