소스 검색

Try to read set data from IndexedDB

Cadel Watson 1 년 전
부모
커밋
37d1ce9e01
3개의 변경된 파일154개의 추가작업 그리고 36개의 파일을 삭제
  1. 51 8
      js/app.js
  2. 19 12
      src/Database.elm
  3. 84 16
      src/Main.elm

+ 51 - 8
js/app.js

@@ -4,11 +4,54 @@ import cardRatings from "../data/sets/mkm/card-ratings-all.json";
 
 import {Elm} from '../src/Main.elm';
 
-Elm.Main.init({
-    node: document.getElementById('myapp'),
-    flags: {
-        setData: JSON.stringify(setData),
-        draftData: JSON.stringify(draftData),
-        cardRatings: JSON.stringify(cardRatings)
-    }
-});
+function getSetData(db, setCode, callback) {
+    const transaction = db.transaction(["sets"], "readwrite");
+
+    const objectStore = transaction.objectStore("sets");
+    const request = objectStore.get(setCode);
+
+    request.onerror = (event) => {
+        alert("Database error")
+    };
+    request.onsuccess = (event) => {
+        if (request.result === undefined) {
+            callback({code: setCode, data: null});
+        } else {
+            callback({code: setCode, data: request.result.data});
+        }
+    };
+}
+
+const openDBRequest = indexedDB.open("set_database", 2);
+
+openDBRequest.onerror = (event) => {
+    alert("Could not open browser database");
+};
+
+openDBRequest.onupgradeneeded = (event) => {
+    console.log("Upgrading")
+    const database = event.target.result;
+
+    const objectStore = database.createObjectStore("sets", {keyPath: "code"});
+}
+
+openDBRequest.onsuccess = (event) => {
+    const database = event.target.result;
+    const app = Elm.Main.init({
+        node: document.getElementById('myapp'),
+        flags: {
+            setData: JSON.stringify(setData),
+            draftData: JSON.stringify(draftData),
+            cardRatings: JSON.stringify(cardRatings)
+        }
+    });
+    console.log(app);
+    console.log(app.ports)
+
+    app.ports.sendDoesSetHaveLocalData.subscribe((setCode) => {
+        getSetData(database, setCode, (data) => {
+            app.ports.receiveDoesSetHaveLocalData.send(JSON.stringify(data));
+        })
+    });
+};
+

+ 19 - 12
src/Database.elm

@@ -21,20 +21,26 @@ getAll (Database db) =
     Dict.values db
 
 
-decode : String -> String -> Result String Database
-decode setData draftData =
-    case ( decodeString decodeSetData setData, decodeString decodePerformanceData draftData ) of
-        ( Ok set, Ok draft ) ->
-            Ok (createDatabase draft set |> Database)
-
-        ( Err err, _ ) ->
-            Err <| Decode.errorToString err
-
-        ( _, Err err ) ->
-            Err <| Decode.errorToString err
+decode : String -> Result String ( String, Maybe Database )
+decode setData =
+    let
+        decoder : Decoder ( String, Maybe Database )
+        decoder =
+            Decode.map2 pair
+                (Decode.field "code" Decode.string)
+                (Decode.field "data"
+                    (Decode.nullable
+                        (Decode.map2 createDatabase
+                            (Decode.field "ratings" decodePerformanceData)
+                            (Decode.field "cards" decodeSetData)
+                        )
+                    )
+                )
+    in
+    decodeString decoder setData |> Result.mapError Decode.errorToString
 
 
-createDatabase : Dict String CardPerformanceData -> Dict String CardDetails -> Dict String CardData
+createDatabase : Dict String CardPerformanceData -> Dict String CardDetails -> Database
 createDatabase performanceData detailsData =
     Dict.merge
         (\_ _ cardData -> cardData)
@@ -43,6 +49,7 @@ createDatabase performanceData detailsData =
         performanceData
         detailsData
         Dict.empty
+        |> Database
 
 
 decodePerformanceData : Decoder (Dict String CardPerformanceData)

+ 84 - 16
src/Main.elm

@@ -1,4 +1,4 @@
-module Main exposing (..)
+port module Main exposing (..)
 
 import API
 import Browser exposing (Document)
@@ -7,12 +7,15 @@ import Chart as C
 import Chart.Attributes as CA
 import Database
 import Deck
+import Dict exposing (Dict)
 import Draft exposing (Draft)
 import Html exposing (Html, a, button, div, img, li, p, span, text, ul)
 import Html.Attributes exposing (alt, class, classList, disabled, src)
 import Html.Events as Events exposing (onClick, onMouseEnter)
 import Html.Keyed as Keyed
 import Icon exposing (chevronDown, chevronUp)
+import Json.Decode exposing (decodeString)
+import Json.Encode as Encode
 import List.Extra as List
 import Round
 import Signals
@@ -26,7 +29,7 @@ main =
         { init = init
         , update = update
         , view = view
-        , subscriptions = \_ -> Sub.none
+        , subscriptions = subscriptions
         }
 
 
@@ -53,11 +56,18 @@ type alias ToolboxAccordion =
     { cmc : Bool, signals : Bool, signalsDelta : Bool, deckList : Bool }
 
 
+type SetLoadStatus
+    = CheckingLocalData
+    | HasLocalData Database.Database
+    | FetchingRemoteData
+    | SavingRemoteData
+
+
 type alias ChooseSetModel =
     { draftData : String
     , cardRatings : String
     , setData : String
-    , sets : Maybe (List String)
+    , sets : Maybe (Dict String SetLoadStatus)
     }
 
 
@@ -104,12 +114,13 @@ type Msg
     | ToggleDeckList
     | SetDeckSortMethod Deck.DeckSortMethod
     | IOGotSets (Result String (List String))
+    | PortReceiveDoesSetHaveLocalData String
 
 
-startDraft : ChooseSetModel -> ( Model, Cmd Msg )
-startDraft initFlags =
-    case ( Draft.decode initFlags.draftData, Database.decode initFlags.setData initFlags.cardRatings ) of
-        ( Ok draftData, Ok database ) ->
+startDraft : ChooseSetModel -> String -> ( Model, Cmd Msg )
+startDraft initFlags setCode =
+    case ( Maybe.andThen (Dict.get setCode) initFlags.sets, Draft.decode initFlags.draftData ) of
+        ( Just (HasLocalData database), Ok draftData ) ->
             ( Ready
                 { draft = draftData
                 , database = database
@@ -129,14 +140,11 @@ startDraft initFlags =
             , Cmd.none
             )
 
-        ( Err err, Ok _ ) ->
-            ( Error { error = "Error decoding draft data: " ++ err }, Cmd.none )
-
-        ( Ok _, Err err ) ->
-            ( Error { error = "Error decoding set data: " ++ err }, Cmd.none )
+        ( _, Ok _ ) ->
+            ( Error { error = "No set data in init flags" }, Cmd.none )
 
-        ( Err draftError, Err databaseError ) ->
-            ( Error { error = "Error decoding draft data: " ++ draftError ++ ", set data: " ++ databaseError }, Cmd.none )
+        ( _, Err err ) ->
+            ( Error { error = "Error decoding draft data: " ++ err }, Cmd.none )
 
 
 update : Msg -> Model -> ( Model, Cmd Msg )
@@ -145,11 +153,50 @@ update msg model =
         ChooseSet mdl ->
             case msg of
                 IOGotSets (Ok sets) ->
-                    ( ChooseSet { mdl | sets = Just sets }, Cmd.none )
+                    let
+                        setStatus : Dict String SetLoadStatus
+                        setStatus =
+                            sets
+                                |> List.map (\s -> ( s, CheckingLocalData ))
+                                |> Dict.fromList
+
+                        setCmds : List (Cmd Msg)
+                        setCmds =
+                            List.map
+                                (\s -> sendDoesSetHaveLocalData s)
+                                sets
+                    in
+                    ( ChooseSet { mdl | sets = Just setStatus }
+                    , Cmd.batch setCmds
+                    )
 
                 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 FetchingRemoteData
+                    in
+                    case Database.decode unparsedData of
+                        Ok ( setCode, Just db ) ->
+                            ( ChooseSet { mdl | sets = Maybe.map (markSetDataLoaded setCode db) mdl.sets }, Cmd.none )
+
+                        Ok ( setCode, Nothing ) ->
+                            ( ChooseSet { mdl | sets = Maybe.map (markSetDataNotAvailable setCode) mdl.sets }, Cmd.none )
+
+                        Err e ->
+                            ( Error { error = "Error decoding local set data (" ++ e ++ ")" }, Cmd.none )
+
                 _ ->
                     ( ChooseSet mdl, Cmd.none )
 
@@ -213,6 +260,9 @@ update msg model =
                 IOGotSets _ ->
                     ( Ready mdl, Cmd.none )
 
+                PortReceiveDoesSetHaveLocalData _ ->
+                    ( Ready mdl, Cmd.none )
+
         Error mdl ->
             ( Error mdl, Cmd.none )
 
@@ -240,7 +290,7 @@ viewChooseSet model =
         [ div [ class "max-w-2xl max-h-2xl" ]
             [ case model.sets of
                 Just sets ->
-                    ul [] (List.map (\s -> li [] [ text s ]) sets)
+                    ul [] (List.map (\s -> li [] [ text s ]) (Dict.keys sets))
 
                 Nothing ->
                     p [] [ text "Loading..." ]
@@ -752,3 +802,21 @@ viewKeyedCard model wasChosen { name, frontImage, backImage } =
         , 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