Compare commits

..

No commits in common. "e2a11ae0d1663b11882fdf08de243b919bd070d4" and "bf8e33ee1cfe9a83b17cc3bf09cbe769da7db3f4" have entirely different histories.

4 changed files with 62 additions and 413 deletions

View File

@ -1,23 +1,22 @@
module Main exposing (main) module Main exposing (main)
import Api
import Browser
import Element exposing (Element) import Element exposing (Element)
import Element.Background
import GameList exposing (Game, GameList) import GameList exposing (Game, GameList)
import Json.Decode as D import Http
import Layout import ScreenSize exposing (ScreenSize)
import Material.Icons as Icons import Theme
import Program
import Widget.Icon
main : Program () Model Msg
main = main =
Program.document Browser.document
{ flagsDecoder = D.string { init = init
, headers = headers
, init = init
, subscriptions = subscriptions
, title = always "Coolio!" -- TODO
, update = update
, view = view , view = view
, update = update
, subscriptions = subscriptions
} }
@ -27,8 +26,10 @@ main =
type alias Model = type alias Model =
{ baseUrl : String { baseUrl : String
, flavor : Theme.Flavor
, games : GameList , games : GameList
, screen : Screen , screen : Screen
, size : ScreenSize
} }
@ -41,25 +42,25 @@ type Screen
type Msg type Msg
= OnGameList GameList.Msg = OnGameList GameList.Msg
| OnScreen Screen | OnScreen Screen
| OnScreenSize ScreenSize
init : Result D.Error String -> ( Model, Cmd Msg ) init : () -> ( Model, Cmd Msg )
init baseUrl = init () =
let let
( gmdl, gmsg ) = ( gmdl, gmsg ) =
GameList.init {} GameList.init {}
in in
( { baseUrl = ( { baseUrl = "http://localhost:5000"
case baseUrl of , flavor = Theme.Latte
Ok s ->
s
Err _ ->
"http://localhost:5000"
, games = gmdl , games = gmdl
, screen = ViewGameSelectionMenu , screen = ViewGameSelectionMenu
, size = ScreenSize.init
} }
, Cmd.batch
[ ScreenSize.updateScreenSize OnScreenSize
, Cmd.map OnGameList gmsg , Cmd.map OnGameList gmsg
]
) )
@ -78,6 +79,9 @@ update msg model =
OnScreen screen -> OnScreen screen ->
( { model | screen = screen }, Cmd.none ) ( { model | screen = screen }, Cmd.none )
OnScreenSize size ->
( { model | size = size }, Cmd.none )
-- SUBSCRIPTIONS -- SUBSCRIPTIONS
@ -85,50 +89,59 @@ update msg model =
subscriptions : Model -> Sub Msg subscriptions : Model -> Sub Msg
subscriptions model = subscriptions model =
Sub.map OnGameList (GameList.subscriptions model.games) Sub.batch
[ ScreenSize.onResize OnScreenSize
, Sub.map OnGameList (GameList.subscriptions model.games)
]
-- VIEW -- VIEW
headers : Model -> List { icon : Widget.Icon.Icon Msg, onPress : Msg } view : Model -> Browser.Document Msg
headers model = view model =
{ title =
case model.screen of case model.screen of
ViewCreateGame -> ViewCreateGame ->
[ { icon = Layout.iconAsIcon Icons.arrow_back, onPress = OnScreen ViewGameSelectionMenu } "Create Game | Bot-Man-Toe"
]
ViewGameSelectionMenu -> ViewGameSelectionMenu ->
[] "Menu | Bot-Man-Toe"
ViewGame _ -> ViewGame _ ->
[ { icon = Layout.iconAsIcon Icons.arrow_back, onPress = OnScreen ViewGameSelectionMenu } "Replay | Bot-Man-Toe"
, body =
viewScreen model
|> Element.layout
[ Element.Background.color (Theme.baseUI model.flavor)
] ]
|> List.singleton
}
view : Program.ViewBox Model -> Element Msg viewScreen : Model -> Element Msg
view data = viewScreen model =
case data.model.screen of case model.screen of
ViewCreateGame -> ViewCreateGame ->
Element.text "Create game menu!" Element.text "Create game menu!"
ViewGameSelectionMenu -> ViewGameSelectionMenu ->
GameList.viewSelection GameList.viewSelection
{ flavor = data.flavor { flavor = model.flavor
, height = data.size.height , height = model.size.height
, model = data.model.games , model = model.games
, onCreateGame = OnScreen ViewCreateGame , onCreateGame = OnScreen ViewCreateGame
, onNavigateToGame = OnScreen << ViewGame , onNavigateToGame = OnScreen << ViewGame
, width = data.size.width , width = model.size.width
} }
ViewGame game -> ViewGame game ->
GameList.viewGame GameList.viewGame
{ flavor = data.flavor { flavor = model.flavor
, game = game , game = game
, height = data.size.height , height = model.size.height
, onNavigateBack = OnScreen ViewGameSelectionMenu , onNavigateBack = OnScreen ViewGameSelectionMenu
, toMsg = OnGameList , toMsg = OnGameList
, width = data.size.width , width = model.size.width
} }

View File

@ -6,6 +6,7 @@ module Match exposing (..)
import Api import Api
import Duration exposing (Duration) import Duration exposing (Duration)
import Element exposing (Element) import Element exposing (Element)
import Element.Background
import Http import Http
import Json.Decode as D import Json.Decode as D
import Layout import Layout
@ -251,5 +252,5 @@ viewMenu :
, width : Quantity Int Pixels , width : Quantity Int Pixels
} }
-> Element (Msg gameState) -> Element (Msg gameState)
viewMenu _ = viewMenu data =
Element.none Element.none

View File

@ -1,300 +0,0 @@
module Program exposing (Px, ViewBox, document, element)
import Browser
import Color
import Element exposing (Element)
import Element.Background
import Element.Events
import Element.Font
import Html
import Json.Decode as D
import Layout
import Pixels exposing (Pixels)
import Quantity exposing (Quantity)
import ScreenSize exposing (ScreenSize)
import Svg
import Svg.Attributes
import Theme
import Widget.Icon
type alias Model model =
{ content : model
, flavor : Theme.Flavor
, size : ScreenSize
}
type Msg msg
= OnContent msg
| OnFlavor Theme.Flavor
| OnScreenSize ScreenSize
type alias Px =
Quantity Int Pixels
type alias ViewBox model =
{ flavor : Theme.Flavor, model : model, size : ScreenSize }
element :
{ flagsDecoder : D.Decoder flags
, init : Result D.Error flags -> ( model, Cmd msg )
, subscriptions : model -> Sub msg
, update : msg -> model -> ( model, Cmd msg )
, view : ViewBox model -> Element msg
}
-> Program D.Value (Model model) (Msg msg)
element data =
Browser.element
{ init = init { f = data.init, d = data.flagsDecoder }
, subscriptions = subscriptions data.subscriptions
, update = update data.update
, view =
view
{ body = data.view
, headers = always []
}
}
document :
{ flagsDecoder : D.Decoder flags
, headers : model -> List { icon : Widget.Icon.Icon msg, onPress : msg }
, init : Result D.Error flags -> ( model, Cmd msg )
, subscriptions : model -> Sub msg
, title : model -> String
, update : msg -> model -> ( model, Cmd msg )
, view : ViewBox model -> Element msg
}
-> Program D.Value (Model model) (Msg msg)
document data =
Browser.document
{ init = init { f = data.init, d = data.flagsDecoder }
, subscriptions = subscriptions data.subscriptions
, update = update data.update
, view =
\model ->
{ title = data.title model.content
, body = [ view { body = data.view, headers = data.headers } model ]
}
}
-- INIT
init :
{ f : Result D.Error flags -> ( model, Cmd msg )
, d : D.Decoder flags
}
-> D.Value
-> ( Model model, Cmd (Msg msg) )
init data blob =
case data.f (D.decodeValue data.d blob) of
( mdl, msg ) ->
( { content = mdl
, flavor = Theme.Frappe
, size = ScreenSize.init
}
, Cmd.batch
[ Cmd.map OnContent msg
, ScreenSize.updateScreenSize OnScreenSize
]
)
-- UPDATE
update :
(msg -> model -> ( model, Cmd msg ))
-> Msg msg
-> Model model
-> ( Model model, Cmd (Msg msg) )
update f msg model =
case msg of
OnContent m ->
case f m model.content of
( newMdl, newMsg ) ->
( { model | content = newMdl }
, Cmd.map OnContent newMsg
)
OnFlavor flavor ->
( { model | flavor = flavor }, Cmd.none )
OnScreenSize size ->
( { model | size = size }, Cmd.none )
-- SUBSCRIPTIONS
subscriptions : (model -> Sub msg) -> Model model -> Sub (Msg msg)
subscriptions f model =
Sub.batch
[ Sub.map OnContent <| f model.content
, ScreenSize.onResize OnScreenSize
]
-- VIEW
view :
{ body : ViewBox model -> Element msg
, headers : model -> List { icon : Widget.Icon.Icon msg, onPress : msg }
}
-> Model model
-> Html.Html (Msg msg)
view data model =
let
preferredNavBarHeight =
Pixels.pixels 40
showNavBar =
preferredNavBarHeight
|> Quantity.multiplyBy 6
|> Quantity.lessThanOrEqualTo model.size.height
contentHeight =
if showNavBar then
model.size.height |> Quantity.minus preferredNavBarHeight
else
model.size.height
in
[ viewNavBar
{ headers = data.headers model.content
, iconHeight = preferredNavBarHeight
, model = model
}
, data.body
{ flavor = model.flavor
, model = model.content
, size = { height = contentHeight, width = model.size.width }
}
|> Element.map OnContent
]
|> Element.column [ Element.width Element.fill ]
|> Element.layout
[ Element.Background.color (Theme.baseUI model.flavor)
, Element.Font.color (Theme.textUI model.flavor)
, Element.width <| Element.px <| Pixels.inPixels model.size.width
]
viewFlavorPicker :
{ currentFlavor : Theme.Flavor
, flavorToPick : Theme.Flavor
, onClick : Theme.Flavor -> msg
, size : Px
}
-> Element msg
viewFlavorPicker data =
Layout.svg
{ aspectRatio = 1 / 1
, height = Pixels.inPixels data.size
, svg =
Svg.circle
[ Svg.Attributes.cx "5"
, Svg.Attributes.cy "5"
, Svg.Attributes.r "4"
, Svg.Attributes.strokeWidth "1"
, Svg.Attributes.fill (Color.toCssString <| Theme.base data.flavorToPick)
, Svg.Attributes.stroke (Color.toCssString <| Theme.crust data.currentFlavor)
]
[]
, viewMinY = 0
, viewMaxY = 10
, viewMinX = 0
, viewMaxX = 10
, width = Pixels.inPixels data.size
}
|> (if data.currentFlavor /= data.flavorToPick then
Element.el [ Element.Events.onClick (data.onClick data.flavorToPick) ]
else
identity
)
viewNavBar :
{ headers : List { icon : Widget.Icon.Icon msg, onPress : msg }
, iconHeight : Px
, model : Model model
}
-> Element (Msg msg)
viewNavBar data =
let
heightAttr =
Quantity.twice data.iconHeight
|> Pixels.inPixels
|> Element.px
|> Element.height
widthAttr =
Quantity.twice data.iconHeight
|> Pixels.inPixels
|> Element.px
|> Element.width
in
Element.row
[ Element.Background.color <| Theme.mantleUI data.model.flavor
, Element.width Element.fill
]
[ data.headers
|> List.map
(viewNavBarIcon
{ flavor = data.model.flavor
, height = Quantity.twice data.iconHeight
, heightIcon = data.iconHeight
}
)
|> Element.row []
, Element.el [ heightAttr, Element.width Element.fill ] Element.none
, [ Theme.Latte, Theme.Frappe, Theme.Macchiato, Theme.Mocha ]
|> List.map
(\flavor ->
viewFlavorPicker
{ currentFlavor = data.model.flavor
, flavorToPick = flavor
, onClick = OnFlavor
, size = data.iconHeight
}
|> Element.el [ Element.centerX, Element.centerY ]
|> Element.el [ heightAttr, widthAttr ]
)
|> Element.row []
]
viewNavBarIcon :
{ flavor : Theme.Flavor
, height : Px
, heightIcon : Px
}
-> { icon : Widget.Icon.Icon msg, onPress : msg }
-> Element (Msg msg)
viewNavBarIcon { flavor, height, heightIcon } { icon, onPress } =
-- TODO: Implement coloring for hover + onclick
icon { color = Theme.text flavor, size = Pixels.inPixels heightIcon }
|> Element.el
[ Element.centerX
, Element.centerY
, Element.height <| Element.px <| Pixels.inPixels heightIcon
, Element.width <| Element.px <| Pixels.inPixels heightIcon
]
|> Element.el
[ Element.Events.onClick onPress
, Element.height <| Element.px <| Pixels.inPixels height
, Element.width <| Element.px <| Pixels.inPixels height
]
|> Element.map OnContent

View File

@ -1,65 +0,0 @@
module Screen.CreateGame exposing (..)
-- MODEL
type alias Model =
{ baseUrl : String
, players : List String
}
type Msg
= OnBaseUrl String
| OnPlayer Int String
| RemovePlayer Int
-- UPDATE
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
OnBaseUrl url ->
( { model | baseUrl = url }, Cmd.none )
OnPlayer n p ->
let
newIndex = List.length model.players == n
newPlayers =
if newIndex && mayCreateNewPlayer model.players then
List.append model.players [ p ]
else
List.indexedMap
(\i player ->
if n == i then
p
else
player
)
model.players
in
( { model | players = newPlayers }, Cmd.none )
RemovePlayer n ->
( { model
| players =
model.players
|> List.indexedMap
(\i player ->
if n == i then
Nothing
else
Just player
)
|> List.filterMap identity
}
, Cmd.none
)
-- SUBSCRIPTIONS
-- VIEW
mayCreateNewPlayer : List String -> Bool
mayCreateNewPlayer =
List.all (not << String.isEmpty)