diff --git a/elm.json b/elm.json index 7c53ae6..a4af880 100644 --- a/elm.json +++ b/elm.json @@ -15,7 +15,8 @@ "elm/time": "1.0.0", "elm/url": "1.0.0", "jims/html-parser": "1.0.0", - "mdgriffith/elm-ui": "1.1.8" + "mdgriffith/elm-ui": "1.1.8", + "rtfeldman/elm-iso8601-date-strings": "1.1.3" }, "indirect": { "elm/bytes": "1.0.8", diff --git a/src/Colors.elm b/src/Colors.elm index 350c61d..bc631eb 100644 --- a/src/Colors.elm +++ b/src/Colors.elm @@ -1,4 +1,4 @@ -module Colors exposing (blackFont, greyBackground, primary, primaryOver, white) +module Colors exposing (blackFont, greyBackground, greyFont, primary, primaryOver, white) import Element @@ -26,3 +26,8 @@ greyBackground = blackFont : Element.Color blackFont = Element.rgb255 54 54 54 + + +greyFont : Element.Color +greyFont = + Element.rgb255 128 128 128 diff --git a/src/Consts.elm b/src/Consts.elm index cd94e5d..4dc340c 100644 --- a/src/Consts.elm +++ b/src/Consts.elm @@ -1,4 +1,11 @@ -module Consts exposing (homeFontSize, homePadding, name, url) +module Consts exposing + ( homeFontSize + , homePadding + , name + , normalFontSize + , titleFontSize + , url + ) url : String @@ -11,6 +18,16 @@ name = url +normalFontSize : Int +normalFontSize = + 13 + + +titleFontSize : Int +titleFontSize = + 15 + + homeFontSize : Int homeFontSize = 25 diff --git a/src/Core.elm b/src/Core.elm index 75b4802..23e8a5d 100644 --- a/src/Core.elm +++ b/src/Core.elm @@ -3,6 +3,7 @@ module Core exposing (FullModel(..), Model, Msg(..), Page(..), init, update) import Browser.Navigation import Json.Decode as Decode import Task +import Time import Twitch import Url @@ -14,6 +15,7 @@ type FullModel type alias Model = { playlists : List Twitch.Playlist + , zone : Time.Zone , page : Page } @@ -26,7 +28,7 @@ type Page type Msg = Noop - | PlaylistsReceived (List Twitch.Playlist) + | PlaylistsReceived ( List Twitch.Playlist, Time.Zone ) | HomeClicked | PlaylistClicked Twitch.Playlist | VideoClicked Twitch.Playlist Twitch.Video @@ -45,17 +47,17 @@ update msg model = ( Noop, _ ) -> ( model, Cmd.none ) - ( PlaylistsReceived playlists, _ ) -> - ( Loaded { playlists = playlists, page = Home }, Cmd.none ) + ( PlaylistsReceived ( playlists, zone ), _ ) -> + ( Loaded { playlists = playlists, zone = zone, page = Home }, Cmd.none ) - ( HomeClicked, Loaded { playlists } ) -> - ( Loaded { playlists = playlists, page = Home }, Cmd.none ) + ( HomeClicked, Loaded m ) -> + ( Loaded { m | page = Home }, Cmd.none ) - ( PlaylistClicked playlist, Loaded { playlists } ) -> - ( Loaded { playlists = playlists, page = Playlist playlist }, Cmd.none ) + ( PlaylistClicked playlist, Loaded m ) -> + ( Loaded { m | page = Playlist playlist }, Cmd.none ) - ( VideoClicked playlist video, Loaded { playlists } ) -> - ( Loaded { playlists = playlists, page = Video playlist video }, Cmd.none ) + ( VideoClicked playlist video, Loaded m ) -> + ( Loaded { m | page = Video playlist video }, Cmd.none ) _ -> ( model, Cmd.none ) diff --git a/src/TimeUtils.elm b/src/TimeUtils.elm new file mode 100644 index 0000000..2404971 --- /dev/null +++ b/src/TimeUtils.elm @@ -0,0 +1,52 @@ +module TimeUtils exposing (monthToString, pad2) + +import Time + + +pad2 : String -> String +pad2 input = + if String.length input == 1 then + "0" ++ input + + else + input + + +monthToString : Time.Month -> String +monthToString month = + case month of + Time.Jan -> + "01" + + Time.Feb -> + "02" + + Time.Mar -> + "03" + + Time.Apr -> + "04" + + Time.May -> + "05" + + Time.Jun -> + "06" + + Time.Jul -> + "07" + + Time.Aug -> + "08" + + Time.Sep -> + "09" + + Time.Oct -> + "10" + + Time.Nov -> + "11" + + Time.Dec -> + "12" diff --git a/src/Twitch.elm b/src/Twitch.elm index 180547e..3aeadcc 100644 --- a/src/Twitch.elm +++ b/src/Twitch.elm @@ -8,8 +8,10 @@ module Twitch exposing import Html.Parser import Http +import Iso8601 import Json.Decode as Decode import Task exposing (Task) +import Time type alias Playlist = @@ -23,6 +25,7 @@ type alias Video = { name : String , url : String , duration : Int + , date : Time.Posix } @@ -63,9 +66,17 @@ sortPlaylists playlists = List.sortBy .url (List.map sortPlaylist playlists) |> List.reverse -fetchPlaylists : Task x (List Playlist) +fetchPlaylists : Task x ( List Playlist, Time.Zone ) fetchPlaylists = - fetchPlaylistPath |> Task.andThen fetchPlaylistsMapper |> Task.map sortPlaylists + fetchPlaylistPath + |> Task.andThen fetchPlaylistsMapper + |> Task.map sortPlaylists + |> Task.andThen fetchTimezone + + +fetchTimezone : List Playlist -> Task x ( List Playlist, Time.Zone ) +fetchTimezone playlists = + Task.map (\zone -> ( playlists, zone )) Time.here fetchPlaylistPath : Task x (List String) @@ -129,10 +140,10 @@ parseVideo url result = Ok v _ -> - Ok { name = "", url = url, duration = 0 } + Ok { name = "", url = url, duration = 0, date = Time.millisToPosix 0 } _ -> - Ok { name = "", url = url, duration = 0 } + Ok { name = "", url = url, duration = 0, date = Time.millisToPosix 0 } fetchPlaylistsMapper : List String -> Task x (List Playlist) @@ -221,6 +232,7 @@ decodePlaylistName = decodeVideo : String -> Decode.Decoder Video decodeVideo url = - Decode.map2 (\x y -> Video x url y) + Decode.map3 (\x y -> Video x url y) (Decode.field "title" Decode.string) (Decode.map Basics.round (Decode.field "duration" Decode.float)) + (Decode.field "date" Iso8601.decoder) diff --git a/src/Views.elm b/src/Views.elm index 443b8ec..e0a81f7 100644 --- a/src/Views.elm +++ b/src/Views.elm @@ -9,13 +9,18 @@ import Element.Background as Background import Element.Border as Border import Element.Font as Font import Element.Input as Input +import Time +import TimeUtils import Twitch view : Core.FullModel -> Browser.Document Core.Msg view model = { title = Consts.url - , body = [ Element.layout [] (viewContent model) ] + , body = + [ Element.layout [ Font.color Colors.blackFont, Font.size Consts.normalFontSize ] + (viewContent model) + ] } @@ -40,10 +45,10 @@ mainView model = playlistsView model.playlists Core.Playlist playlist -> - videoMiniaturesView playlist + videoMiniaturesView model.zone playlist Core.Video playlist video -> - videoView playlist video + videoView model.zone playlist video topBar : Element Core.Msg @@ -135,7 +140,7 @@ playlistView playlist = Element.column [ Element.width Element.fill, Element.spacing 10 ] [ image , Element.paragraph - [ Font.bold, Font.color Colors.blackFont ] + [ Font.bold, Font.size Consts.titleFontSize ] [ Element.text playlist.name ] ] @@ -148,14 +153,14 @@ playlistView playlist = button -videoMiniaturesView : Twitch.Playlist -> Element Core.Msg -videoMiniaturesView playlist = +videoMiniaturesView : Time.Zone -> Twitch.Playlist -> Element Core.Msg +videoMiniaturesView zone playlist = let empty = Element.el [ Element.width Element.fill ] Element.none views = - List.map (videoMiniatureView playlist) playlist.videos + List.map (videoMiniatureView zone playlist) playlist.videos grouped = group 4 views @@ -171,20 +176,9 @@ videoMiniaturesView playlist = final -videoMiniatureView : Twitch.Playlist -> Twitch.Video -> Element Core.Msg -videoMiniatureView playlist video = +videoMiniature : Twitch.Video -> Element Core.Msg +videoMiniature video = let - image = - Element.image - [ Element.width Element.fill - , Element.height Element.fill - , Element.inFront inFront - ] - { description = "", src = Twitch.videoMiniatureUrl video } - - label = - formatTime video.duration - inFront = Element.text label |> Element.el @@ -199,12 +193,27 @@ videoMiniatureView playlist video = , Element.padding 5 ] + image = + Element.image + [ Element.width Element.fill + , Element.height Element.fill + , Element.inFront inFront + ] + { description = "", src = Twitch.videoMiniatureUrl video } + + label = + formatTime video.duration + in + image + + +videoMiniatureView : Time.Zone -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg +videoMiniatureView zone playlist video = + let display = Element.column [ Element.width Element.fill, Element.spacing 10 ] - [ image - , Element.paragraph - [ Font.bold, Font.color Colors.blackFont ] - [ Element.text video.name ] + [ videoMiniature video + , videoDescription zone video ] button = @@ -216,17 +225,72 @@ videoMiniatureView playlist video = button -videoView : Twitch.Playlist -> Twitch.Video -> Element Core.Msg -videoView playlist video = - Element.row [ Element.padding 10, Element.width Element.fill, Element.spacing 20 ] - [ Element.image [ Element.width (Element.fillPortion 2) ] - { description = "", src = Twitch.videoMiniatureUrl video } - , Element.column [ Element.alignTop, Element.width (Element.fillPortion 1) ] - [ Element.text "sup" - ] +videoInList : Time.Zone -> Twitch.Video -> Element Core.Msg +videoInList zone video = + Element.row [ Element.width Element.fill, Element.spacing 10 ] + [ Element.el [ Element.width (Element.fillPortion 1) ] + (videoMiniature video) + , Element.el [ Element.width (Element.fillPortion 2), Element.paddingXY 0 10, Element.alignTop ] + (videoDescription zone video) ] +videoView : Time.Zone -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg +videoView zone playlist video = + Element.row [ Element.padding 10, Element.width Element.fill, Element.spacing 20 ] + [ Element.column [ Element.spacing 10, Element.width (Element.fillPortion 2) ] + [ Element.image [ Element.width Element.fill ] + { description = "", src = Twitch.videoMiniatureUrl video } + , Element.paragraph + [ Font.size Consts.homeFontSize + , Font.bold + ] + [ Element.text video.name ] + , Element.paragraph + [ Font.size Consts.titleFontSize ] + [ Element.text ("Diffusé le " ++ formatDate zone video.date) ] + ] + , Element.column [ Element.alignTop, Element.spacing 10, Element.width (Element.fillPortion 1) ] + (List.map (videoInList zone) playlist.videos) + ] + + +videoDescription : Time.Zone -> Twitch.Video -> Element Core.Msg +videoDescription zone video = + Element.column [ Element.spacing 10 ] + [ Element.paragraph + [ Font.bold + , Font.size Consts.titleFontSize + ] + [ Element.text video.name ] + , Element.paragraph + [ Font.color Colors.greyFont + ] + [ Element.text ("Diffusé le " ++ formatDate zone video.date) ] + ] + + +formatDate : Time.Zone -> Time.Posix -> String +formatDate zone time = + let + day = + Time.toDay zone time |> String.fromInt |> TimeUtils.pad2 + + month = + Time.toMonth zone time |> TimeUtils.monthToString + + year = + Time.toYear zone time |> String.fromInt |> TimeUtils.pad2 + + hours = + Time.toHour zone time |> String.fromInt + + minutes = + Time.toMinute zone time |> String.fromInt |> TimeUtils.pad2 + in + day ++ "/" ++ month ++ "/" ++ year ++ " à " ++ hours ++ "h" ++ minutes + + formatTime : Int -> String formatTime time = let