Fix events and scrolling from history

This commit is contained in:
Mikko Ahlroth 2024-08-25 21:29:57 +03:00
parent 8570d4e39e
commit f4450206b6
6 changed files with 63 additions and 79 deletions

View file

@ -12,7 +12,7 @@ packages = [
{ name = "gleam_otp", version = "0.11.2", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "517FFB679E44AD71D059F3EF6A17BA6EFC8CB94FA174D52E22FB6768CF684D78" },
{ name = "gleam_stdlib", version = "0.40.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "86606B75A600BBD05E539EB59FABC6E307EEEA7B1E5865AFB6D980A93BCB2181" },
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
{ name = "lustre", version = "4.3.5", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "BED65BD6A23439FB155A5BE166ED3C6BC20DED844FA9BB21840860951BC8E153" },
{ name = "lustre", version = "4.3.6", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "A122A11C761E2366EEA4649CBBE5C162BCA8EF5D78C0B1C7AACBA6E824AE9F5D" },
{ name = "plinth", version = "0.4.12", build_tools = ["gleam"], requirements = ["conversation", "gleam_javascript", "gleam_json", "gleam_stdlib"], otp_app = "plinth", source = "hex", outer_checksum = "3727B517C05BD4D49A4AF34BA7E63E03CA77B4E8AD2A4DCE60266B28717C1F9A" },
{ name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" },
{ name = "thoas", version = "1.2.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "E38697EDFFD6E91BD12CEA41B155115282630075C2A727E7A6B2947F5408B86A" },

View file

@ -289,19 +289,19 @@ pub fn view(model: Model) {
case model.view {
library_view.Tracks ->
tracks_view.render(library_if_loaded(model), model.settings, [
attribute.id("tracks-view"),
attribute.id("library-view"),
attribute.class("glass-bg"),
start_play.on(StartPlay),
])
library_view.Artists ->
artists_view.render(library_if_loaded(model), model.settings, [
attribute.id("artists-view"),
attribute.id("library-view"),
attribute.class("glass-bg"),
start_play.on(StartPlay),
])
library_view.Albums ->
albums_view.render(library_if_loaded(model), model.settings, [
attribute.id("albums-view"),
attribute.id("library-view"),
attribute.class("glass-bg"),
start_play.on(StartPlay),
])
@ -311,7 +311,7 @@ pub fn view(model: Model) {
id,
model.settings,
[
attribute.id("single-artist-view"),
attribute.id("library-view"),
attribute.class("glass-bg"),
start_play.on(StartPlay),
],
@ -322,7 +322,7 @@ pub fn view(model: Model) {
id,
model.settings,
[
attribute.id("single-album-view"),
attribute.id("library-view"),
attribute.class("glass-bg"),
start_play.on(StartPlay),
],

View file

@ -108,7 +108,6 @@ pub type Model(a, filter) {
sorter: Sorter(a),
search: search.Model,
settings: option.Option(common.Settings),
history: history_store.StorageFormat,
history_api: history_store.HistoryStorage,
styles_path: String,
)
@ -175,24 +174,9 @@ pub fn render(
pub fn request_scroll(pos: Float) -> Nil
pub fn init(id, filter, data_getter, shuffler, sorter, styles_path) {
let scrollend_effect =
effect.from(fn(dispatch) {
lustre_utils.after_next_render(fn() {
add_scrollend_listener(fn(pos) { dispatch(ListScrolled(pos)) })
})
})
let history_api = history_store.get_api()
let history = get_view_history(history_api)
let scroll_to = dict.get(history.scrolls, id)
let scroll_to_effect = case scroll_to {
Ok(pos) if pos >. 0.0 ->
effect.from(fn(dispatch) {
lustre_utils.after_next_render(fn() { dispatch(ScrollRequested(pos)) })
})
_ -> effect.none()
}
let scroll_to_effect = get_history_scroll(history_api, id)
#(
Model(
@ -205,20 +189,26 @@ pub fn init(id, filter, data_getter, shuffler, sorter, styles_path) {
sorter:,
search: search.init(),
settings: option.None,
history:,
history_api:,
styles_path:,
),
effect.batch([scrollend_effect, scroll_to_effect]),
scroll_to_effect,
)
}
pub fn update(model: Model(a, filter), msg) {
case msg {
LibraryUpdated(library) -> #(
update_data(Model(..model, library_status: new_library(library))),
effect.none(),
LibraryUpdated(library) -> {
let scroll_effect = case model.library_status {
NoLibrary -> get_history_scroll(model.history_api, model.id)
_ -> effect.none()
}
#(
update_data(Model(..model, library_status: HaveLibrary(library))),
scroll_effect,
)
}
SettingsUpdated(settings) -> #(
Model(..model, settings: settings),
effect.none(),
@ -280,7 +270,11 @@ pub fn library_view(
element.fragment([
styles,
div(
[attribute.id("library-list"), scroll_to.on(ScrollRequested)],
[
attribute.id("library-list"),
event.on("scrollend", handle_scrollend),
scroll_to.on(ScrollRequested),
],
list.append(
[
search.view(model.search)
@ -407,16 +401,29 @@ fn update_data(model: Model(a, filter)) {
}
}
fn get_history_scroll(history_api: history_store.HistoryStorage, id: String) {
let history = get_view_history(history_api).scrolls
let scroll_to = dict.get(history, id)
case scroll_to {
Ok(pos) if pos >. 0.0 ->
effect.from(fn(dispatch) {
lustre_utils.after_next_render(fn() { dispatch(ScrollRequested(pos)) })
})
_ -> effect.none()
}
}
fn get_view_history(history_api) {
result.unwrap(history_store.read(history_api), history_store.new())
}
@external(javascript, "../../../library_view_ffi.mjs", "addScrollendListener")
fn add_scrollend_listener(callback: fn(Float) -> Nil) -> Nil
fn handle_scrollend(e: dynamic.Dynamic) {
use position <- result.try(dynamic.field(
"target",
dynamic.field("scrollTop", dynamic.float),
)(e))
Ok(ListScrolled(position))
}
@external(javascript, "../../../library_view_ffi.mjs", "scrollTo")
fn scroll_to(pos: Float) -> Nil
fn new_library(library: Library) -> LibraryStatus {
HaveLibrary(library)
}

View file

@ -1,5 +1,4 @@
import elekf/utils/custom_event.{type CustomEvent}
import forbidden_stdlib/dynamic as forbidden_dynamic
import elekf/utils/custom_event
import gleam/dynamic
import gleam/json
import gleam/result
@ -12,7 +11,7 @@ pub type EventData {
}
pub fn emit(pos: Float) {
event.emit(event_name, json.float(pos))
event.emit(event_name, json.object([#("pos", json.float(pos))]))
}
pub fn on(msg: fn(Float) -> b) {
@ -24,18 +23,13 @@ pub fn on(msg: fn(Float) -> b) {
}
pub fn js_custom_event(pos: Float) {
custom_event.new(event_name, EventData(pos))
custom_event.new(event_name, json.object([#("pos", json.float(pos))]))
}
fn decoder(data: dynamic.Dynamic) {
let e: CustomEvent = forbidden_dynamic.unsafe_coerce(data)
use detail <- result.try(
custom_event.get_detail(e)
|> result.replace_error([
dynamic.DecodeError("event detail", "no detail", []),
]),
)
use event_data <- result.try(dynamic.float(detail))
Ok(event_data)
use detail <- result.try(dynamic.field(
"detail",
dynamic.field("pos", dynamic.float),
)(data))
Ok(detail)
}

View file

@ -1,7 +1,5 @@
import elekf/utils/custom_event.{type CustomEvent}
import elekf/web/codec/play_queue as play_queue_codec
import elekf/web/play_queue.{type PlayQueue}
import forbidden_stdlib/dynamic as forbidden_dynamic
import gleam/dynamic
import gleam/json
import gleam/result
@ -32,18 +30,14 @@ pub fn on(msg: fn(PlayQueue, Int) -> b) {
}
fn decoder(data: dynamic.Dynamic) {
let e: CustomEvent = forbidden_dynamic.unsafe_coerce(data)
use detail <- result.try(
custom_event.get_detail(e)
|> result.replace_error([
dynamic.DecodeError("event detail", "no detail", []),
]),
)
use event_data <- result.try(dynamic.decode2(
use detail <- result.try(dynamic.field(
"detail",
dynamic.decode2(
EventData,
dynamic.field("queue", play_queue_codec.decode),
dynamic.field("position", dynamic.int),
)(detail))
),
)(data))
Ok(event_data)
Ok(detail)
}

View file

@ -8,19 +8,6 @@ export function requestScroll(pos) {
}
}
export function addScrollendListener(callback) {
const el = getEl();
if (el) {
el.addEventListener(
"scrollend",
() => {
callback(el.scrollTop);
},
{ passive: true }
);
}
}
export function scrollTo(pos) {
const el = getEl();
if (el) {
@ -32,5 +19,7 @@ export function scrollTo(pos) {
}
function getEl() {
return document.getElementById("library-list");
return document
.getElementById("library-view")
.shadowRoot?.getElementById("library-list");
}