Change miniatures when hover
This commit is contained in:
parent
bf1d35c179
commit
948df5da9a
68
src/Core.elm
68
src/Core.elm
|
@ -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
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
|
|
|
@ -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 }
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue