Change miniatures when hover

This commit is contained in:
Thomas Forgione 2020-10-16 12:03:07 +02:00
parent bf1d35c179
commit 948df5da9a
4 changed files with 169 additions and 49 deletions

View File

@ -5,6 +5,7 @@ import Browser.Events as Events
import Browser.Navigation as Nav import Browser.Navigation as Nav
import Dict exposing (Dict) import Dict exposing (Dict)
import Element import Element
import Hover exposing (Hover)
import Http import Http
import Ports import Ports
import Task import Task
@ -24,13 +25,14 @@ type alias Model =
, page : Page , page : Page
, key : Nav.Key , key : Nav.Key
, device : Element.Device , device : Element.Device
, time : Time.Posix
} }
type Page type Page
= Home = Home (Maybe (Hover Twitch.Playlist))
| Playlist Twitch.Playlist | Playlist Twitch.Playlist (Maybe (Hover Twitch.Video))
| Video Twitch.Playlist Twitch.Video | Video Twitch.Playlist Twitch.Video (Maybe (Hover Twitch.Video))
type Msg type Msg
@ -43,6 +45,10 @@ type Msg
| UrlRequested Browser.UrlRequest | UrlRequested Browser.UrlRequest
| SizeReceived Int Int | SizeReceived Int Int
| TimeZoneReceived Time.Zone | TimeZoneReceived Time.Zone
| HoverPlaylist Twitch.Playlist
| HoverVideo Twitch.Video
| Unhover
| TimeReceived Time.Posix
init : { width : Int, height : Int } -> Url.Url -> Nav.Key -> ( FullModel, Cmd Msg ) init : { width : Int, height : Int } -> Url.Url -> Nav.Key -> ( FullModel, Cmd Msg )
@ -67,7 +73,10 @@ resultToMsg result =
subscriptions : FullModel -> Sub Msg subscriptions : FullModel -> Sub Msg
subscriptions _ = subscriptions _ =
Events.onResize (\w h -> SizeReceived w h) Sub.batch
[ Events.onResize (\w h -> SizeReceived w h)
, Time.every 200 TimeReceived
]
update : Msg -> FullModel -> ( FullModel, Cmd Msg ) update : Msg -> FullModel -> ( FullModel, Cmd Msg )
@ -79,6 +88,39 @@ update msg model =
( TimeZoneReceived z, Unloaded d u k _ ) -> ( TimeZoneReceived z, Unloaded d u k _ ) ->
( Unloaded d u k z, Cmd.none ) ( Unloaded d u k z, Cmd.none )
( TimeReceived p, Loaded m ) ->
( Loaded { m | time = p }, Cmd.none )
( HoverPlaylist hover, Loaded m ) ->
case m.page of
Home Nothing ->
( Loaded { m | page = Home (Just (Hover.hover hover m.time)) }, Cmd.none )
_ ->
( Loaded m, Cmd.none )
( HoverVideo hover, Loaded m ) ->
case m.page of
Playlist p Nothing ->
( Loaded { m | page = Playlist p (Just (Hover.hover hover m.time)) }, Cmd.none )
Video p v Nothing ->
( Loaded { m | page = Video p v (Just (Hover.hover v m.time)) }, Cmd.none )
_ ->
( Loaded m, Cmd.none )
( Unhover, Loaded m ) ->
case m.page of
Home _ ->
( Loaded { m | page = Home Nothing }, Cmd.none )
Playlist p _ ->
( Loaded { m | page = Playlist p Nothing }, Cmd.none )
Video p v _ ->
( Loaded { m | page = Video p v Nothing }, Cmd.none )
( TimeZoneReceived z, Loaded m ) -> ( TimeZoneReceived z, Loaded m ) ->
( Loaded { m | zone = z }, Cmd.none ) ( Loaded { m | zone = z }, Cmd.none )
@ -90,7 +132,15 @@ update msg model =
( PlaylistsReceived playlists, Unloaded device url key zone ) -> ( PlaylistsReceived playlists, Unloaded device url key zone ) ->
update update
(UrlReceived url) (UrlReceived url)
(Loaded { key = key, playlists = playlists, zone = zone, page = Home, device = device }) (Loaded
{ key = key
, playlists = playlists
, zone = zone
, page = Home Nothing
, device = device
, time = Time.millisToPosix 0
}
)
( HomeClicked, Loaded m ) -> ( HomeClicked, Loaded m ) ->
( model ( model
@ -159,19 +209,19 @@ update msg model =
( page, cmd ) = ( page, cmd ) =
case ( playlist, video ) of case ( playlist, video ) of
( Just p, Just v ) -> ( Just p, Just v ) ->
( Video p v ( Video p v Nothing
, Ports.registerVideo ( Twitch.videoId v, "videos/" ++ p.url ++ v.url, time ) , Ports.registerVideo ( Twitch.videoId v, "videos/" ++ p.url ++ v.url, time )
) )
( Just p, Nothing ) -> ( Just p, Nothing ) ->
( Playlist p, Cmd.none ) ( Playlist p Nothing, Cmd.none )
_ -> _ ->
( Home, Cmd.none ) ( Home Nothing, Cmd.none )
extraCmd = extraCmd =
case page of case page of
Video _ _ -> Video _ _ _ ->
Cmd.none Cmd.none
_ -> _ ->

14
src/Hover.elm Normal file
View File

@ -0,0 +1,14 @@
module Hover exposing (..)
import Time
type alias Hover a =
{ element : a
, time : Time.Posix
}
hover : a -> Time.Posix -> Hover a
hover element time =
{ element = element, time = time }

View File

@ -9,6 +9,7 @@ module Twitch exposing
, videoName , videoName
) )
import Hover exposing (Hover)
import Http import Http
import Iso8601 import Iso8601
import Json.Decode as Decode import Json.Decode as Decode
@ -70,9 +71,22 @@ videoId video =
String.dropLeft 1 video.url |> String.replace "/" "-" String.dropLeft 1 video.url |> String.replace "/" "-"
playlistMiniatureUrl : Playlist -> String playlistMiniatureUrl : Time.Posix -> Maybe (Hover Playlist) -> Playlist -> String
playlistMiniatureUrl playlist = playlistMiniatureUrl currentTime hover playlist =
case List.head playlist.videos of let
skip =
case hover of
Nothing ->
0
Just { element, time } ->
if element == playlist then
modBy (List.length playlist.videos) ((Time.posixToMillis currentTime - Time.posixToMillis time) // 1000)
else
0
in
case List.head (List.drop skip playlist.videos) of
Just v -> Just v ->
"videos/" ++ playlist.url ++ v.url ++ "miniature-050.png" "videos/" ++ playlist.url ++ v.url ++ "miniature-050.png"
@ -80,6 +94,30 @@ playlistMiniatureUrl playlist =
"" ""
videoMiniatureUrl : Playlist -> Video -> String videoMiniatureUrl : Time.Posix -> Maybe (Hover Video) -> Playlist -> Video -> String
videoMiniatureUrl playlist video = videoMiniatureUrl currentTime hover playlist video =
"videos/" ++ playlist.url ++ video.url ++ "miniature-050.png" let
index =
case hover of
Nothing ->
5
Just { element, time } ->
if element == video then
modBy 11 ((Time.posixToMillis currentTime - Time.posixToMillis time) // 1000)
else
5
indexString =
case index of
10 ->
"100"
0 ->
"000"
n ->
"0" ++ String.fromInt n ++ "0"
in
"videos/" ++ playlist.url ++ video.url ++ "miniature-" ++ indexString ++ ".png"

View File

@ -7,9 +7,11 @@ import Core
import Element exposing (Element) import Element exposing (Element)
import Element.Background as Background import Element.Background as Background
import Element.Border as Border import Element.Border as Border
import Element.Events as Events
import Element.Font as Font import Element.Font as Font
import Element.Input as Input import Element.Input as Input
import Element.Keyed as Keyed import Element.Keyed as Keyed
import Hover exposing (Hover)
import Html import Html
import Html.Attributes import Html.Attributes
import Json.Encode as Encode import Json.Encode as Encode
@ -53,27 +55,27 @@ title model =
Core.Loaded m -> Core.Loaded m ->
case m.page of case m.page of
Core.Home -> Core.Home _ ->
Consts.url Consts.url
Core.Playlist p -> Core.Playlist p _ ->
Consts.url ++ " - " ++ p.name Consts.url ++ " - " ++ p.name
Core.Video p v -> Core.Video p v _ ->
Consts.url ++ " - " ++ p.name ++ " - " ++ v.name Consts.url ++ " - " ++ p.name ++ " - " ++ v.name
viewContent : Core.Model -> Element Core.Msg viewContent : Core.Model -> Element Core.Msg
viewContent model = viewContent model =
case model.page of case model.page of
Core.Home -> Core.Home hover ->
playlistsView model.device model.playlists playlistsView model.device model.playlists model.time hover
Core.Playlist playlist -> Core.Playlist playlist hover ->
videoMiniaturesView model.device model.zone playlist videoMiniaturesView model.device model.zone model.time hover playlist
Core.Video playlist video -> Core.Video playlist video hover ->
videoView model.device model.zone playlist video videoView model.device model.zone model.time hover playlist video
topBar : Element Core.Msg topBar : Element Core.Msg
@ -99,14 +101,14 @@ homeButton =
} }
playlistsView : Element.Device -> List Twitch.Playlist -> Element Core.Msg playlistsView : Element.Device -> List Twitch.Playlist -> Time.Posix -> Maybe (Hover Twitch.Playlist) -> Element Core.Msg
playlistsView device playlists = playlistsView device playlists time hover =
let let
empty = empty =
Element.el [ Element.width Element.fill ] Element.none Element.el [ Element.width Element.fill ] Element.none
views = views =
List.map playlistView playlists List.map (playlistView time hover) playlists
grouped = grouped =
group (numberOfVideosPerRow device) views group (numberOfVideosPerRow device) views
@ -122,15 +124,23 @@ playlistsView device playlists =
final final
playlistView : Twitch.Playlist -> Element Core.Msg playlistView : Time.Posix -> Maybe (Hover Twitch.Playlist) -> Twitch.Playlist -> Element Core.Msg
playlistView playlist = playlistView time hover playlist =
let let
key =
Twitch.playlistMiniatureUrl time Nothing playlist
src = src =
Twitch.playlistMiniatureUrl playlist Twitch.playlistMiniatureUrl time hover playlist
image = image =
Keyed.el [ Element.width Element.fill, Element.height Element.fill ] Keyed.el
( src [ Element.width Element.fill
, Element.height Element.fill
, Events.onMouseEnter (Core.HoverPlaylist playlist)
, Events.onMouseLeave Core.Unhover
]
( key
, Element.image , Element.image
[ Element.width Element.fill [ Element.width Element.fill
, Element.height Element.fill , Element.height Element.fill
@ -187,14 +197,14 @@ playlistView playlist =
button button
videoMiniaturesView : Element.Device -> Time.Zone -> Twitch.Playlist -> Element Core.Msg videoMiniaturesView : Element.Device -> Time.Zone -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Element Core.Msg
videoMiniaturesView device zone playlist = videoMiniaturesView device zone time hover playlist =
let let
empty = empty =
Element.el [ Element.width Element.fill ] Element.none Element.el [ Element.width Element.fill ] Element.none
views = views =
List.map (videoMiniatureView zone playlist) playlist.videos List.map (videoMiniatureView zone time hover playlist) playlist.videos
grouped = grouped =
group (numberOfVideosPerRow device) views group (numberOfVideosPerRow device) views
@ -210,8 +220,8 @@ videoMiniaturesView device zone playlist =
final final
videoMiniature : Twitch.Playlist -> Twitch.Video -> Element Core.Msg videoMiniature : Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoMiniature playlist video = videoMiniature time hover playlist video =
let let
inFront = inFront =
Element.text label Element.text label
@ -227,12 +237,20 @@ videoMiniature playlist video =
, Element.padding 5 , Element.padding 5
] ]
key =
Twitch.videoMiniatureUrl time Nothing playlist video
src = src =
Twitch.videoMiniatureUrl playlist video Twitch.videoMiniatureUrl time hover playlist video
image = image =
Keyed.el [ Element.width Element.fill, Element.height Element.fill ] Keyed.el
( src [ Element.width Element.fill
, Element.height Element.fill
, Events.onMouseEnter (Core.HoverVideo video)
, Events.onMouseLeave Core.Unhover
]
( key
, Element.image , Element.image
[ Element.width Element.fill [ Element.width Element.fill
, Element.height Element.fill , Element.height Element.fill
@ -247,12 +265,12 @@ videoMiniature playlist video =
image image
videoMiniatureView : Time.Zone -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg videoMiniatureView : Time.Zone -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoMiniatureView zone playlist video = videoMiniatureView zone time hover playlist video =
let let
display = display =
Element.column [ Element.width Element.fill, Element.spacing 10 ] Element.column [ Element.width Element.fill, Element.spacing 10 ]
[ videoMiniature playlist video [ videoMiniature time hover playlist video
, videoDescription zone video , videoDescription zone video
] ]
@ -265,13 +283,13 @@ videoMiniatureView zone playlist video =
button button
videoInList : Time.Zone -> Twitch.Playlist -> Twitch.Video -> Twitch.Video -> Element Core.Msg videoInList : Time.Zone -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Twitch.Video -> Element Core.Msg
videoInList zone playlist activeVideo video = videoInList zone time hover playlist activeVideo video =
let let
label = label =
Element.row [ Element.width Element.fill, Element.spacing 10 ] Element.row [ Element.width Element.fill, Element.spacing 10 ]
[ Element.el [ Element.width (Element.fillPortion 2) ] [ Element.el [ Element.width (Element.fillPortion 2) ]
(videoMiniature playlist video) (videoMiniature time hover playlist video)
, Element.el [ Element.width (Element.fillPortion 3), Element.paddingXY 0 10, Element.alignTop ] , Element.el [ Element.width (Element.fillPortion 3), Element.paddingXY 0 10, Element.alignTop ]
(videoDescription zone video) (videoDescription zone video)
] ]
@ -292,8 +310,8 @@ videoInList zone playlist activeVideo video =
} }
videoView : Element.Device -> Time.Zone -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg videoView : Element.Device -> Time.Zone -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoView device zone playlist video = videoView device zone time hover playlist video =
let let
( builder, contentPadding ) = ( builder, contentPadding ) =
case device.class of case device.class of
@ -360,7 +378,7 @@ videoView device zone playlist video =
, Element.height Element.fill , Element.height Element.fill
, Element.scrollbarY , Element.scrollbarY
] ]
(List.map (videoInList zone playlist video) playlist.videos) (List.map (videoInList zone time hover playlist video) playlist.videos)
] ]