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

View file

@ -108,7 +108,6 @@ pub type Model(a, filter) {
sorter: Sorter(a), sorter: Sorter(a),
search: search.Model, search: search.Model,
settings: option.Option(common.Settings), settings: option.Option(common.Settings),
history: history_store.StorageFormat,
history_api: history_store.HistoryStorage, history_api: history_store.HistoryStorage,
styles_path: String, styles_path: String,
) )
@ -175,24 +174,9 @@ pub fn render(
pub fn request_scroll(pos: Float) -> Nil pub fn request_scroll(pos: Float) -> Nil
pub fn init(id, filter, data_getter, shuffler, sorter, styles_path) { 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_api = history_store.get_api()
let history = get_view_history(history_api)
let scroll_to = dict.get(history.scrolls, id) let scroll_to_effect = get_history_scroll(history_api, 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()
}
#( #(
Model( Model(
@ -205,20 +189,26 @@ pub fn init(id, filter, data_getter, shuffler, sorter, styles_path) {
sorter:, sorter:,
search: search.init(), search: search.init(),
settings: option.None, settings: option.None,
history:,
history_api:, history_api:,
styles_path:, styles_path:,
), ),
effect.batch([scrollend_effect, scroll_to_effect]), scroll_to_effect,
) )
} }
pub fn update(model: Model(a, filter), msg) { pub fn update(model: Model(a, filter), msg) {
case msg { case msg {
LibraryUpdated(library) -> #( LibraryUpdated(library) -> {
update_data(Model(..model, library_status: new_library(library))), let scroll_effect = case model.library_status {
effect.none(), NoLibrary -> get_history_scroll(model.history_api, model.id)
) _ -> effect.none()
}
#(
update_data(Model(..model, library_status: HaveLibrary(library))),
scroll_effect,
)
}
SettingsUpdated(settings) -> #( SettingsUpdated(settings) -> #(
Model(..model, settings: settings), Model(..model, settings: settings),
effect.none(), effect.none(),
@ -280,7 +270,11 @@ pub fn library_view(
element.fragment([ element.fragment([
styles, styles,
div( div(
[attribute.id("library-list"), scroll_to.on(ScrollRequested)], [
attribute.id("library-list"),
event.on("scrollend", handle_scrollend),
scroll_to.on(ScrollRequested),
],
list.append( list.append(
[ [
search.view(model.search) 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) { fn get_view_history(history_api) {
result.unwrap(history_store.read(history_api), history_store.new()) result.unwrap(history_store.read(history_api), history_store.new())
} }
@external(javascript, "../../../library_view_ffi.mjs", "addScrollendListener") fn handle_scrollend(e: dynamic.Dynamic) {
fn add_scrollend_listener(callback: fn(Float) -> Nil) -> Nil use position <- result.try(dynamic.field(
"target",
dynamic.field("scrollTop", dynamic.float),
)(e))
Ok(ListScrolled(position))
}
@external(javascript, "../../../library_view_ffi.mjs", "scrollTo") @external(javascript, "../../../library_view_ffi.mjs", "scrollTo")
fn scroll_to(pos: Float) -> Nil 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 elekf/utils/custom_event
import forbidden_stdlib/dynamic as forbidden_dynamic
import gleam/dynamic import gleam/dynamic
import gleam/json import gleam/json
import gleam/result import gleam/result
@ -12,7 +11,7 @@ pub type EventData {
} }
pub fn emit(pos: Float) { 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) { 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) { 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) { fn decoder(data: dynamic.Dynamic) {
let e: CustomEvent = forbidden_dynamic.unsafe_coerce(data) use detail <- result.try(dynamic.field(
use detail <- result.try( "detail",
custom_event.get_detail(e) dynamic.field("pos", dynamic.float),
|> result.replace_error([ )(data))
dynamic.DecodeError("event detail", "no detail", []), Ok(detail)
]),
)
use event_data <- result.try(dynamic.float(detail))
Ok(event_data)
} }

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/codec/play_queue as play_queue_codec
import elekf/web/play_queue.{type PlayQueue} import elekf/web/play_queue.{type PlayQueue}
import forbidden_stdlib/dynamic as forbidden_dynamic
import gleam/dynamic import gleam/dynamic
import gleam/json import gleam/json
import gleam/result import gleam/result
@ -32,18 +30,14 @@ pub fn on(msg: fn(PlayQueue, Int) -> b) {
} }
fn decoder(data: dynamic.Dynamic) { fn decoder(data: dynamic.Dynamic) {
let e: CustomEvent = forbidden_dynamic.unsafe_coerce(data) use detail <- result.try(dynamic.field(
use detail <- result.try( "detail",
custom_event.get_detail(e) dynamic.decode2(
|> result.replace_error([ EventData,
dynamic.DecodeError("event detail", "no detail", []), dynamic.field("queue", play_queue_codec.decode),
]), dynamic.field("position", dynamic.int),
) ),
use event_data <- result.try(dynamic.decode2( )(data))
EventData,
dynamic.field("queue", play_queue_codec.decode),
dynamic.field("position", dynamic.int),
)(detail))
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) { export function scrollTo(pos) {
const el = getEl(); const el = getEl();
if (el) { if (el) {
@ -32,5 +19,7 @@ export function scrollTo(pos) {
} }
function getEl() { function getEl() {
return document.getElementById("library-list"); return document
.getElementById("library-view")
.shadowRoot?.getElementById("library-list");
} }