diff --git a/src/db/db.c b/src/db/db.c new file mode 100644 index 0000000..8bbce74 --- /dev/null +++ b/src/db/db.c @@ -0,0 +1,60 @@ +/* db.c + * + * Copyright 2021 Joshua Strobl + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "db.h" + +sqlite3 *koto_db = NULL; + +void close_db() { + sqlite3_close(koto_db); +} + +void create_db_tables() { + char *tables_creation_queries = "CREATE TABLE IF NOT EXISTS artists(id string UNIQUE, path string UNIQUE, type int, name string, art_path string);" + "CREATE TABLE IF NOT EXISTS albums(id string UNIQUE, path string UNIQUE, artist_id int, name string, art_path string);" + "CREATE TABLE IF NOT EXISTS tracks(id string UNIQUE, path string UNIQUE, type int, artist_id int, album_id int, file_name string, name string, disc int, position int);"; + + gchar *create_tables_errmsg = NULL; + int rc = sqlite3_exec(koto_db, tables_creation_queries, 0,0, &create_tables_errmsg); + + if (rc != SQLITE_OK) { + g_critical("Failed to create required tables: %s", create_tables_errmsg); + } +} + +void open_db() { + const gchar *data_home = g_get_user_data_dir(); + gchar *data_dir = g_build_path(G_DIR_SEPARATOR_S, data_home, "com.github.joshstrobl.koto", NULL); + mkdir(data_home, 0755); + mkdir(data_dir, 0755); + chown(data_dir, getuid(), getgid()); + + gchar *db_path = g_build_filename(data_dir, "db", NULL); // Build out our path using XDG_DATA_HOME (e.g. .local/share/) + our namespace + db as the file name + int rc = sqlite3_open(db_path, &koto_db); + + if (rc) { + g_critical("Failed to open or create database: %s", sqlite3_errmsg(koto_db)); + return; + } + + create_db_tables(); // Attempt to create our database tables +} diff --git a/src/db/db.h b/src/db/db.h new file mode 100644 index 0000000..a7cf546 --- /dev/null +++ b/src/db/db.h @@ -0,0 +1,22 @@ +/* db.h + * + * Copyright 2021 Joshua Strobl + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +void close_db(); +void open_db(); + diff --git a/src/indexer/album.c b/src/indexer/album.c index 4fd97db..ae671d3 100644 --- a/src/indexer/album.c +++ b/src/indexer/album.c @@ -199,7 +199,7 @@ void koto_indexed_album_read_path(KotoIndexedAlbum *self, magic_t cookie, const } else if (g_str_has_prefix(mime_type, "audio/") || g_str_has_prefix(mime_type, "video/ogg")) { // Is an audio file or ogg because it is special gchar *appended_slash_to_path = g_strdup_printf("%s%s", g_strdup(self->path), G_DIR_SEPARATOR_S); gchar **possible_cd_split = g_strsplit(full_path, appended_slash_to_path, -1); // Split based on the album path - guint *cd = 0; + guint *cd = (guint*) 1; gchar *file_with_cd_sep = g_strdup(possible_cd_split[1]); // Duplicate gchar **split_on_cd = g_strsplit(file_with_cd_sep, G_DIR_SEPARATOR_S, -1); // Split based on separator (e.g. / ) diff --git a/src/indexer/file.c b/src/indexer/file.c index 6963a37..c436cec 100644 --- a/src/indexer/file.c +++ b/src/indexer/file.c @@ -268,7 +268,7 @@ void koto_indexed_file_set_file_name(KotoIndexedFile *self, gchar *new_file_name } void koto_indexed_file_set_cd(KotoIndexedFile *self, guint cd) { - if (cd <= 1) { // No change really + if (cd == 0) { // No change really return; } diff --git a/src/koto-playerbar.c b/src/koto-playerbar.c index 1719366..12523b9 100644 --- a/src/koto-playerbar.c +++ b/src/koto-playerbar.c @@ -98,7 +98,7 @@ void koto_playerbar_create_playback_details(KotoPlayerBar* bar) { GtkIconTheme *default_icon_theme = gtk_icon_theme_get_for_display(gdk_display_get_default()); // Get the icon theme for this display if (default_icon_theme != NULL) { - gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(bar)); + gint scale_factor = gtk_widget_get_scale_factor(GTK_WIDGET(bar->main)); GtkIconPaintable* audio_paintable = gtk_icon_theme_lookup_icon(default_icon_theme, "audio-x-generic-symbolic", NULL, 96, scale_factor, GTK_TEXT_DIR_NONE, GTK_ICON_LOOKUP_PRELOAD); if (GTK_IS_ICON_PAINTABLE(audio_paintable)) { diff --git a/src/main.c b/src/main.c index 417f06d..0e28674 100644 --- a/src/main.c +++ b/src/main.c @@ -16,10 +16,13 @@ */ #include +#include "db/db.h" #include "koto-config.h" #include "koto-window.h" +extern sqlite3 *koto_db; + static void on_activate (GtkApplication *app) { g_assert(GTK_IS_APPLICATION (app)); @@ -33,6 +36,16 @@ static void on_activate (GtkApplication *app) { gtk_window_present(window); } +static void on_shutdown(GtkApplication *app) { + (void) app; + + if (koto_db != NULL) { + g_message("Have a db?"); + } + + close_db(); // Close the database +} + int main (int argc, char *argv[]) { g_autoptr(GtkApplication) app = NULL; int ret; @@ -43,8 +56,10 @@ int main (int argc, char *argv[]) { textdomain (GETTEXT_PACKAGE); gtk_init(); + open_db(); // Open our database app = gtk_application_new ("com.github.joshstrobl.koto", G_APPLICATION_FLAGS_NONE); g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL); + g_signal_connect(app, "shutdown", G_CALLBACK(on_shutdown), NULL); ret = g_application_run (G_APPLICATION (app), argc, argv); return ret; diff --git a/src/meson.build b/src/meson.build index d95e31e..aa802e8 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,12 +1,14 @@ add_project_arguments('-Db_sanitize=address', language: 'c') koto_sources = [ + 'db/db.c', 'indexer/album.c', 'indexer/artist.c', 'indexer/file.c', 'indexer/file-indexer.c', 'pages/music/album-view.c', 'pages/music/artist-view.c', + 'pages/music/disc-view.c', 'pages/music/music-local.c', 'main.c', 'koto-button.c', @@ -23,6 +25,7 @@ koto_deps = [ dependency('gio-2.0', version: '>= 2.66'), dependency('gtk4', version: '>= 4.0'), dependency('libmagic', version: '>=5.39'), + dependency('sqlite3', version: '>=3.34'), dependency('taglib_c', version: '>=1.11'), ] diff --git a/src/pages/music/album-view.c b/src/pages/music/album-view.c index 0d7c1bb..1b1e0fd 100644 --- a/src/pages/music/album-view.c +++ b/src/pages/music/album-view.c @@ -19,8 +19,8 @@ #include #include "../../indexer/album.h" #include "../../indexer/artist.h" -#include "../../koto-track-item.h" #include "album-view.h" +#include "disc-view.h" #include "koto-config.h" #include "koto-utils.h" @@ -29,7 +29,7 @@ struct _KotoAlbumView { KotoIndexedAlbum *album; GtkWidget *main; GtkWidget *album_tracks_box; - GtkWidget *tracks; + GtkWidget *discs; GtkWidget *album_label; GHashTable *cd_to_track_listbox; @@ -71,13 +71,15 @@ static void koto_album_view_init(KotoAlbumView *self) { gtk_widget_set_can_focus(self->main, FALSE); self->album_tracks_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - self->tracks = gtk_list_box_new(); // Create our list of our tracks - gtk_list_box_set_sort_func(GTK_LIST_BOX(self->tracks), koto_album_view_sort_tracks, NULL, NULL); // Ensure we can sort our tracks - gtk_widget_add_css_class(self->tracks, "track-list"); - gtk_widget_set_size_request(self->tracks, 600, -1); + self->discs = gtk_list_box_new(); // Create our list of our tracks + gtk_list_box_set_selection_mode(GTK_LIST_BOX(self->discs), GTK_SELECTION_NONE); + gtk_list_box_set_sort_func(GTK_LIST_BOX(self->discs), koto_album_view_sort_discs, NULL, NULL); // Ensure we can sort our discs + gtk_widget_add_css_class(self->discs, "discs-list"); + gtk_widget_set_can_focus(self->discs, FALSE); + gtk_widget_set_size_request(self->discs, 600, -1); gtk_box_append(GTK_BOX(self->main), self->album_tracks_box); // Add the tracks box to the art info combo box - gtk_box_append(GTK_BOX(self->album_tracks_box), self->tracks); // Add the tracks list box to the albums tracks box + gtk_box_append(GTK_BOX(self->album_tracks_box), self->discs); // Add the discs list box to the albums tracks box } GtkWidget* koto_album_view_get_main(KotoAlbumView *self) { @@ -134,40 +136,49 @@ void koto_album_view_set_album(KotoAlbumView *self, KotoIndexedAlbum *album) { gtk_widget_set_halign(self->album_label, GTK_ALIGN_START); gtk_box_prepend(GTK_BOX(self->album_tracks_box), self->album_label); // Prepend our new label to the album + tracks box - GList *t; - for (t = koto_indexed_album_get_files(self->album); t != NULL; t = t->next) { // For each file / track - KotoIndexedFile *file = (KotoIndexedFile*) t->data; - KotoTrackItem *track_item = koto_track_item_new(file); // Create our new track item - gtk_list_box_prepend(GTK_LIST_BOX(self->tracks), GTK_WIDGET(track_item)); // Add to our tracks list box + GHashTable *discs = g_hash_table_new(g_str_hash, g_str_equal); + GList *tracks = koto_indexed_album_get_files(album); // Get the tracks for this album + + for (guint i = 0; i < g_list_length(tracks); i++) { + KotoIndexedFile *file = (KotoIndexedFile*) g_list_nth_data(tracks, i); // Get the + guint *disc_number; + g_object_get(file, "cd", &disc_number, NULL); + gchar *disc_num_as_str = g_strdup_printf("%u", GPOINTER_TO_UINT(disc_number)); + + if (g_hash_table_contains(discs, disc_num_as_str)) { // Already have this added + continue; // Skip + } + + g_hash_table_insert(discs, disc_num_as_str, "0"); // Mark this disc number in the hash table + KotoDiscView *disc_view = koto_disc_view_new(album, disc_number); + gtk_list_box_append(GTK_LIST_BOX(self->discs), GTK_WIDGET(disc_view)); // Add the Disc View to the List Box } + + if (g_list_length(g_hash_table_get_keys(discs)) == 1) { // Only have one album + GtkListBoxRow *row = gtk_list_box_get_row_at_index(GTK_LIST_BOX(self->discs), 0); // Get the first item + + if (GTK_IS_LIST_BOX_ROW(row)) { // Is a row + koto_disc_view_set_disc_label_visible((KotoDiscView*) gtk_list_box_row_get_child(row), FALSE); // Get + } + } + + g_hash_table_destroy(discs); } -int koto_album_view_sort_tracks(GtkListBoxRow *track1, GtkListBoxRow *track2, gpointer user_data) { +int koto_album_view_sort_discs(GtkListBoxRow *disc1, GtkListBoxRow *disc2, gpointer user_data) { (void) user_data; - KotoTrackItem *track1_item = KOTO_TRACK_ITEM(gtk_list_box_row_get_child(track1)); - KotoTrackItem *track2_item = KOTO_TRACK_ITEM(gtk_list_box_row_get_child(track2)); + KotoDiscView *disc1_item = KOTO_DISC_VIEW(gtk_list_box_row_get_child(disc1)); + KotoDiscView *disc2_item = KOTO_DISC_VIEW(gtk_list_box_row_get_child(disc2)); - KotoIndexedFile *track1_file; - KotoIndexedFile *track2_file; + guint disc1_num; + guint disc2_num; - g_object_get(track1_item, "track", &track1_file, NULL); - g_object_get(track2_item, "track", &track2_file, NULL); + g_object_get(disc1_item, "disc", &disc1_num, NULL); + g_object_get(disc2_item, "disc", &disc2_num, NULL); - guint16 *track1_pos; - guint16 *track2_pos; - - g_object_get(track1_file, "position", &track1_pos, NULL); - g_object_get(track2_file, "position", &track2_pos, NULL); - - if (track1_pos == track2_pos) { // Identical positions (like reported as 0) - gchar *track1_name; - gchar *track2_name; - - g_object_get(track1_file, "parsed-name", &track1_name, NULL); - g_object_get(track2_file, "parsed-name", &track2_name, NULL); - - return g_utf8_collate(track1_name, track2_name); - } else if (track1_pos < track2_pos) { + if (disc1_num == disc2_num) { // Identical positions (like reported as 0) + return 0; + } else if (disc1_num < disc2_num) { return -1; } else { return 1; diff --git a/src/pages/music/album-view.h b/src/pages/music/album-view.h index 705ad59..c415b8b 100644 --- a/src/pages/music/album-view.h +++ b/src/pages/music/album-view.h @@ -32,6 +32,6 @@ KotoAlbumView* koto_album_view_new(KotoIndexedAlbum *album); GtkWidget* koto_album_view_get_main(KotoAlbumView *self); void koto_album_view_add_track_to_listbox(KotoIndexedAlbum *self, KotoIndexedFile *file); void koto_album_view_set_album(KotoAlbumView *self, KotoIndexedAlbum *album); -int koto_album_view_sort_tracks(GtkListBoxRow *track1, GtkListBoxRow *track2, gpointer user_data); +int koto_album_view_sort_discs(GtkListBoxRow *track1, GtkListBoxRow *track2, gpointer user_data); G_END_DECLS diff --git a/src/pages/music/disc-view.c b/src/pages/music/disc-view.c new file mode 100644 index 0000000..9a1cc73 --- /dev/null +++ b/src/pages/music/disc-view.c @@ -0,0 +1,218 @@ +/* disc-view.c + * + * Copyright 2021 Joshua Strobl + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include "../../indexer/album.h" +#include "../../koto-track-item.h" +#include "disc-view.h" + +struct _KotoDiscView { + GtkBox parent_instance; + KotoIndexedAlbum *album; + GtkWidget *header; + GtkWidget *label; + GtkWidget *list; + + guint *disc_number; +}; + +G_DEFINE_TYPE(KotoDiscView, koto_disc_view, GTK_TYPE_BOX); + +enum { + PROP_0, + PROP_DISC, + PROP_ALBUM, + N_PROPERTIES +}; + +static GParamSpec *props[N_PROPERTIES] = { NULL, }; +static void koto_disc_view_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec); +static void koto_disc_view_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec); + +static void koto_disc_view_class_init(KotoDiscViewClass *c) { + GObjectClass *gobject_class; + gobject_class = G_OBJECT_CLASS(c); + gobject_class->set_property = koto_disc_view_set_property; + gobject_class->get_property = koto_disc_view_get_property; + + props[PROP_DISC] = g_param_spec_uint( + "disc", + "Disc", + "Disc", + 0, + G_MAXUINT16, + 1, + G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + ); + + props[PROP_ALBUM] = g_param_spec_object( + "album", + "Album", + "Album", + KOTO_TYPE_INDEXED_ALBUM, + G_PARAM_CONSTRUCT|G_PARAM_EXPLICIT_NOTIFY|G_PARAM_READWRITE + ); + + g_object_class_install_properties(gobject_class, N_PROPERTIES, props); +} + +static void koto_disc_view_get_property(GObject *obj, guint prop_id, GValue *val, GParamSpec *spec) { + KotoDiscView *self = KOTO_DISC_VIEW(obj); + + switch (prop_id) { + case PROP_DISC: + g_value_set_uint(val, GPOINTER_TO_UINT(self->disc_number)); + break; + case PROP_ALBUM: + g_value_set_object(val, self->album); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec); + break; + } +} + +static void koto_disc_view_set_property(GObject *obj, guint prop_id, const GValue *val, GParamSpec *spec) { + KotoDiscView *self = KOTO_DISC_VIEW(obj); + + switch (prop_id) { + case PROP_DISC: + koto_disc_view_set_disc_number(self, g_value_get_uint(val)); + break; + case PROP_ALBUM: + koto_disc_view_set_album(self, (KotoIndexedAlbum*) g_value_get_object(val)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec); + break; + } +} + +static void koto_disc_view_init(KotoDiscView *self) { + gtk_widget_add_css_class(GTK_WIDGET(self), "disc-view"); + gtk_widget_set_can_focus(GTK_WIDGET(self), FALSE); + self->header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_hexpand(self->header, TRUE); + gtk_widget_set_size_request(self->header, 16, -1); + + GtkWidget *ico = gtk_image_new_from_icon_name("drive-optical-symbolic"); + gtk_box_prepend(GTK_BOX(self->header), ico); + + self->label = gtk_label_new(NULL); // Create an empty label + gtk_widget_set_halign(self->label, GTK_ALIGN_START); + gtk_widget_set_valign(self->label, GTK_ALIGN_CENTER); + gtk_box_append(GTK_BOX(self->header), self->label); + + gtk_box_append(GTK_BOX(self), self->header); +} + +void koto_disc_view_set_album(KotoDiscView *self, KotoIndexedAlbum *album) { + if (album == NULL) { + return; + } + + if (self->album != NULL) { + g_free(self->album); + } + + self->album = album; + + if (GTK_IS_LIST_BOX(self->list)) { // Already have a listbox + gtk_box_remove(GTK_BOX(self), self->list); // Remove the box + g_object_unref(self->list); // Unref the list + } + + self->list = gtk_list_box_new(); // Create our list of our tracks + gtk_list_box_set_selection_mode(GTK_LIST_BOX(self->list), GTK_SELECTION_MULTIPLE); + gtk_list_box_set_sort_func(GTK_LIST_BOX(self->list), koto_album_view_sort_tracks, NULL, NULL); // Ensure we can sort our tracks + gtk_widget_add_css_class(self->list, "track-list"); + gtk_widget_set_size_request(self->list, 600, -1); + gtk_box_append(GTK_BOX(self), self->list); + + GList *t; + for (t = koto_indexed_album_get_files(self->album); t != NULL; t = t->next) { // For each file / track + KotoIndexedFile *file = (KotoIndexedFile*) t->data; + + guint *disc_number; + g_object_get(file, "cd", &disc_number, NULL); // get the disc number + + if (GPOINTER_TO_UINT(self->disc_number) != GPOINTER_TO_UINT(disc_number)) { // Track does not belong to this CD + continue; + } + + KotoTrackItem *track_item = koto_track_item_new(file); // Create our new track item + gtk_list_box_prepend(GTK_LIST_BOX(self->list), GTK_WIDGET(track_item)); // Add to our tracks list box + } +} + +void koto_disc_view_set_disc_number(KotoDiscView *self, guint disc_number) { + if (disc_number == 0) { + return; + } + + self->disc_number = GUINT_TO_POINTER(disc_number); + + gchar *disc_label = g_strdup_printf("Disc %u", disc_number); + gtk_label_set_text(GTK_LABEL(self->label), disc_label); // Set the label + + g_free(disc_label); +} + +void koto_disc_view_set_disc_label_visible(KotoDiscView *self, gboolean visible) { + (visible) ? gtk_widget_show(self->header) : gtk_widget_hide(self->header); +} + +int koto_album_view_sort_tracks(GtkListBoxRow *track1, GtkListBoxRow *track2, gpointer user_data) { + (void) user_data; + KotoTrackItem *track1_item = KOTO_TRACK_ITEM(gtk_list_box_row_get_child(track1)); + KotoTrackItem *track2_item = KOTO_TRACK_ITEM(gtk_list_box_row_get_child(track2)); + + KotoIndexedFile *track1_file; + KotoIndexedFile *track2_file; + + g_object_get(track1_item, "track", &track1_file, NULL); + g_object_get(track2_item, "track", &track2_file, NULL); + + guint16 *track1_pos; + guint16 *track2_pos; + + g_object_get(track1_file, "position", &track1_pos, NULL); + g_object_get(track2_file, "position", &track2_pos, NULL); + + if (track1_pos == track2_pos) { // Identical positions (like reported as 0) + gchar *track1_name; + gchar *track2_name; + + g_object_get(track1_file, "parsed-name", &track1_name, NULL); + g_object_get(track2_file, "parsed-name", &track2_name, NULL); + + return g_utf8_collate(track1_name, track2_name); + } else if (track1_pos < track2_pos) { + return -1; + } else { + return 1; + } +} + +KotoDiscView* koto_disc_view_new(KotoIndexedAlbum *album, guint *disc_number) { + return g_object_new(KOTO_TYPE_DISC_VIEW, + "disc", disc_number, + "album", album, + "orientation", GTK_ORIENTATION_VERTICAL, + NULL + ); +} diff --git a/src/pages/music/disc-view.h b/src/pages/music/disc-view.h new file mode 100644 index 0000000..464ade5 --- /dev/null +++ b/src/pages/music/disc-view.h @@ -0,0 +1,36 @@ +/* disc-view.h + * + * Copyright 2021 Joshua Strobl + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include "../../indexer/album.h" + +G_BEGIN_DECLS + +#define KOTO_TYPE_DISC_VIEW (koto_disc_view_get_type()) + +G_DECLARE_FINAL_TYPE(KotoDiscView, koto_disc_view, KOTO, DISC_VIEW, GtkBox) + +KotoDiscView* koto_disc_view_new(KotoIndexedAlbum *album, guint *disc); +void koto_disc_view_set_album(KotoDiscView *self, KotoIndexedAlbum *album); +void koto_disc_view_set_disc_label_visible(KotoDiscView *self, gboolean visible); +void koto_disc_view_set_disc_number(KotoDiscView *self, guint disc_number); +int koto_album_view_sort_tracks(GtkListBoxRow *track1, GtkListBoxRow *track2, gpointer user_data); + +G_END_DECLS diff --git a/src/pages/music/music-local.c b/src/pages/music/music-local.c index f2ba9e0..ddb40eb 100644 --- a/src/pages/music/music-local.c +++ b/src/pages/music/music-local.c @@ -117,17 +117,12 @@ void koto_page_music_local_add_artist(KotoPageMusicLocal *self, KotoIndexedArtis KotoArtistView *artist_view = koto_artist_view_new(); // Create our new artist view koto_artist_view_add_artist(artist_view, artist); // Add the artist gtk_stack_add_named(GTK_STACK(self->stack), koto_artist_view_get_main(artist_view), artist_name); - - GtkGesture *controller = gtk_gesture_click_new(); // Create a new GtkGestureClick - g_signal_connect(controller, "pressed", G_CALLBACK(koto_page_music_local_handle_artist_click), self); - gtk_widget_add_controller(GTK_WIDGET(artist_button), GTK_EVENT_CONTROLLER(controller)); } -void koto_page_music_local_handle_artist_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data) { - (void) n_press; (void) x; (void) y; +void koto_page_music_local_handle_artist_click(GtkListBox *box, GtkListBoxRow *row, gpointer data) { + (void) box; KotoPageMusicLocal *self = (KotoPageMusicLocal*) data; - GtkWidget *btn_widget = gtk_event_controller_get_widget(GTK_EVENT_CONTROLLER(gesture)); // Get the widget that applied to this gesture - KotoButton *btn = KOTO_BUTTON(btn_widget); + KotoButton *btn = KOTO_BUTTON(gtk_list_box_row_get_child(row)); gchar *artist_name; g_object_get(btn, "button-text", &artist_name, NULL); @@ -169,6 +164,7 @@ void koto_page_music_local_set_library(KotoPageMusicLocal *self, KotoIndexedLibr gboolean list_created = GTK_IS_LIST_BOX(self->artist_list); if (list_created) { // Successfully created our list + g_signal_connect(GTK_LIST_BOX(self->artist_list), "row-activated", G_CALLBACK(koto_page_music_local_handle_artist_click), self); gtk_list_box_set_activate_on_single_click(GTK_LIST_BOX(self->artist_list), TRUE); gtk_list_box_set_selection_mode(GTK_LIST_BOX(self->artist_list), GTK_SELECTION_BROWSE); gtk_list_box_set_sort_func(GTK_LIST_BOX(self->artist_list), koto_page_music_local_sort_artists, NULL, NULL); // Add our sort function @@ -181,6 +177,8 @@ void koto_page_music_local_set_library(KotoPageMusicLocal *self, KotoIndexedLibr gtk_widget_set_size_request(GTK_WIDGET(self->artist_list), 300, -1); self->stack = gtk_stack_new(); // Create a new stack + gtk_stack_set_transition_duration(GTK_STACK(self->stack), 400); + gtk_stack_set_transition_type(GTK_STACK(self->stack), GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT); gtk_widget_set_hexpand(self->stack, TRUE); gboolean stack_created = GTK_IS_STACK(self->stack); diff --git a/src/pages/music/music-local.h b/src/pages/music/music-local.h index b680b5f..20ccf56 100644 --- a/src/pages/music/music-local.h +++ b/src/pages/music/music-local.h @@ -31,7 +31,7 @@ G_DECLARE_FINAL_TYPE (KotoPageMusicLocal, koto_page_music_local, KOTO, PAGE_MUSI KotoPageMusicLocal* koto_page_music_local_new(); void koto_page_music_local_add_artist(KotoPageMusicLocal *self, KotoIndexedArtist *artist); -void koto_page_music_local_handle_artist_click(GtkGestureClick *gesture, int n_press, double x, double y, gpointer data); +void koto_page_music_local_handle_artist_click(GtkListBox *box, GtkListBoxRow *row, gpointer data); void koto_page_music_local_set_library(KotoPageMusicLocal *self, KotoIndexedLibrary *lib); int koto_page_music_local_sort_artists(GtkListBoxRow *artist1, GtkListBoxRow *artist2, gpointer user_data); diff --git a/theme/_disc-view.scss b/theme/_disc-view.scss new file mode 100644 index 0000000..983fd0e --- /dev/null +++ b/theme/_disc-view.scss @@ -0,0 +1,20 @@ +@import "vars"; + +.disc-view { + & > box { // Horizontal box with image and disc labe + color: #ccc; + margin: 10px 0; + } + + & .track-list { + & > row { + &:nth-child(odd):not(:hover) { + background-color: $midnight; + } + + &:nth-child(even), &:hover { + background-color: $grey; + } + } + } +} diff --git a/theme/main.scss b/theme/main.scss index 13b4ae0..f6edc03 100644 --- a/theme/main.scss +++ b/theme/main.scss @@ -1,11 +1,12 @@ @import 'pages/music-local.scss'; @import 'button'; -@import 'vars'; +@import 'disc-view'; @import 'expander'; @import 'player-bar'; @import 'primary-nav'; @import 'track-item'; +@import 'vars'; window { background-color: $grey; diff --git a/theme/meson.build b/theme/meson.build index f53e8ab..f17aa7b 100644 --- a/theme/meson.build +++ b/theme/meson.build @@ -11,11 +11,12 @@ theme = custom_target('Theme generation', depend_files: files([ 'pages/_music-local.scss', '_button.scss', - '_vars.scss', + '_disc-view.scss', '_expander.scss', '_player-bar.scss', '_primary-nav.scss', '_track-item.scss', + '_vars.scss', ]), build_by_default: true, ) diff --git a/theme/pages/_music-local.scss b/theme/pages/_music-local.scss index 00d042b..be50a5a 100644 --- a/theme/pages/_music-local.scss +++ b/theme/pages/_music-local.scss @@ -37,18 +37,6 @@ font-weight: 900; padding: $halvedpadding 0; } - - & > .track-list { - & > row { - &:nth-child(odd):not(:hover) { - background-color: $midnight; - } - - &:nth-child(even), &:hover { - background-color: $grey; - } - } - } } } }