Add sorting
This commit is contained in:
parent
ee70f6742c
commit
ccecb20aea
10 changed files with 105 additions and 5 deletions
|
@ -1,7 +1,12 @@
|
||||||
import gleam/list
|
import gleam/list
|
||||||
|
import gleam/string
|
||||||
|
import gleam/int
|
||||||
|
import elekf/utils/order
|
||||||
import elekf/library.{type Library}
|
import elekf/library.{type Library}
|
||||||
import elekf/library/album.{type Album}
|
import elekf/library/album.{type Album}
|
||||||
|
|
||||||
|
const year_sorters = [year_compare, name_compare]
|
||||||
|
|
||||||
/// Get the individual tracks in an album.
|
/// Get the individual tracks in an album.
|
||||||
pub fn get_tracks(library: Library, album: Album) {
|
pub fn get_tracks(library: Library, album: Album) {
|
||||||
list.map(
|
list.map(
|
||||||
|
@ -9,3 +14,21 @@ pub fn get_tracks(library: Library, album: Album) {
|
||||||
fn(track_id) { #(track_id, library.assert_track(library, track_id)) },
|
fn(track_id) { #(track_id, library.assert_track(library, track_id)) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sort given albums by their lowercased names.
|
||||||
|
pub fn sort_by_name(a: Album, b: Album) {
|
||||||
|
name_compare(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sort given albums by their publishing year first, then lowercased names.
|
||||||
|
pub fn sort_by_year(a: Album, b: Album) {
|
||||||
|
order.compare_by_multiple(year_sorters, a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name_compare(a: Album, b: Album) {
|
||||||
|
string.compare(a.name_lower, b.name_lower)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn year_compare(a: Album, b: Album) {
|
||||||
|
int.compare(a.year, b.year)
|
||||||
|
}
|
||||||
|
|
7
src/elekf/library/artist_utils.gleam
Normal file
7
src/elekf/library/artist_utils.gleam
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import gleam/string
|
||||||
|
import elekf/library/artist.{type Artist}
|
||||||
|
|
||||||
|
/// Sort given artists by their lowercased names.
|
||||||
|
pub fn sort_by_name(a: Artist, b: Artist) {
|
||||||
|
string.compare(a.name_lower, b.name_lower)
|
||||||
|
}
|
24
src/elekf/library/track_utils.gleam
Normal file
24
src/elekf/library/track_utils.gleam
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import gleam/string
|
||||||
|
import gleam/int
|
||||||
|
import elekf/utils/order
|
||||||
|
import elekf/library/track.{type Track}
|
||||||
|
|
||||||
|
const track_number_sorters = [order_compare, name_compare]
|
||||||
|
|
||||||
|
/// Sort given tracks by their lowercased names.
|
||||||
|
pub fn sort_by_name(a: Track, b: Track) {
|
||||||
|
name_compare(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sort given tracks by their track number first, lowercased title second.
|
||||||
|
pub fn sort_by_track_number(a: Track, b: Track) {
|
||||||
|
order.compare_by_multiple(track_number_sorters, a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn order_compare(a: Track, b: Track) {
|
||||||
|
int.compare(a.number, b.number)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name_compare(a: Track, b: Track) {
|
||||||
|
string.compare(a.title_lower, b.title_lower)
|
||||||
|
}
|
21
src/elekf/utils/order.gleam
Normal file
21
src/elekf/utils/order.gleam
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import gleam/order
|
||||||
|
import gleam/list
|
||||||
|
|
||||||
|
/// A function that sorts two values.
|
||||||
|
pub type Sorter(a) =
|
||||||
|
fn(a, a) -> order.Order
|
||||||
|
|
||||||
|
/// Compare two values by using multiple sorters. The comparison will stop after
|
||||||
|
/// the first sorter that returns something other than `order.Eq`.
|
||||||
|
pub fn compare_by_multiple(sorters: List(Sorter(a)), a: a, b: a) {
|
||||||
|
list.fold_until(
|
||||||
|
sorters,
|
||||||
|
order.Eq,
|
||||||
|
fn(prev, sorter) {
|
||||||
|
case prev {
|
||||||
|
order.Eq -> list.Continue(sorter(a, b))
|
||||||
|
other -> list.Stop(other)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
|
@ -12,6 +12,7 @@ import lustre/element.{text}
|
||||||
import lustre/element/html.{div, h3}
|
import lustre/element/html.{div, h3}
|
||||||
import lustre/attribute
|
import lustre/attribute
|
||||||
import lustre/event
|
import lustre/event
|
||||||
|
import elekf/utils/order.{type Sorter} as order_utils
|
||||||
import elekf/library.{type Library}
|
import elekf/library.{type Library}
|
||||||
import elekf/library/track.{type Track}
|
import elekf/library/track.{type Track}
|
||||||
import elekf/library/artist.{type Artist}
|
import elekf/library/artist.{type Artist}
|
||||||
|
@ -78,6 +79,7 @@ pub type Model(a) {
|
||||||
data: List(LibraryItem(a)),
|
data: List(LibraryItem(a)),
|
||||||
data_getter: DataGetter(a),
|
data_getter: DataGetter(a),
|
||||||
shuffler: Shuffler(a),
|
shuffler: Shuffler(a),
|
||||||
|
sorter: Sorter(a),
|
||||||
search: search.Model,
|
search: search.Model,
|
||||||
settings: option.Option(common.Settings),
|
settings: option.Option(common.Settings),
|
||||||
)
|
)
|
||||||
|
@ -97,11 +99,12 @@ pub fn register(
|
||||||
data_getter: DataGetter(a),
|
data_getter: DataGetter(a),
|
||||||
item_view: ItemView(a),
|
item_view: ItemView(a),
|
||||||
shuffler: Shuffler(a),
|
shuffler: Shuffler(a),
|
||||||
|
sorter: Sorter(a),
|
||||||
search_filter: SearchFilter(a),
|
search_filter: SearchFilter(a),
|
||||||
) {
|
) {
|
||||||
lustre.component(
|
lustre.component(
|
||||||
name,
|
name,
|
||||||
fn() { init(library.empty(), data_getter, shuffler) },
|
fn() { init(library.empty(), data_getter, shuffler, sorter) },
|
||||||
update,
|
update,
|
||||||
generate_view(item_view, search_filter),
|
generate_view(item_view, search_filter),
|
||||||
generic_attributes(),
|
generic_attributes(),
|
||||||
|
@ -134,13 +137,14 @@ pub fn render(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(library, data_getter, shuffler) {
|
pub fn init(library, data_getter, shuffler, sorter) {
|
||||||
#(
|
#(
|
||||||
Model(
|
Model(
|
||||||
library,
|
library,
|
||||||
data_getter(library),
|
data_getter(library),
|
||||||
data_getter,
|
data_getter,
|
||||||
shuffler,
|
shuffler,
|
||||||
|
sorter,
|
||||||
search.init(),
|
search.init(),
|
||||||
option.None,
|
option.None,
|
||||||
),
|
),
|
||||||
|
@ -151,7 +155,13 @@ pub fn init(library, data_getter, shuffler) {
|
||||||
pub fn update(model, msg) {
|
pub fn update(model, msg) {
|
||||||
case msg {
|
case msg {
|
||||||
LibraryUpdated(library) -> #(
|
LibraryUpdated(library) -> #(
|
||||||
Model(..model, library: library, data: model.data_getter(library)),
|
Model(
|
||||||
|
..model,
|
||||||
|
library: library,
|
||||||
|
data: library
|
||||||
|
|> model.data_getter()
|
||||||
|
|> list.sort(fn(a, b) { model.sorter(a.1, b.1) }),
|
||||||
|
),
|
||||||
effect.none(),
|
effect.none(),
|
||||||
)
|
)
|
||||||
SettingsUpdated(settings) -> #(
|
SettingsUpdated(settings) -> #(
|
||||||
|
|
|
@ -11,6 +11,7 @@ import elekf/library.{type Library}
|
||||||
import elekf/library/album.{type Album}
|
import elekf/library/album.{type Album}
|
||||||
import elekf/library/track.{type Track}
|
import elekf/library/track.{type Track}
|
||||||
import elekf/library/album_utils
|
import elekf/library/album_utils
|
||||||
|
import elekf/library/track_utils
|
||||||
import elekf/web/components/library_view.{AlbumExpandToggled}
|
import elekf/web/components/library_view.{AlbumExpandToggled}
|
||||||
import elekf/web/components/library_item.{type LibraryItem}
|
import elekf/web/components/library_item.{type LibraryItem}
|
||||||
import elekf/web/components/library_views/track_item
|
import elekf/web/components/library_views/track_item
|
||||||
|
@ -94,6 +95,9 @@ pub fn view(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view_tracks(library: Library, tracks: List(LibraryItem(Track))) {
|
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(
|
div(
|
||||||
[
|
[
|
||||||
attribute.class(
|
attribute.class(
|
||||||
|
|
|
@ -58,7 +58,12 @@ pub fn render(
|
||||||
|
|
||||||
fn init() {
|
fn init() {
|
||||||
let #(lib_m, lib_e) =
|
let #(lib_m, lib_e) =
|
||||||
library_view.init(library.empty(), data_getter, shuffler)
|
library_view.init(
|
||||||
|
library.empty(),
|
||||||
|
data_getter,
|
||||||
|
shuffler,
|
||||||
|
album_utils.sort_by_name,
|
||||||
|
)
|
||||||
|
|
||||||
#(
|
#(
|
||||||
Model(library_view: lib_m, expanded_album: library.invalid_id),
|
Model(library_view: lib_m, expanded_album: library.invalid_id),
|
||||||
|
|
|
@ -11,6 +11,7 @@ import lustre/attribute
|
||||||
import lustre/event
|
import lustre/event
|
||||||
import elekf/library.{type Library}
|
import elekf/library.{type Library}
|
||||||
import elekf/library/artist.{type Artist}
|
import elekf/library/artist.{type Artist}
|
||||||
|
import elekf/library/artist_utils
|
||||||
import elekf/web/components/library_view.{type Model, ShowArtist}
|
import elekf/web/components/library_view.{type Model, ShowArtist}
|
||||||
import elekf/web/components/library_item.{type LibraryItem}
|
import elekf/web/components/library_item.{type LibraryItem}
|
||||||
import elekf/web/components/library_views/thumbnail
|
import elekf/web/components/library_views/thumbnail
|
||||||
|
@ -25,6 +26,7 @@ pub fn register() {
|
||||||
data_getter,
|
data_getter,
|
||||||
item_view,
|
item_view,
|
||||||
shuffler,
|
shuffler,
|
||||||
|
artist_utils.sort_by_name,
|
||||||
search_filter,
|
search_filter,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,7 @@ fn init() {
|
||||||
library.empty(),
|
library.empty(),
|
||||||
fn(_) -> List(LibraryItem(Album)) { [] },
|
fn(_) -> List(LibraryItem(Album)) { [] },
|
||||||
shuffler,
|
shuffler,
|
||||||
|
album_utils.sort_by_year,
|
||||||
)
|
)
|
||||||
|
|
||||||
#(
|
#(
|
||||||
|
@ -101,7 +102,8 @@ fn update(model: Model, msg) {
|
||||||
expanded_album: library.invalid_id,
|
expanded_album: library.invalid_id,
|
||||||
library_view: library_view.Model(
|
library_view: library_view.Model(
|
||||||
..model.library_view,
|
..model.library_view,
|
||||||
data: data_getter(model.library_view.library, artist),
|
data: data_getter(model.library_view.library, artist)
|
||||||
|
|> list.sort(fn(a, b) { model.library_view.sorter(a.1, b.1) }),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
effect.none(),
|
effect.none(),
|
||||||
|
|
|
@ -7,6 +7,7 @@ import gleam/option
|
||||||
import lustre/attribute
|
import lustre/attribute
|
||||||
import elekf/library.{type Library}
|
import elekf/library.{type Library}
|
||||||
import elekf/library/track.{type Track}
|
import elekf/library/track.{type Track}
|
||||||
|
import elekf/library/track_utils
|
||||||
import elekf/web/components/library_view.{type Model}
|
import elekf/web/components/library_view.{type Model}
|
||||||
import elekf/web/components/library_item.{type LibraryItem}
|
import elekf/web/components/library_item.{type LibraryItem}
|
||||||
import elekf/web/components/library_views/track_item
|
import elekf/web/components/library_views/track_item
|
||||||
|
@ -21,6 +22,7 @@ pub fn register() {
|
||||||
data_getter,
|
data_getter,
|
||||||
item_view,
|
item_view,
|
||||||
shuffler,
|
shuffler,
|
||||||
|
track_utils.sort_by_name,
|
||||||
search_filter,
|
search_filter,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue