Initial workings of tracking with range input
This commit is contained in:
parent
fb889ea32f
commit
d073dfb7ed
5 changed files with 84 additions and 6 deletions
1
.tool-versions
Normal file
1
.tool-versions
Normal file
|
@ -0,0 +1 @@
|
|||
gleam 0.31.0
|
2
src/elekf/utils/performance.gleam
Normal file
2
src/elekf/utils/performance.gleam
Normal file
|
@ -0,0 +1,2 @@
|
|||
@external(javascript, "../../performance_ffi.mjs", "now")
|
||||
pub fn now() -> Float
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import gleam/uri
|
||||
import gleam/int
|
||||
import gleam/dynamic
|
||||
import gleam/float
|
||||
import lustre/element.{text}
|
||||
import lustre/element/html.{audio, button, div, input, p}
|
||||
|
@ -15,9 +14,12 @@ import elekf/web/components/icon.{Alt, icon}
|
|||
import elekf/web/components/track_length.{track_length}
|
||||
import elekf/library/track.{Track}
|
||||
import elekf/utils/date
|
||||
import elekf/utils/performance
|
||||
import ibroadcast/authed_request.{RequestConfig}
|
||||
import ibroadcast/streaming
|
||||
|
||||
const max_track_interval = 500.0
|
||||
|
||||
pub type PlayState {
|
||||
Playing
|
||||
Paused
|
||||
|
@ -33,6 +35,8 @@ pub type Model {
|
|||
state: PlayState,
|
||||
loading_stream: Bool,
|
||||
request_config: RequestConfig,
|
||||
user_is_skipping: Bool,
|
||||
last_tracked: Float,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -46,6 +50,9 @@ pub type Msg {
|
|||
Clear
|
||||
UpdateTime(Float)
|
||||
UpdateRequestConfig(RequestConfig)
|
||||
StartUserSkip
|
||||
EndUserSkip
|
||||
PositionSelected(Int)
|
||||
}
|
||||
|
||||
pub fn init(
|
||||
|
@ -63,6 +70,8 @@ pub fn init(
|
|||
Playing,
|
||||
False,
|
||||
request_config,
|
||||
False,
|
||||
performance.now(),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -90,14 +99,35 @@ pub fn update(model: Model, msg) {
|
|||
NextTrack -> #(model, effect.none())
|
||||
PrevTrack -> #(model, effect.none())
|
||||
Clear -> #(model, effect.none())
|
||||
UpdateTime(time) -> #(
|
||||
Model(..model, position: float.truncate(time)),
|
||||
effect.none(),
|
||||
)
|
||||
UpdateTime(time) ->
|
||||
case model.user_is_skipping {
|
||||
True -> #(model, effect.none())
|
||||
False -> {
|
||||
let pos = float.truncate(time)
|
||||
set_track_to(pos)
|
||||
|
||||
#(Model(..model, position: pos), effect.none())
|
||||
}
|
||||
}
|
||||
UpdateRequestConfig(config) -> #(
|
||||
Model(..model, request_config: config),
|
||||
effect.none(),
|
||||
)
|
||||
StartUserSkip -> #(Model(..model, user_is_skipping: True), effect.none())
|
||||
EndUserSkip -> #(Model(..model, user_is_skipping: False), effect.none())
|
||||
PositionSelected(time) -> {
|
||||
case { performance.now() -. model.last_tracked } >. max_track_interval {
|
||||
True -> {
|
||||
skip_to_time(time)
|
||||
|
||||
#(
|
||||
Model(..model, position: time, last_tracked: performance.now()),
|
||||
effect.none(),
|
||||
)
|
||||
}
|
||||
False -> #(model, effect.none())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,7 +197,9 @@ pub fn view(model: Model) {
|
|||
attribute.min("0"),
|
||||
attribute.max(int.to_string(model.track.length)),
|
||||
attribute.attribute("aria-label", "Track position"),
|
||||
attribute.value(dynamic.from(model.position)),
|
||||
event.on("input", event_slider_change),
|
||||
event.on_mouse_down(StartUserSkip),
|
||||
event.on_mouse_up(EndUserSkip),
|
||||
]),
|
||||
p(
|
||||
[attribute.id("player-times")],
|
||||
|
@ -215,6 +247,10 @@ fn event_timeupdate(_: a) {
|
|||
Ok(UpdateTime(current_time()))
|
||||
}
|
||||
|
||||
fn event_slider_change(_: a) {
|
||||
Ok(PositionSelected(current_track_position()))
|
||||
}
|
||||
|
||||
@external(javascript, "../../../player_ffi.mjs", "play")
|
||||
fn play() -> Nil
|
||||
|
||||
|
@ -223,3 +259,12 @@ fn pause() -> Nil
|
|||
|
||||
@external(javascript, "../../../player_ffi.mjs", "currentTime")
|
||||
fn current_time() -> Float
|
||||
|
||||
@external(javascript, "../../../player_ffi.mjs", "skipToPosition")
|
||||
fn skip_to_time(time: Int) -> Nil
|
||||
|
||||
@external(javascript, "../../../player_ffi.mjs", "currentTrackPosition")
|
||||
fn current_track_position() -> Int
|
||||
|
||||
@external(javascript, "../../../player_ffi.mjs", "setTrackTo")
|
||||
fn set_track_to(pos: Int) -> Nil
|
||||
|
|
3
src/performance_ffi.mjs
Normal file
3
src/performance_ffi.mjs
Normal file
|
@ -0,0 +1,3 @@
|
|||
export function now() {
|
||||
return globalThis.performance.now();
|
||||
}
|
|
@ -1,10 +1,16 @@
|
|||
const player_id = "player-elem";
|
||||
const track_id = "player-track";
|
||||
|
||||
/**
|
||||
* @type {HTMLAudioElement}
|
||||
*/
|
||||
let player;
|
||||
|
||||
/**
|
||||
* @type {HTMLInputElement}
|
||||
*/
|
||||
let track;
|
||||
|
||||
export function registerCallback(event, callback) {
|
||||
getPlayer();
|
||||
player.addEventListener(event, callback);
|
||||
|
@ -25,8 +31,29 @@ export function pause() {
|
|||
player.pause();
|
||||
}
|
||||
|
||||
export function skipToPosition(pos) {
|
||||
getPlayer();
|
||||
player.currentTime = pos;
|
||||
}
|
||||
|
||||
export function currentTrackPosition() {
|
||||
getTrack();
|
||||
return track.valueAsNumber;
|
||||
}
|
||||
|
||||
export function setTrackTo(pos) {
|
||||
getTrack();
|
||||
track.value = String(pos);
|
||||
}
|
||||
|
||||
function getPlayer() {
|
||||
if (player === undefined) {
|
||||
player = document.getElementById(player_id);
|
||||
}
|
||||
}
|
||||
|
||||
function getTrack() {
|
||||
if (track === undefined) {
|
||||
track = document.getElementById(track_id);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue