Implement chapter 4 - part1
- pull photo urls from the server - provide styles.css and list ourselves
This commit is contained in:
parent
fe10054e44
commit
e47f1d0449
6 changed files with 1475 additions and 204 deletions
|
|
@ -1,16 +1,21 @@
|
|||
module PhotoGroove exposing (main)
|
||||
|
||||
import Array exposing (Array)
|
||||
import Browser
|
||||
import Html exposing (Html, button, div, h1, h3, img, input, label, text)
|
||||
import Html.Attributes exposing (..)
|
||||
import Html.Events exposing (onClick)
|
||||
import Http
|
||||
import Random
|
||||
|
||||
|
||||
type Status
|
||||
= Loading
|
||||
| Loaded (List Photo) String
|
||||
| Errored String
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ photos : List Photo
|
||||
, selectedUrl : String
|
||||
{ status : Status
|
||||
, chosenSize : ThumbnailSize
|
||||
}
|
||||
|
||||
|
|
@ -27,51 +32,47 @@ type ThumbnailSize
|
|||
|
||||
initialModel : Model
|
||||
initialModel =
|
||||
{ photos =
|
||||
[ { url = "1.jpeg" }
|
||||
, { url = "2.jpeg" }
|
||||
, { url = "3.jpeg" }
|
||||
]
|
||||
, selectedUrl = "1.jpeg"
|
||||
{ status = Loading
|
||||
, chosenSize = Large
|
||||
}
|
||||
|
||||
|
||||
getPhotoUrl : Int -> String
|
||||
getPhotoUrl id =
|
||||
case Array.get id photoArray of
|
||||
Just photo ->
|
||||
photo.url
|
||||
|
||||
Nothing ->
|
||||
""
|
||||
|
||||
|
||||
photoArray : Array Photo
|
||||
photoArray =
|
||||
Array.fromList initialModel.photos
|
||||
|
||||
|
||||
randomPhotoPicker : Random.Generator Int
|
||||
randomPhotoPicker =
|
||||
Random.int 0 (Array.length photoArray - 1)
|
||||
initialCommand : Cmd Message
|
||||
initialCommand =
|
||||
Http.get
|
||||
{ url = "list"
|
||||
, expect = Http.expectString GotPhotos
|
||||
}
|
||||
|
||||
|
||||
view : Model -> Html Message
|
||||
view model =
|
||||
div [ class "content" ]
|
||||
[ h1 [] [ text "Photo Groove" ]
|
||||
, button [ onClick ClickedSurpriseMe ] [ text "Surprise me!" ]
|
||||
, h3 [] [ text "Thumbnail Size:" ]
|
||||
, div [ id "choose-size" ]
|
||||
(List.map viewSizeChooser [ Small, Medium, Large ])
|
||||
, div
|
||||
[ id "thumbnails"
|
||||
, class (sizeToClass model.chosenSize)
|
||||
]
|
||||
(List.map (viewThumbnail model.selectedUrl) model.photos)
|
||||
, img [ class "large", src (urlPrefix ++ "large/" ++ model.selectedUrl) ] []
|
||||
div [ class "content" ] <|
|
||||
case model.status of
|
||||
Loading ->
|
||||
[]
|
||||
|
||||
Loaded photos selected ->
|
||||
viewLoaded photos selected model.chosenSize
|
||||
|
||||
Errored error ->
|
||||
[ text ("Error: " ++ error) ]
|
||||
|
||||
|
||||
viewLoaded : List Photo -> String -> ThumbnailSize -> List (Html Message)
|
||||
viewLoaded photos selected size =
|
||||
[ h1 [] [ text "Photo Groove" ]
|
||||
, button [ onClick ClickedSurpriseMe ] [ text "Surprise me!" ]
|
||||
, h3 [] [ text "Thumbnail Size:" ]
|
||||
, div [ id "choose-size" ]
|
||||
(List.map viewSizeChooser [ Small, Medium, Large ])
|
||||
, div
|
||||
[ id "thumbnails"
|
||||
, class (sizeToClass size)
|
||||
]
|
||||
(List.map (viewThumbnail selected) photos)
|
||||
, img [ class "large", src (urlPrefix ++ "large/" ++ selected) ] []
|
||||
]
|
||||
|
||||
|
||||
viewThumbnail : String -> Photo -> Html Message
|
||||
|
|
@ -127,23 +128,84 @@ type Message
|
|||
= ClickedThumbnail String
|
||||
| ClickedSurpriseMe
|
||||
| ClickedSize ThumbnailSize
|
||||
| GotSelectedIndex Int
|
||||
| GotRandomPhoto Photo
|
||||
| GotPhotos (Result Http.Error String)
|
||||
|
||||
|
||||
update : Message -> Model -> ( Model, Cmd Message )
|
||||
update msg model =
|
||||
case msg of
|
||||
ClickedThumbnail thumb ->
|
||||
( { model | selectedUrl = thumb }, Cmd.none )
|
||||
( { model | status = selectUrl thumb model.status }, Cmd.none )
|
||||
|
||||
ClickedSurpriseMe ->
|
||||
( model, Random.generate GotSelectedIndex randomPhotoPicker )
|
||||
case model.status of
|
||||
Loaded (photo :: morePhotos) _ ->
|
||||
Random.uniform photo morePhotos
|
||||
|> Random.generate GotRandomPhoto
|
||||
|> Tuple.pair model
|
||||
|
||||
Loaded [] _ ->
|
||||
( model, Cmd.none )
|
||||
|
||||
Loading ->
|
||||
( model, Cmd.none )
|
||||
|
||||
Errored _ ->
|
||||
( model, Cmd.none )
|
||||
|
||||
ClickedSize size ->
|
||||
( { model | chosenSize = size }, Cmd.none )
|
||||
|
||||
GotSelectedIndex idx ->
|
||||
( { model | selectedUrl = getPhotoUrl idx }, Cmd.none )
|
||||
GotRandomPhoto photo ->
|
||||
( { model | status = selectUrl photo.url model.status }, Cmd.none )
|
||||
|
||||
GotPhotos (Ok str) ->
|
||||
case String.split "," str of
|
||||
(x :: _) as urls ->
|
||||
let
|
||||
photos =
|
||||
List.map Photo urls
|
||||
in
|
||||
( { model | status = Loaded photos x }, Cmd.none )
|
||||
|
||||
[] ->
|
||||
( { model | status = Errored ("No photos: " ++ str) }, Cmd.none )
|
||||
|
||||
GotPhotos (Err httpError) ->
|
||||
( { model | status = Errored <| ("Failed to load photos: " ++ httpErrorToString httpError) }, Cmd.none )
|
||||
|
||||
|
||||
selectUrl : String -> Status -> Status
|
||||
selectUrl url status =
|
||||
case status of
|
||||
Loading ->
|
||||
status
|
||||
|
||||
Loaded photos _ ->
|
||||
Loaded photos url
|
||||
|
||||
Errored _ ->
|
||||
status
|
||||
|
||||
|
||||
httpErrorToString : Http.Error -> String
|
||||
httpErrorToString err =
|
||||
case err of
|
||||
Http.BadUrl msg ->
|
||||
"bad URL: " ++ msg
|
||||
|
||||
Http.Timeout ->
|
||||
"timeout"
|
||||
|
||||
Http.NetworkError ->
|
||||
"network error"
|
||||
|
||||
Http.BadStatus status ->
|
||||
"bad status: " ++ String.fromInt status
|
||||
|
||||
Http.BadBody msg ->
|
||||
"bad body: " ++ msg
|
||||
|
||||
|
||||
urlPrefix : String
|
||||
|
|
@ -154,7 +216,7 @@ urlPrefix =
|
|||
main : Program () Model Message
|
||||
main =
|
||||
Browser.element
|
||||
{ init = \_ -> ( initialModel, Cmd.none )
|
||||
{ init = \_ -> ( initialModel, initialCommand )
|
||||
, subscriptions = \_ -> Sub.none
|
||||
, view = view
|
||||
, update = update
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue