Basic sound controls ° keybaord shortcuts

This commit is contained in:
Thomas Forgione 2021-06-14 10:46:34 +02:00
parent e99a5ed1e3
commit 37a8253387
3 changed files with 137 additions and 10 deletions

View File

@ -79,6 +79,7 @@
app.ports.seek.subscribe(function(arg) { app.ports.seek.subscribe(function(arg) {
const video = document.getElementById('video'); const video = document.getElementById('video');
console.log(arg);
video.currentTime = arg; video.currentTime = arg;
}); });
@ -113,6 +114,12 @@
}); });
} }
}); });
app.ports.setVolume.subscribe(function(arg) {
const video = document.getElementById('video');
video.volume = arg.volume;
video.muted = arg.muted;
});
</script> </script>
</body> </body>
</html> </html>

View File

@ -78,3 +78,35 @@ check =
svgFeatherIcon "check" svgFeatherIcon "check"
[ Svg.polyline [ points "20 6 9 17 4 12" ] [] [ Svg.polyline [ points "20 6 9 17 4 12" ] []
] ]
volume : Bool -> Element msg
volume =
svgFeatherIcon "volume"
[ Svg.polygon [ points "11 5 6 9 2 9 2 15 6 15 11 19 11 5" ] []
]
volume1 : Bool -> Element msg
volume1 =
svgFeatherIcon "volume-1"
[ Svg.polygon [ points "11 5 6 9 2 9 2 15 6 15 11 19 11 5" ] []
, Svg.path [ d "M15.54 8.46a5 5 0 0 1 0 7.07" ] []
]
volume2 : Bool -> Element msg
volume2 =
svgFeatherIcon "volume-2"
[ Svg.polygon [ points "11 5 6 9 2 9 2 15 6 15 11 19 11 5" ] []
, Svg.path [ d "M19.07 4.93a10 10 0 0 1 0 14.14M15.54 8.46a5 5 0 0 1 0 7.07" ] []
]
volumeX : Bool -> Element msg
volumeX =
svgFeatherIcon "volume-x"
[ Svg.polygon [ points "11 5 6 9 2 9 2 15 6 15 11 19 11 5" ] []
, Svg.line [ x1 "23", y1 "9", x2 "17", y2 "15" ] []
, Svg.line [ x1 "17", y1 "9", x2 "23", y2 "15" ] []
]

View File

@ -26,7 +26,7 @@ main =
, update = update , update = update
, view = view , view = view
, subscriptions = , subscriptions =
\_ -> \model ->
Sub.batch Sub.batch
[ nowHasQualities NowHasQualities [ nowHasQualities NowHasQualities
, nowHasQuality , nowHasQuality
@ -40,6 +40,7 @@ main =
) )
, Browser.Events.onAnimationFrameDelta AnimationFrameDelta , Browser.Events.onAnimationFrameDelta AnimationFrameDelta
, Browser.Events.onResize (\x y -> NowHasWindowSize ( x, y )) , Browser.Events.onResize (\x y -> NowHasWindowSize ( x, y ))
, Browser.Events.onKeyDown (decodeKeyDown model)
] ]
, onUrlChange = \_ -> Noop , onUrlChange = \_ -> Noop
, onUrlRequest = \_ -> Noop , onUrlRequest = \_ -> Noop
@ -81,6 +82,7 @@ type Msg
| SetSettings Settings | SetSettings Settings
| SetPlaybackRate Float | SetPlaybackRate Float
| SetQuality Quality.Quality | SetQuality Quality.Quality
| SetVolume Float Bool
| RequestFullscreen | RequestFullscreen
| ExitFullscreen | ExitFullscreen
| AnimationFrameDelta Float | AnimationFrameDelta Float
@ -145,8 +147,8 @@ update msg model =
PlayPause -> PlayPause ->
( model, playPause () ) ( model, playPause () )
Seek ratio -> Seek time ->
( model, seek (ratio * model.duration) ) ( model, seek time )
SetPlaybackRate rate -> SetPlaybackRate rate ->
( { model | showSettings = False, settings = All }, setPlaybackRate rate ) ( { model | showSettings = False, settings = All }, setPlaybackRate rate )
@ -166,6 +168,9 @@ update msg model =
SetQuality q -> SetQuality q ->
( { model | showSettings = False, settings = All }, setQuality q ) ( { model | showSettings = False, settings = All }, setQuality q )
SetVolume v m ->
( model, setVolume { volume = v, muted = m } )
AnimationFrameDelta delta -> AnimationFrameDelta delta ->
if model.animationFrame + delta > 3500 then if model.animationFrame + delta > 3500 then
( { model | animationFrame = model.animationFrame + delta, showSettings = False, settings = All }, Cmd.none ) ( { model | animationFrame = model.animationFrame + delta, showSettings = False, settings = All }, Cmd.none )
@ -301,7 +306,7 @@ video model =
(Element.width Element.fill (Element.width Element.fill
:: Element.height Element.fill :: Element.height Element.fill
:: Element.pointer :: Element.pointer
:: seekBarEvents :: seekBarEvents model
) )
Element.none Element.none
) )
@ -320,6 +325,7 @@ video model =
, Element.row , Element.row
[ Element.spacing 10, Element.width Element.fill ] [ Element.spacing 10, Element.width Element.fill ]
[ playPauseButton model.playing [ playPauseButton model.playing
, volumeButton model.volume model.muted
, Element.el [ Element.moveDown 2.5 ] (Element.text (formatTime model.position ++ " / " ++ formatTime model.duration)) , Element.el [ Element.moveDown 2.5 ] (Element.text (formatTime model.position ++ " / " ++ formatTime model.duration))
, Element.row [ Element.spacing 10, Element.alignRight ] , Element.row [ Element.spacing 10, Element.alignRight ]
[ settingsButton, fullscreenButton model.isFullscreen ] [ settingsButton, fullscreenButton model.isFullscreen ]
@ -534,6 +540,28 @@ fullscreenButton isFullscreen =
) )
volumeButton : Float -> Bool -> Element Msg
volumeButton volume muted =
let
icon =
if muted then
Icons.volumeX
else if volume < 0.3 then
Icons.volume
else if volume < 0.6 then
Icons.volume1
else
Icons.volume2
in
Input.button []
{ label = icon True
, onPress = Just (SetVolume volume (not muted))
}
settingsButton : Element Msg settingsButton : Element Msg
settingsButton = settingsButton =
Input.button [] Input.button []
@ -564,10 +592,10 @@ videoEvents =
] ]
seekBarEvents : List (Element.Attribute Msg) seekBarEvents : Model -> List (Element.Attribute Msg)
seekBarEvents = seekBarEvents model =
List.map Element.htmlAttribute List.map Element.htmlAttribute
[ Html.Events.on "click" decodeSeek [ Html.Events.on "click" (decodeSeek model)
] ]
@ -593,9 +621,9 @@ decodeVolumeChange =
(Decode.field "muted" Decode.bool) (Decode.field "muted" Decode.bool)
decodeSeek : Decode.Decoder Msg decodeSeek : Model -> Decode.Decoder Msg
decodeSeek = decodeSeek model =
Decode.map2 (\x y -> Seek (toFloat x / toFloat y)) Decode.map2 (\x y -> Seek (toFloat x / toFloat y * model.duration))
(Decode.field "layerX" Decode.int) (Decode.field "layerX" Decode.int)
(Dom.target <| Decode.field "offsetWidth" Decode.int) (Dom.target <| Decode.field "offsetWidth" Decode.int)
@ -646,6 +674,63 @@ decodePlaybackRateChange =
(Decode.field "playbackRate" Decode.float) (Decode.field "playbackRate" Decode.float)
decodeKeyDown : Model -> Decode.Decoder Msg
decodeKeyDown model =
Decode.field "keyCode" Decode.int
|> Decode.andThen
(\x ->
case x of
-- Enter key
32 ->
Decode.succeed PlayPause
-- J key
74 ->
Decode.succeed (Seek (max 0 (model.position - 10)))
-- L key
76 ->
Decode.succeed (Seek (min model.duration (model.position + 10)))
-- K key
75 ->
Decode.succeed PlayPause
-- Left arrow
37 ->
Decode.succeed (Seek (max 0 (model.position - 5)))
-- Right arrow
39 ->
Decode.succeed (Seek (min model.duration (model.position + 5)))
-- Down arrow
40 ->
Decode.succeed (SetVolume (max 0 (model.volume - 0.1)) model.muted)
-- Top arrow
38 ->
Decode.succeed (SetVolume (min 1 (model.volume + 0.1)) model.muted)
-- M key
77 ->
Decode.succeed (SetVolume model.volume (not model.muted))
-- F key
70 ->
Decode.succeed
(if model.isFullscreen then
ExitFullscreen
else
RequestFullscreen
)
_ ->
Decode.fail ("no shortcut for code " ++ String.fromInt x)
)
every : Float -> List ( Float, Float ) -> List ( Float, Float, Bool ) every : Float -> List ( Float, Float ) -> List ( Float, Float, Bool )
every duration input = every duration input =
everyAux duration 0.0 [] input |> List.reverse |> List.filter (\( x, y, _ ) -> x /= y) everyAux duration 0.0 [] input |> List.reverse |> List.filter (\( x, y, _ ) -> x /= y)
@ -724,6 +809,9 @@ port setPlaybackRate : Float -> Cmd msg
port setQuality : Quality.Quality -> Cmd msg port setQuality : Quality.Quality -> Cmd msg
port setVolume : { volume : Float, muted : Bool } -> Cmd msg
port nowHasQualities : (List Int -> msg) -> Sub msg port nowHasQualities : (List Int -> msg) -> Sub msg