From f4450206b6a339b4c8b80a7a2ed9e380393ce264 Mon Sep 17 00:00:00 2001 From: Mikko Ahlroth Date: Sun, 25 Aug 2024 21:29:57 +0300 Subject: [PATCH] Fix events and scrolling from history --- manifest.toml | 2 +- src/elekf/web/authed_view.gleam | 10 +-- src/elekf/web/components/library_view.gleam | 67 ++++++++++++--------- src/elekf/web/events/scroll_to.gleam | 22 +++---- src/elekf/web/events/start_play.gleam | 24 +++----- src/library_view_ffi.mjs | 17 +----- 6 files changed, 63 insertions(+), 79 deletions(-) diff --git a/manifest.toml b/manifest.toml index 5c739c2..340c3e4 100644 --- a/manifest.toml +++ b/manifest.toml @@ -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" }, diff --git a/src/elekf/web/authed_view.gleam b/src/elekf/web/authed_view.gleam index 4414795..d9c898a 100644 --- a/src/elekf/web/authed_view.gleam +++ b/src/elekf/web/authed_view.gleam @@ -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), ], diff --git a/src/elekf/web/components/library_view.gleam b/src/elekf/web/components/library_view.gleam index 83e84b2..9df4fd2 100644 --- a/src/elekf/web/components/library_view.gleam +++ b/src/elekf/web/components/library_view.gleam @@ -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) -} diff --git a/src/elekf/web/events/scroll_to.gleam b/src/elekf/web/events/scroll_to.gleam index 1c359a9..4c15aa0 100644 --- a/src/elekf/web/events/scroll_to.gleam +++ b/src/elekf/web/events/scroll_to.gleam @@ -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) } diff --git a/src/elekf/web/events/start_play.gleam b/src/elekf/web/events/start_play.gleam index cf4e0d4..ff60ef5 100644 --- a/src/elekf/web/events/start_play.gleam +++ b/src/elekf/web/events/start_play.gleam @@ -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( - EventData, - dynamic.field("queue", play_queue_codec.decode), - dynamic.field("position", dynamic.int), - )(detail)) + use detail <- result.try(dynamic.field( + "detail", + dynamic.decode2( + EventData, + dynamic.field("queue", play_queue_codec.decode), + dynamic.field("position", dynamic.int), + ), + )(data)) - Ok(event_data) + Ok(detail) } diff --git a/src/library_view_ffi.mjs b/src/library_view_ffi.mjs index 39a7ded..3ad57ee 100644 --- a/src/library_view_ffi.mjs +++ b/src/library_view_ffi.mjs @@ -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"); }