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 Dict exposing (Dict)
import Element
import Hover exposing (Hover)
import Http
import Ports
import Task
@ -24,13 +25,14 @@ type alias Model =
, page : Page
, key : Nav.Key
, device : Element.Device
, time : Time.Posix
}
type Page
= Home
| Playlist Twitch.Playlist
| Video Twitch.Playlist Twitch.Video
= Home (Maybe (Hover Twitch.Playlist))
| Playlist Twitch.Playlist (Maybe (Hover Twitch.Video))
| Video Twitch.Playlist Twitch.Video (Maybe (Hover Twitch.Video))
type Msg
@ -43,6 +45,10 @@ type Msg
| UrlRequested Browser.UrlRequest
| SizeReceived Int Int
| 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 )
@ -67,7 +73,10 @@ resultToMsg result =
subscriptions : FullModel -> Sub Msg
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 )
@ -79,6 +88,39 @@ update msg model =
( TimeZoneReceived z, Unloaded d u k _ ) ->
( 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 ) ->
( Loaded { m | zone = z }, Cmd.none )
@ -90,7 +132,15 @@ update msg model =
( PlaylistsReceived playlists, Unloaded device url key zone ) ->
update
(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 ) ->
( model
@ -159,19 +209,19 @@ update msg model =
( page, cmd ) =
case ( playlist, video ) of
( Just p, Just v ) ->
( Video p v
( Video p v Nothing
, Ports.registerVideo ( Twitch.videoId v, "videos/" ++ p.url ++ v.url, time )
)
( Just p, Nothing ) ->
( Playlist p, Cmd.none )
( Playlist p Nothing, Cmd.none )
_ ->
( Home, Cmd.none )
( Home Nothing, Cmd.none )
extraCmd =
case page of
Video _ _ ->
Video _ _ _ ->
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
)
import Hover exposing (Hover)
import Http
import Iso8601
import Json.Decode as Decode
@ -70,9 +71,22 @@ videoId video =
String.dropLeft 1 video.url |> String.replace "/" "-"
playlistMiniatureUrl : Playlist -> String
playlistMiniatureUrl playlist =
case List.head playlist.videos of
playlistMiniatureUrl : Time.Posix -> Maybe (Hover Playlist) -> Playlist -> String
playlistMiniatureUrl currentTime hover playlist =
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 ->
"videos/" ++ playlist.url ++ v.url ++ "miniature-050.png"
@ -80,6 +94,30 @@ playlistMiniatureUrl playlist =
""
videoMiniatureUrl : Playlist -> Video -> String
videoMiniatureUrl playlist video =
"videos/" ++ playlist.url ++ video.url ++ "miniature-050.png"
videoMiniatureUrl : Time.Posix -> Maybe (Hover Video) -> Playlist -> Video -> String
videoMiniatureUrl currentTime hover playlist video =
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.Background as Background
import Element.Border as Border
import Element.Events as Events
import Element.Font as Font
import Element.Input as Input
import Element.Keyed as Keyed
import Hover exposing (Hover)
import Html
import Html.Attributes
import Json.Encode as Encode
@ -53,27 +55,27 @@ title model =
Core.Loaded m ->
case m.page of
Core.Home ->
Core.Home _ ->
Consts.url
Core.Playlist p ->
Core.Playlist p _ ->
Consts.url ++ " - " ++ p.name
Core.Video p v ->
Core.Video p v _ ->
Consts.url ++ " - " ++ p.name ++ " - " ++ v.name
viewContent : Core.Model -> Element Core.Msg
viewContent model =
case model.page of
Core.Home ->
playlistsView model.device model.playlists
Core.Home hover ->
playlistsView model.device model.playlists model.time hover
Core.Playlist playlist ->
videoMiniaturesView model.device model.zone playlist
Core.Playlist playlist hover ->
videoMiniaturesView model.device model.zone model.time hover playlist
Core.Video playlist video ->
videoView model.device model.zone playlist video
Core.Video playlist video hover ->
videoView model.device model.zone model.time hover playlist video
topBar : Element Core.Msg
@ -99,14 +101,14 @@ homeButton =
}
playlistsView : Element.Device -> List Twitch.Playlist -> Element Core.Msg
playlistsView device playlists =
playlistsView : Element.Device -> List Twitch.Playlist -> Time.Posix -> Maybe (Hover Twitch.Playlist) -> Element Core.Msg
playlistsView device playlists time hover =
let
empty =
Element.el [ Element.width Element.fill ] Element.none
views =
List.map playlistView playlists
List.map (playlistView time hover) playlists
grouped =
group (numberOfVideosPerRow device) views
@ -122,15 +124,23 @@ playlistsView device playlists =
final
playlistView : Twitch.Playlist -> Element Core.Msg
playlistView playlist =
playlistView : Time.Posix -> Maybe (Hover Twitch.Playlist) -> Twitch.Playlist -> Element Core.Msg
playlistView time hover playlist =
let
key =
Twitch.playlistMiniatureUrl time Nothing playlist
src =
Twitch.playlistMiniatureUrl playlist
Twitch.playlistMiniatureUrl time hover playlist
image =
Keyed.el [ Element.width Element.fill, Element.height Element.fill ]
( src
Keyed.el
[ Element.width Element.fill
, Element.height Element.fill
, Events.onMouseEnter (Core.HoverPlaylist playlist)
, Events.onMouseLeave Core.Unhover
]
( key
, Element.image
[ Element.width Element.fill
, Element.height Element.fill
@ -187,14 +197,14 @@ playlistView playlist =
button
videoMiniaturesView : Element.Device -> Time.Zone -> Twitch.Playlist -> Element Core.Msg
videoMiniaturesView device zone playlist =
videoMiniaturesView : Element.Device -> Time.Zone -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Element Core.Msg
videoMiniaturesView device zone time hover playlist =
let
empty =
Element.el [ Element.width Element.fill ] Element.none
views =
List.map (videoMiniatureView zone playlist) playlist.videos
List.map (videoMiniatureView zone time hover playlist) playlist.videos
grouped =
group (numberOfVideosPerRow device) views
@ -210,8 +220,8 @@ videoMiniaturesView device zone playlist =
final
videoMiniature : Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoMiniature playlist video =
videoMiniature : Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoMiniature time hover playlist video =
let
inFront =
Element.text label
@ -227,12 +237,20 @@ videoMiniature playlist video =
, Element.padding 5
]
key =
Twitch.videoMiniatureUrl time Nothing playlist video
src =
Twitch.videoMiniatureUrl playlist video
Twitch.videoMiniatureUrl time hover playlist video
image =
Keyed.el [ Element.width Element.fill, Element.height Element.fill ]
( src
Keyed.el
[ Element.width Element.fill
, Element.height Element.fill
, Events.onMouseEnter (Core.HoverVideo video)
, Events.onMouseLeave Core.Unhover
]
( key
, Element.image
[ Element.width Element.fill
, Element.height Element.fill
@ -247,12 +265,12 @@ videoMiniature playlist video =
image
videoMiniatureView : Time.Zone -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoMiniatureView zone playlist video =
videoMiniatureView : Time.Zone -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoMiniatureView zone time hover playlist video =
let
display =
Element.column [ Element.width Element.fill, Element.spacing 10 ]
[ videoMiniature playlist video
[ videoMiniature time hover playlist video
, videoDescription zone video
]
@ -265,13 +283,13 @@ videoMiniatureView zone playlist video =
button
videoInList : Time.Zone -> Twitch.Playlist -> Twitch.Video -> Twitch.Video -> Element Core.Msg
videoInList zone playlist activeVideo video =
videoInList : Time.Zone -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Twitch.Video -> Element Core.Msg
videoInList zone time hover playlist activeVideo video =
let
label =
Element.row [ Element.width Element.fill, Element.spacing 10 ]
[ 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 ]
(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 device zone playlist video =
videoView : Element.Device -> Time.Zone -> Time.Posix -> Maybe (Hover Twitch.Video) -> Twitch.Playlist -> Twitch.Video -> Element Core.Msg
videoView device zone time hover playlist video =
let
( builder, contentPadding ) =
case device.class of
@ -360,7 +378,7 @@ videoView device zone playlist video =
, Element.height Element.fill
, Element.scrollbarY
]
(List.map (videoInList zone playlist video) playlist.videos)
(List.map (videoInList zone time hover playlist video) playlist.videos)
]