diff --git a/src/elekf/web/components/player.gleam b/src/elekf/web/components/player.gleam index dfde3c9..11b0f55 100644 --- a/src/elekf/web/components/player.gleam +++ b/src/elekf/web/components/player.gleam @@ -148,10 +148,9 @@ pub fn update(model: Model, msg) { effect.none(), ) actions.SelectPosition(actions.Commit) -> { - let pos = current_track_position() - skip_to_time(pos) + skip_to_time(model.position) - #(Model(..model, position: pos), effect.none()) + #(model, effect.none()) } actions.SelectPosition(actions.Ephemeral) -> { let pos = current_track_position() @@ -193,7 +192,6 @@ pub fn update(model: Model, msg) { True -> #(model, effect.none()) False -> { let pos = float.truncate(time) - set_track_to(pos) case position.make_position_state( @@ -361,9 +359,6 @@ 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 - @external(javascript, "../../../player_ffi.mjs", "createAudioContext") fn create_audio_context() -> AudioContext diff --git a/src/elekf/web/components/player/full_screen.gleam b/src/elekf/web/components/player/full_screen.gleam index 8e2f965..37883da 100644 --- a/src/elekf/web/components/player/full_screen.gleam +++ b/src/elekf/web/components/player/full_screen.gleam @@ -2,28 +2,21 @@ import gleam/int import gleam/float import gleam/option import lustre/element.{text} -import lustre/element/html.{div, input, p} +import lustre/element/html.{div, p} import lustre/attribute import lustre/event import elekf/utils/lustre import elekf/web/components/icon.{Alt, icon} -import elekf/web/components/track_length.{track_length} import elekf/web/components/button_group import elekf/web/components/button import elekf/web/components/link import elekf/web/components/thumbnail -import elekf/web/components/player/actions.{ - Commit, EndUserSkip, Ephemeral, NextTrack, Pause, Play, PrevTrack, - SelectPosition, StartUserSkip, -} +import elekf/web/components/player/actions.{NextTrack, Pause, Play, PrevTrack} import elekf/web/components/player/model.{type Model} +import elekf/web/components/player/track pub fn view(model: Model) { let is_playing = model.state == model.Playing - let current_time_padding = case model.track.length > 3600 { - True -> track_length.Hours - False -> track_length.Auto - } div( [ @@ -96,33 +89,7 @@ pub fn view(model: Model) { [icon("arrows-angle-contract", Alt("Small player"))], ), ]), - p( - [ - attribute.id("player-time-elapsed"), - attribute.class("player-time"), - attribute.attribute("aria-label", "Time elapsed"), - ], - [track_length(model.position, current_time_padding)], - ), - p( - [ - attribute.id("player-time-total"), - attribute.class("player-time"), - attribute.attribute("aria-label", "Total time"), - ], - [track_length(model.track.length, track_length.Auto)], - ), - input([ - attribute.id("player-track"), - attribute.type_("range"), - attribute.min("0"), - attribute.max(int.to_string(model.track.length)), - attribute.attribute("aria-label", "Track position"), - event.on("change", fn(_) { Ok(SelectPosition(Commit)) }), - event.on_mouse_down(StartUserSkip), - event.on_mouse_up(EndUserSkip), - event.on_input(fn(_) { SelectPosition(Ephemeral) }), - ]), + ..track.view(model) ]), ], ) diff --git a/src/elekf/web/components/player/small.gleam b/src/elekf/web/components/player/small.gleam index 502078c..69a7670 100644 --- a/src/elekf/web/components/player/small.gleam +++ b/src/elekf/web/components/player/small.gleam @@ -1,28 +1,20 @@ -import gleam/int import gleam/option import lustre/element.{text} -import lustre/element/html.{div, input, p} +import lustre/element/html.{div, p} import lustre/attribute import lustre/event import elekf/web/components/icon.{Alt, icon} -import elekf/web/components/track_length.{track_length} import elekf/web/components/button_group import elekf/web/components/button import elekf/web/components/link import elekf/web/components/thumbnail -import elekf/web/components/player/actions.{ - Commit, EndUserSkip, Ephemeral, NextTrack, Pause, Play, PrevTrack, - SelectPosition, StartUserSkip, -} +import elekf/web/components/player/actions.{NextTrack, Pause, Play, PrevTrack} import elekf/web/components/player/model.{type Model} +import elekf/web/components/player/track import elekf/web/router pub fn view(model: Model) { let is_playing = model.state == model.Playing - let current_time_padding = case model.track.length > 3600 { - True -> track_length.Hours - False -> track_length.Auto - } div( [ @@ -78,33 +70,7 @@ pub fn view(model: Model) { [icon("arrows-angle-expand", Alt("Full screen player"))], ), ]), - p( - [ - attribute.id("player-time-elapsed"), - attribute.class("player-time"), - attribute.attribute("aria-label", "Time elapsed"), - ], - [track_length(model.position, current_time_padding)], - ), - p( - [ - attribute.id("player-time-total"), - attribute.class("player-time"), - attribute.attribute("aria-label", "Total time"), - ], - [track_length(model.track.length, track_length.Auto)], - ), - input([ - attribute.id("player-track"), - attribute.type_("range"), - attribute.min("0"), - attribute.max(int.to_string(model.track.length)), - attribute.attribute("aria-label", "Track position"), - event.on("change", fn(_) { Ok(SelectPosition(Commit)) }), - event.on_mouse_down(StartUserSkip), - event.on_mouse_up(EndUserSkip), - event.on_input(fn(_) { SelectPosition(Ephemeral) }), - ]), + ..track.view(model) ]), ], ) diff --git a/src/elekf/web/components/player/track.gleam b/src/elekf/web/components/player/track.gleam new file mode 100644 index 0000000..1c234ba --- /dev/null +++ b/src/elekf/web/components/player/track.gleam @@ -0,0 +1,55 @@ +//// A track for visualising the current song's progress and skipping it back +//// and forth, and additional timestamps. + +import gleam/int +import gleam/dynamic +import lustre/element/html.{input, p} +import lustre/attribute +import lustre/event +import elekf/web/components/track_length.{track_length} +import elekf/web/components/player/model +import elekf/web/components/player/actions.{ + Commit, EndUserSkip, Ephemeral, SelectPosition, StartUserSkip, +} + +pub fn view(model: model.Model) { + let current_time_padding = case model.track.length > 3600 { + True -> track_length.Hours + False -> track_length.Auto + } + + let track_pos = dynamic.from(int.to_string(model.position)) + + [ + p( + [ + attribute.id("player-time-elapsed"), + attribute.class("player-time"), + attribute.attribute("aria-label", "Time elapsed"), + ], + [track_length(model.position, current_time_padding)], + ), + p( + [ + attribute.id("player-time-total"), + attribute.class("player-time"), + attribute.attribute("aria-label", "Total time"), + ], + [track_length(model.track.length, track_length.Auto)], + ), + input([ + attribute.id("player-track"), + attribute.type_("range"), + attribute.min("0"), + attribute.max(int.to_string(model.track.length)), + attribute.value(track_pos), + attribute.attribute("aria-label", "Track position"), + event.on("change", fn(_) { Ok(SelectPosition(Commit)) }), + event.on_mouse_down(StartUserSkip), + event.on_mouse_up(EndUserSkip), + event.on("touchstart", fn(_) { Ok(StartUserSkip) }), + event.on("touchend", fn(_) { Ok(EndUserSkip) }), + event.on_input(fn(_) { SelectPosition(Ephemeral) }), + ]), + ] +} diff --git a/src/player_ffi.mjs b/src/player_ffi.mjs index e71b79b..65bb271 100644 --- a/src/player_ffi.mjs +++ b/src/player_ffi.mjs @@ -41,11 +41,6 @@ export function currentTrackPosition() { return track.valueAsNumber; } -export function setTrackTo(pos) { - getTrack(); - track.value = String(pos); -} - export function createAudioContext() { return new globalThis.AudioContext(); } @@ -75,7 +70,8 @@ function getPlayer() { } function getTrack() { - if (track === undefined) { + // Track element might not be fetched yet, or it might have been removed from the DOM + if (track === undefined || !track.isConnected) { track = document.getElementById(track_id); } }