This commit is contained in:
Mikko Ahlroth 2024-02-27 12:06:22 +02:00
parent 830918c344
commit 773627bd5d
7 changed files with 42 additions and 149 deletions

View file

@ -1,15 +1,15 @@
//// The library stores the music library retrieved from iBroadcast.
import gleam/map.{type Map}
import gleam/dict.{type Dict}
import elekf/library/track.{type Track}
import elekf/library/album.{type Album}
import elekf/library/artist.{type Artist}
pub type Library {
Library(
albums: Map(Int, Album),
artists: Map(Int, Artist),
tracks: Map(Int, Track),
albums: Dict(Int, Album),
artists: Dict(Int, Artist),
tracks: Dict(Int, Track),
)
}
@ -18,38 +18,38 @@ pub const invalid_id = -1
/// Gets an empty library for use as a default value.
pub fn empty() {
Library(albums: map.new(), artists: map.new(), tracks: map.new())
Library(albums: dict.new(), artists: dict.new(), tracks: dict.new())
}
/// Gets an album from the library based on ID.
pub fn get_album(library: Library, id: Int) {
map.get(library.albums, id)
dict.get(library.albums, id)
}
/// Gets an artist from the library based on ID.
pub fn get_artist(library: Library, id: Int) {
map.get(library.artists, id)
dict.get(library.artists, id)
}
/// Gets a track from the library based on ID.
pub fn get_track(library: Library, id: Int) {
map.get(library.tracks, id)
dict.get(library.tracks, id)
}
/// Gets an album from the library, asserting that it exists.
pub fn assert_album(library: Library, id: Int) {
let assert Ok(album) = map.get(library.albums, id)
let assert Ok(album) = dict.get(library.albums, id)
album
}
/// Gets an artist from the library, asserting that it exists.
pub fn assert_artist(library: Library, id: Int) {
let assert Ok(artist) = map.get(library.artists, id)
let assert Ok(artist) = dict.get(library.artists, id)
artist
}
/// Gets a track from the library, asserting that it exists.
pub fn assert_track(library: Library, id: Int) {
let assert Ok(track) = map.get(library.tracks, id)
let assert Ok(track) = dict.get(library.tracks, id)
track
}

View file

@ -16,10 +16,7 @@ import lustre/event
import elekf/utils/order.{type Sorter}
import elekf/library.{type Library}
import elekf/library/track.{type Track}
import elekf/library/artist.{type Artist}
import elekf/library/album.{type Album}
import elekf/web/events/start_play
import elekf/web/events/show_artist
import elekf/web/components/search
import elekf/web/components/library_item.{type LibraryItem}
import elekf/web/components/shuffle_all
@ -70,9 +67,7 @@ pub type Msg {
SettingsUpdated(option.Option(common.Settings))
ShuffleAll
StartPlay(List(LibraryItem(Track)), Int)
ShowArtist(LibraryItem(Artist))
Search(search.Msg)
AlbumExpandToggled(LibraryItem(Album))
FilterUpdated
}
@ -168,15 +163,11 @@ pub fn update(model, msg) {
)
ShuffleAll -> #(model, shuffle_all(model))
StartPlay(tracks, position) -> #(model, start_play.emit(tracks, position))
ShowArtist(artist) -> #(model, show_artist.emit(artist))
Search(search_msg) -> {
let search_model = search.update(model.search, search_msg)
#(Model(..model, search: search_model), effect.none())
}
// Base case, this should be handled in an implementing view
AlbumExpandToggled(_album) -> #(model, effect.none())
FilterUpdated -> #(update_data(model, model.library), effect.none())
}
}

View file

@ -3,20 +3,14 @@
import gleam/list
import gleam/option
import gleam/int
import lustre/element/html.{div, h3, p}
import lustre/element/html.{h3, p}
import lustre/element.{text}
import lustre/attribute
import lustre/event
import elekf/library.{type Library}
import elekf/library/album.{type Album}
import elekf/library/track.{type Track}
import elekf/library/album_utils
import elekf/library/track_utils
import elekf/web/components/library_view.{AlbumExpandToggled, ShuffleAll}
import elekf/web/components/library_item.{type LibraryItem}
import elekf/web/components/library_views/track_item
import elekf/web/components/thumbnail
import elekf/web/components/shuffle_all
import elekf/web/components/link
import elekf/web/common.{type Settings}
import elekf/web/router
@ -25,7 +19,6 @@ pub fn view(
library: Library,
settings: option.Option(Settings),
item: LibraryItem(Album),
show_tracks: Bool,
) {
let #(album_id, album) = item
let tracks = album_utils.get_tracks(library, album)
@ -35,49 +28,23 @@ pub fn view(
}
let assert Ok(first_track) = list.first(tracks)
list.append(
[
link.link(
router.to_hash(router.Album(album_id)),
"library-item album-item",
[attribute.id("album-list-" <> int.to_string(album_id))],
[
thumbnail.maybe_item_thumbnail(
settings,
{ first_track.1 }.artwork_id,
album.name,
),
h3([attribute.class("album-item-title")], [text(album.name)]),
p([attribute.class("album-item-artist")], [text(artist_name)]),
p([attribute.class("album-item-tracks-meta")], [
text(int.to_string(list.length(album.tracks)) <> " tracks"),
]),
],
),
],
case show_tracks {
True -> [view_tracks(library, tracks)]
False -> []
},
)
}
pub fn view_tracks(library: Library, tracks: List(LibraryItem(Track))) {
let tracks =
list.sort(tracks, fn(a, b) { track_utils.sort_by_track_number(a.1, b.1) })
div(
[
attribute.class(
"library-item-expanded-contents album-item-expanded-tracks",
),
],
list.flatten([
[shuffle_all.view([event.on_click(ShuffleAll)])],
list.index_map(tracks, fn(track_item, index) {
track_item.view(library, tracks, index, track_item, "album-tracks-list")
})
|> list.flatten(),
]),
)
[
link.link(
router.to_hash(router.Album(album_id)),
"library-item album-item",
[attribute.id("album-list-" <> int.to_string(album_id))],
[
thumbnail.maybe_item_thumbnail(
settings,
{ first_track.1 }.artwork_id,
album.name,
),
h3([attribute.class("album-item-title")], [text(album.name)]),
p([attribute.class("album-item-artist")], [text(artist_name)]),
p([attribute.class("album-item-tracks-meta")], [
text(int.to_string(list.length(album.tracks)) <> " tracks"),
]),
],
),
]
}

View file

@ -2,7 +2,7 @@
import gleam/string
import gleam/list
import gleam/map
import gleam/dict
import gleam/option
import gleam/dynamic
import gleam/result
@ -10,11 +10,10 @@ import lustre
import lustre/effect
import lustre/attribute
import lustre/element
import elekf/utils/misc
import elekf/library.{type Library}
import elekf/library/album.{type Album}
import elekf/library/album_utils
import elekf/web/components/library_view.{AlbumExpandToggled}
import elekf/web/components/library_view
import elekf/web/components/library_item.{type LibraryItem}
import elekf/web/components/library_views/album_item
import elekf/web/common
@ -22,7 +21,7 @@ import elekf/web/common
const component_name = "albums-view"
type Model {
Model(library_view: library_view.Model(Album), expanded_album: Int)
Model(library_view: library_view.Model(Album))
}
type Msg {
@ -37,7 +36,7 @@ pub fn register() {
update,
generate_view(search_filter),
library_view.generic_attributes()
|> map.map_values(fn(_key, decoder) {
|> dict.map_values(fn(_key, decoder) {
fn(data: dynamic.Dynamic) {
data
|> decoder()
@ -66,36 +65,20 @@ fn init() {
album_utils.sort_by_name,
)
#(
Model(library_view: lib_m, expanded_album: library.invalid_id),
effect.map(lib_e, LibraryViewMsg),
)
#(Model(library_view: lib_m), effect.map(lib_e, LibraryViewMsg))
}
fn update(model: Model, msg) {
case msg {
LibraryViewMsg(AlbumExpandToggled(album)) -> {
#(
Model(
..model,
expanded_album: misc.toggle(
model.expanded_album,
album.0,
library.invalid_id,
),
),
effect.none(),
)
}
LibraryViewMsg(lib_msg) -> {
let #(lib_m, lib_e) = library_view.update(model.library_view, lib_msg)
#(Model(..model, library_view: lib_m), effect.map(lib_e, LibraryViewMsg))
#(Model(library_view: lib_m), effect.map(lib_e, LibraryViewMsg))
}
}
}
fn data_getter(library: Library) {
map.to_list(library.albums)
dict.to_list(library.albums)
}
fn shuffler(library, items: List(LibraryItem(Album))) {
@ -121,10 +104,5 @@ fn generate_view(search_filter: library_view.SearchFilter(Album)) {
}
fn view(model: Model, item: LibraryItem(Album)) {
album_item.view(
model.library_view.library,
model.library_view.settings,
item,
item.0 == model.expanded_album,
)
album_item.view(model.library_view.library, model.library_view.settings, item)
}

View file

@ -189,12 +189,7 @@ fn view(
}
fn album_view(model: Model, item: LibraryItem(Album)) {
album_item.view(
model.library_view.library,
model.library_view.settings,
item,
False,
)
album_item.view(model.library_view.library, model.library_view.settings, item)
}
fn id_decode(data: dynamic.Dynamic) {

View file

@ -2,7 +2,7 @@
import gleam/string
import gleam/list
import gleam/map
import gleam/dict
import gleam/option
import lustre/attribute
import elekf/library.{type Library}
@ -37,7 +37,7 @@ pub fn render(
}
fn data_getter(library: Library) {
map.to_list(library.tracks)
dict.to_list(library.tracks)
}
fn shuffler(_library, items) {

View file

@ -1,38 +0,0 @@
import gleam/result
import gleam/dynamic
import lustre/event
import elekf/library/artist.{type Artist}
import elekf/web/components/library_item.{type LibraryItem}
import elekf/utils/custom_event.{type CustomEvent}
const event_name = "show-artist"
pub type EventData {
EventData(artist: LibraryItem(Artist))
}
pub fn emit(artist) {
event.emit(event_name, EventData(artist))
}
pub fn on(msg: fn(LibraryItem(Artist)) -> b) {
event.on(
event_name,
fn(data) {
data
|> decoder
|> result.map(fn(e) { msg(e.artist) })
},
)
}
fn decoder(data: dynamic.Dynamic) {
let e: CustomEvent = dynamic.unsafe_coerce(data)
let detail = custom_event.get_detail(e)
let event_data: EventData =
detail
|> dynamic.from()
|> dynamic.unsafe_coerce()
Ok(event_data)
}