Initial workings of tracking with range input

This commit is contained in:
Mikko Ahlroth 2023-10-20 23:44:39 +03:00
parent fb889ea32f
commit d073dfb7ed
5 changed files with 84 additions and 6 deletions

1
.tool-versions Normal file
View file

@ -0,0 +1 @@
gleam 0.31.0

View file

@ -0,0 +1,2 @@
@external(javascript, "../../performance_ffi.mjs", "now")
pub fn now() -> Float

View file

@ -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
View file

@ -0,0 +1,3 @@
export function now() {
return globalThis.performance.now();
}

View file

@ -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);
}
}