1
0

4 کامیت‌ها 4d2a94be31 ... 8d74d8a701

نویسنده SHA1 پیام تاریخ
  Cadel Watson 8d74d8a701 Add sorting in card explorer 10 ماه پیش
  Cadel Watson 58de406cc8 Support deleting local data 10 ماه پیش
  Cadel Watson a869a6334d Add card sorting 10 ماه پیش
  Cadel Watson a1e4bd2949 Add card explorer 10 ماه پیش
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

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است