module Pages.DeckEditor exposing (..) import Browser import Browser.Events import Browser.Navigation import Deck import Element as E import Element.Background as Background import Element.Events as Events import Element.Font as Font import Http import Paginated import Route import Spinner import Symbol import UI import Url import Url.Builder type alias Model = { navigationKey : Browser.Navigation.Key , url : Url.Url , device : E.Device , spinner : Spinner.Model , symbols : Symbol.Table , deck : Deck } type Msg = ViewportChanged UI.Dimensions | SpinnerMsg Spinner.Msg | GotDeck (Result Http.Error Deck.Deck) | GotSymbols Symbol.Table type Deck = Ready Deck.Deck | Loading | NotFound | Failed type alias Grouped = { creatures : List Deck.Card , instants : List Deck.Card , sorceries : List Deck.Card , enchantments : List Deck.Card , lands : List Deck.Card } type alias Group = { label : String, cards : List Deck.Card } groups : List Deck.Card -> List Group groups cards = let last : List a -> Maybe a last xs = List.reverse xs |> List.head typeOf : Deck.Card -> String typeOf card = String.split "—" card.card.typeLine |> List.head |> Maybe.andThen (\types -> String.words types |> last) |> Maybe.withDefault "" isA : String -> Deck.Card -> Bool isA cardType card = typeOf card == cardType isEmpty : Group -> Bool isEmpty group = List.isEmpty group.cards gather : String -> String -> Group gather groupName typeName = List.filter (isA typeName) cards |> List.sortBy (\dc ->(dc.card.cmc, dc.card.name)) |> Group groupName in List.filter (\l -> not <| isEmpty l) [ gather "Creatures" "Creature" , gather "Planeswalkers" "Planeswalker" , gather "Instants" "Instant" , gather "Sorceries" "Sorcery" , gather "Enchantments" "Enchantment" , gather "Artifacts" "Artifact" , gather "Lands" "Land" ] init : Browser.Navigation.Key -> Url.Url -> E.Device -> Symbol.Table -> Int -> ( Model, Cmd Msg ) init key url device symbols deckId = ( { navigationKey = key , url = url , device = device , spinner = Spinner.init , symbols = symbols , deck = Loading } , getDeck deckId ) update : Msg -> Model -> ( Model, Cmd Msg ) update msg model = case msg of ViewportChanged viewport -> ( { model | device = E.classifyDevice viewport } , Cmd.none ) SpinnerMsg msg_ -> ( { model | spinner = Spinner.update msg_ model.spinner }, Cmd.none ) GotDeck (Ok deck) -> ( { model | deck = Ready deck }, Cmd.none ) GotDeck (Err _) -> ( { model | deck = Failed }, Cmd.none ) GotSymbols symbols -> ( { model | symbols = symbols }, Cmd.none ) viewDeck : Symbol.Table -> Deck.Deck -> E.Element Msg viewDeck symbols deck = let viewGroup group = E.column [ E.spacing 10 ] [ E.paragraph [ Font.heavy ] [ UI.title group.label ] , E.wrappedRow [ E.spacing 10 ] <| List.map (\dc -> UI.cardRow { foil = False , subtitle = "x" ++ String.fromInt dc.quantity } [ E.width <| E.px 400, E.clipX, Background.color UI.colors.background ] symbols dc.card ) group.cards ] in E.column [ E.height E.fill, E.centerX, E.spacing 5 ] <| [ E.paragraph [ Font.heavy, Font.size 24, Font.center ] [ UI.title deck.name ] , E.column [ E.height E.fill , E.spacing 10 , Background.color UI.colors.sidebar , E.scrollbarY , E.clipX ] <| List.map viewGroup <| groups deck.cards ] view : Model -> E.Element Msg view model = E.column [ E.width E.fill , E.height E.fill ] [ case model.deck of Ready deck -> viewDeck model.symbols deck Failed -> E.none NotFound -> E.none Loading -> E.el [ E.height E.fill, E.centerX ] <| E.html <| Spinner.view UI.manaSpinner model.spinner , UI.footer <| case model.deck of Ready deck -> UI.text <| String.join " " [ String.fromInt (List.sum <| List.map .quantity deck.cards) , "cards" ] _ -> E.none ] subscriptions : Model -> Sub Msg subscriptions model = Sub.batch [ Browser.Events.onResize (\w h -> ViewportChanged { width = w, height = h }) , Sub.map SpinnerMsg Spinner.subscription ] getDeck : Int -> Cmd Msg getDeck deckId = Http.get { url = Url.Builder.absolute [ "api", "decks", String.fromInt deckId ] [] , expect = Http.expectJson GotDeck Deck.decode }