2021-02-24 20:17:18 +02:00
|
|
|
/* music-local.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 <glib-2.0/glib.h>
|
|
|
|
#include <gtk-4.0/gtk/gtk.h>
|
2021-03-23 19:50:09 +02:00
|
|
|
#include "../../db/cartographer.h"
|
2021-03-02 19:12:12 +02:00
|
|
|
#include "../../indexer/structs.h"
|
2021-02-24 20:17:18 +02:00
|
|
|
#include "koto-button.h"
|
|
|
|
#include "koto-config.h"
|
2021-05-07 21:52:42 +03:00
|
|
|
#include "../../koto-utils.h"
|
2021-02-24 20:17:18 +02:00
|
|
|
#include "music-local.h"
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
extern KotoCartographer * koto_maps;
|
2021-03-23 19:50:09 +02:00
|
|
|
|
2021-02-24 20:17:18 +02:00
|
|
|
enum {
|
|
|
|
PROP_0,
|
|
|
|
PROP_LIB,
|
|
|
|
N_PROPERTIES
|
|
|
|
};
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
static GParamSpec * props[N_PROPERTIES] = {
|
|
|
|
NULL,
|
|
|
|
};
|
2021-02-24 20:17:18 +02:00
|
|
|
|
|
|
|
struct _KotoPageMusicLocal {
|
|
|
|
GtkBox parent_instance;
|
2021-05-11 20:05:04 +03:00
|
|
|
GtkWidget * scrolled_window;
|
|
|
|
GtkWidget * artist_list;
|
|
|
|
GtkWidget * stack;
|
2021-02-24 20:17:18 +02:00
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
KotoIndexedLibrary * lib;
|
2021-02-24 20:17:18 +02:00
|
|
|
gboolean constructed;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _KotoPageMusicLocalClass {
|
|
|
|
GtkBoxClass parent_class;
|
|
|
|
};
|
|
|
|
|
|
|
|
G_DEFINE_TYPE(KotoPageMusicLocal, koto_page_music_local, GTK_TYPE_BOX);
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
KotoPageMusicLocal * music_local_page;
|
|
|
|
|
|
|
|
static void koto_page_music_local_constructed(GObject * obj);
|
|
|
|
|
|
|
|
static void koto_page_music_local_get_property(
|
|
|
|
GObject * obj,
|
|
|
|
guint prop_id,
|
|
|
|
GValue * val,
|
|
|
|
GParamSpec * spec
|
|
|
|
);
|
|
|
|
|
|
|
|
static void koto_page_music_local_set_property(
|
|
|
|
GObject * obj,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue * val,
|
|
|
|
GParamSpec * spec
|
|
|
|
);
|
|
|
|
|
|
|
|
static void koto_page_music_local_class_init(KotoPageMusicLocalClass * c) {
|
|
|
|
GObjectClass * gobject_class;
|
2021-05-07 16:45:57 +03:00
|
|
|
|
2021-02-24 20:17:18 +02:00
|
|
|
|
|
|
|
gobject_class = G_OBJECT_CLASS(c);
|
|
|
|
gobject_class->constructed = koto_page_music_local_constructed;
|
|
|
|
gobject_class->set_property = koto_page_music_local_set_property;
|
|
|
|
gobject_class->get_property = koto_page_music_local_get_property;
|
|
|
|
|
|
|
|
props[PROP_LIB] = g_param_spec_object(
|
|
|
|
"lib",
|
|
|
|
"Library",
|
|
|
|
"Library",
|
|
|
|
KOTO_TYPE_INDEXED_LIBRARY,
|
2021-05-11 20:05:04 +03:00
|
|
|
G_PARAM_CONSTRUCT | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READWRITE
|
2021-02-24 20:17:18 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
g_object_class_install_properties(gobject_class, N_PROPERTIES, props);
|
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
static void koto_page_music_local_get_property(
|
|
|
|
GObject * obj,
|
|
|
|
guint prop_id,
|
|
|
|
GValue * val,
|
|
|
|
GParamSpec * spec
|
|
|
|
) {
|
|
|
|
KotoPageMusicLocal * self = KOTO_PAGE_MUSIC_LOCAL(obj);
|
|
|
|
|
2021-02-24 20:17:18 +02:00
|
|
|
|
|
|
|
switch (prop_id) {
|
|
|
|
case PROP_LIB:
|
|
|
|
g_value_set_object(val, self->lib);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
static void koto_page_music_local_set_property(
|
|
|
|
GObject * obj,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue * val,
|
|
|
|
GParamSpec * spec
|
|
|
|
) {
|
|
|
|
KotoPageMusicLocal * self = KOTO_PAGE_MUSIC_LOCAL(obj);
|
|
|
|
|
2021-02-24 20:17:18 +02:00
|
|
|
|
|
|
|
switch (prop_id) {
|
|
|
|
case PROP_LIB:
|
|
|
|
koto_page_music_local_set_library(self, (KotoIndexedLibrary*) g_value_get_object(val));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, spec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
static void koto_page_music_local_init(KotoPageMusicLocal * self) {
|
2021-02-24 20:17:18 +02:00
|
|
|
self->lib = NULL;
|
|
|
|
self->constructed = FALSE;
|
2021-03-09 11:45:44 +02:00
|
|
|
|
|
|
|
gtk_widget_add_css_class(GTK_WIDGET(self), "page-music-local");
|
|
|
|
gtk_widget_set_hexpand(GTK_WIDGET(self), TRUE);
|
|
|
|
gtk_widget_set_vexpand(GTK_WIDGET(self), TRUE);
|
|
|
|
|
|
|
|
self->scrolled_window = gtk_scrolled_window_new();
|
|
|
|
gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(self->scrolled_window), 300);
|
|
|
|
gtk_scrolled_window_set_propagate_natural_height(GTK_SCROLLED_WINDOW(self->scrolled_window), FALSE);
|
|
|
|
gtk_widget_add_css_class(self->scrolled_window, "artist-list");
|
|
|
|
gtk_widget_set_vexpand(self->scrolled_window, TRUE); // Expand our scrolled window
|
|
|
|
gtk_box_prepend(GTK_BOX(self), self->scrolled_window);
|
|
|
|
|
|
|
|
self->artist_list = gtk_list_box_new(); // Create our artist 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
|
|
|
|
gtk_scrolled_window_set_child(GTK_SCROLLED_WINDOW(self->scrolled_window), self->artist_list);
|
|
|
|
|
|
|
|
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);
|
|
|
|
gtk_widget_set_vexpand(self->stack, TRUE);
|
|
|
|
gtk_box_append(GTK_BOX(self), self->stack);
|
2021-02-24 20:17:18 +02:00
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
static void koto_page_music_local_constructed(GObject * obj) {
|
|
|
|
KotoPageMusicLocal * self = KOTO_PAGE_MUSIC_LOCAL(obj);
|
|
|
|
|
2021-02-24 20:17:18 +02:00
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
G_OBJECT_CLASS(koto_page_music_local_parent_class)->constructed(obj);
|
2021-02-24 20:17:18 +02:00
|
|
|
self->constructed = TRUE;
|
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
void koto_page_music_local_add_artist(
|
|
|
|
KotoPageMusicLocal * self,
|
|
|
|
KotoIndexedArtist * artist
|
|
|
|
) {
|
|
|
|
gchar * artist_name;
|
|
|
|
|
|
|
|
|
2021-02-24 20:17:18 +02:00
|
|
|
g_object_get(artist, "name", &artist_name, NULL);
|
2021-05-11 20:05:04 +03:00
|
|
|
KotoButton * artist_button = koto_button_new_plain(artist_name);
|
|
|
|
|
|
|
|
|
2021-02-24 20:17:18 +02:00
|
|
|
gtk_list_box_prepend(GTK_LIST_BOX(self->artist_list), GTK_WIDGET(artist_button));
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
KotoArtistView * artist_view = koto_artist_view_new(); // Create our new artist view
|
|
|
|
|
|
|
|
|
2021-02-24 20:17:18 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
void koto_page_music_local_go_to_artist_by_name(
|
|
|
|
KotoPageMusicLocal * self,
|
|
|
|
gchar * artist_name
|
|
|
|
) {
|
2021-05-07 16:45:57 +03:00
|
|
|
gtk_stack_set_visible_child_name(GTK_STACK(self->stack), artist_name);
|
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
void koto_page_music_local_go_to_artist_by_uuid(
|
|
|
|
KotoPageMusicLocal * self,
|
|
|
|
gchar * artist_uuid
|
|
|
|
) {
|
|
|
|
KotoIndexedArtist * artist = koto_cartographer_get_artist_by_uuid(koto_maps, artist_uuid); // Get the artist
|
|
|
|
|
2021-05-07 16:45:57 +03:00
|
|
|
|
|
|
|
if (!KOTO_IS_INDEXED_ARTIST(artist)) { // No artist for this UUID
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
gchar * artist_name = NULL;
|
|
|
|
|
|
|
|
|
2021-05-07 16:45:57 +03:00
|
|
|
g_object_get(
|
|
|
|
artist,
|
|
|
|
"name",
|
|
|
|
&artist_name,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
|
2021-05-07 21:52:42 +03:00
|
|
|
if (!koto_utils_is_string_valid(artist_name)) { // Failed to get the artist name
|
2021-05-07 16:45:57 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
koto_page_music_local_go_to_artist_by_name(self, artist_name);
|
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
void koto_page_music_local_handle_artist_click(
|
|
|
|
GtkListBox * box,
|
|
|
|
GtkListBoxRow * row,
|
|
|
|
gpointer data
|
|
|
|
) {
|
2021-02-27 17:26:24 +02:00
|
|
|
(void) box;
|
2021-05-11 20:05:04 +03:00
|
|
|
KotoPageMusicLocal * self = (KotoPageMusicLocal*) data;
|
|
|
|
KotoButton * btn = KOTO_BUTTON(gtk_list_box_row_get_child(row));
|
|
|
|
|
|
|
|
gchar * artist_name;
|
|
|
|
|
2021-02-24 20:17:18 +02:00
|
|
|
|
|
|
|
g_object_get(btn, "button-text", &artist_name, NULL);
|
2021-05-07 16:45:57 +03:00
|
|
|
koto_page_music_local_go_to_artist_by_name(self, artist_name);
|
2021-02-24 20:17:18 +02:00
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
void koto_page_music_local_set_library(
|
|
|
|
KotoPageMusicLocal * self,
|
|
|
|
KotoIndexedLibrary * lib
|
|
|
|
) {
|
2021-02-24 20:17:18 +02:00
|
|
|
if (lib == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (self->lib != NULL) { // If lib is already set
|
|
|
|
g_free(self->lib);
|
|
|
|
}
|
|
|
|
|
|
|
|
self->lib = lib;
|
|
|
|
|
|
|
|
if (!self->constructed) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-09 11:45:44 +02:00
|
|
|
GHashTableIter artist_list_iter;
|
|
|
|
gpointer artist_key;
|
|
|
|
gpointer artist_data;
|
2021-02-24 20:17:18 +02:00
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
GHashTable * artists = koto_indexed_library_get_artists(self->lib); // Get the artists
|
|
|
|
|
2021-02-24 20:17:18 +02:00
|
|
|
|
2021-03-09 11:45:44 +02:00
|
|
|
g_hash_table_iter_init(&artist_list_iter, artists);
|
|
|
|
while (g_hash_table_iter_next(&artist_list_iter, &artist_key, &artist_data)) { // For each of the music artists
|
2021-05-11 20:05:04 +03:00
|
|
|
KotoIndexedArtist * artist = koto_cartographer_get_artist_by_uuid(koto_maps, (gchar*) artist_data); // Cast our data as a KotoIndexedArtist
|
2021-03-23 19:50:09 +02:00
|
|
|
|
|
|
|
if (artist != NULL) {
|
|
|
|
koto_page_music_local_add_artist(self, artist);
|
|
|
|
}
|
2021-02-24 20:17:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
int koto_page_music_local_sort_artists(
|
|
|
|
GtkListBoxRow * artist1,
|
|
|
|
GtkListBoxRow * artist2,
|
|
|
|
gpointer user_data
|
|
|
|
) {
|
2021-02-24 20:17:18 +02:00
|
|
|
(void) user_data;
|
2021-05-11 20:05:04 +03:00
|
|
|
KotoButton * artist1_btn = KOTO_BUTTON(gtk_list_box_row_get_child(artist1));
|
|
|
|
KotoButton * artist2_btn = KOTO_BUTTON(gtk_list_box_row_get_child(artist2));
|
|
|
|
|
|
|
|
gchar * artist1_text;
|
|
|
|
gchar * artist2_text;
|
2021-02-24 20:17:18 +02:00
|
|
|
|
|
|
|
|
|
|
|
g_object_get(artist1_btn, "button-text", &artist1_text, NULL);
|
|
|
|
g_object_get(artist2_btn, "button-text", &artist2_text, NULL);
|
|
|
|
|
|
|
|
return g_utf8_collate(artist1_text, artist2_text);
|
|
|
|
}
|
|
|
|
|
2021-05-11 20:05:04 +03:00
|
|
|
KotoPageMusicLocal * koto_page_music_local_new() {
|
|
|
|
return g_object_new(
|
|
|
|
KOTO_TYPE_PAGE_MUSIC_LOCAL,
|
|
|
|
"orientation",
|
|
|
|
GTK_ORIENTATION_HORIZONTAL,
|
2021-02-24 20:17:18 +02:00
|
|
|
NULL
|
|
|
|
);
|
|
|
|
}
|