diff --git a/data/jp.angeltech.MoeMoji.gschema.xml b/data/jp.angeltech.MoeMoji.gschema.xml index dcabd96..c9c7839 100644 --- a/data/jp.angeltech.MoeMoji.gschema.xml +++ b/data/jp.angeltech.MoeMoji.gschema.xml @@ -1,5 +1,10 @@ + + 'alpha-asc' + Category sort order + How categories are sorted: alpha-asc, alpha-desc, modified-asc, modified-desc, created-asc, created-desc + diff --git a/src/moemoji-window.c b/src/moemoji-window.c index 7f2015e..1475497 100644 --- a/src/moemoji-window.c +++ b/src/moemoji-window.c @@ -22,11 +22,22 @@ char *make_display_name(const char *dirname) { if (*p == '_') *p = ' '; } - if (name[0]) - name[0] = g_ascii_toupper(name[0]); return name; } +static char *get_category_display_name(const char *cat_path) { + g_autofree char *name_file = g_build_filename(cat_path, ".name", NULL); + char *contents = NULL; + if (g_file_get_contents(name_file, &contents, NULL, NULL)) { + g_strchomp(contents); + if (contents[0] != '\0') + return contents; + g_free(contents); + } + g_autofree char *basename = g_path_get_basename(cat_path); + return make_display_name(basename); +} + char *find_kaomoji_dir(void) { const char *src_dir = g_getenv("MESON_SOURCE_ROOT"); if (src_dir) { @@ -83,9 +94,10 @@ static void add_kaomoji_button(GtkFlowBox *flow, const char *text) { label_text = first_line; } GtkWidget *button = gtk_button_new_with_label(label_text); + gtk_widget_set_halign(button, GTK_ALIGN_FILL); GtkWidget *label = gtk_button_get_child(GTK_BUTTON(button)); gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_END); - gtk_label_set_max_width_chars(GTK_LABEL(label), 20); + gtk_label_set_xalign(GTK_LABEL(label), 0.0); gtk_widget_add_css_class(button, "kaomoji-button"); gtk_widget_add_css_class(button, "flat"); if (multiline || g_utf8_strlen(label_text, -1) > 20) @@ -150,15 +162,15 @@ static void load_category(MoeMojiWindow *self, const char *kaomoji_dir, g_free(cat_path); return; } - char *display_name = make_display_name(dirname); + char *display_name = get_category_display_name(cat_path); GtkWidget *header = gtk_label_new(display_name); gtk_widget_add_css_class(header, "category-header"); gtk_label_set_xalign(GTK_LABEL(header), 0.0); gtk_box_append(self->content_box, header); GtkWidget *flow = gtk_flow_box_new(); - gtk_flow_box_set_homogeneous(GTK_FLOW_BOX(flow), FALSE); + gtk_flow_box_set_homogeneous(GTK_FLOW_BOX(flow), TRUE); gtk_flow_box_set_min_children_per_line(GTK_FLOW_BOX(flow), 2); - gtk_flow_box_set_max_children_per_line(GTK_FLOW_BOX(flow), 10); + gtk_flow_box_set_max_children_per_line(GTK_FLOW_BOX(flow), 4); gtk_flow_box_set_selection_mode(GTK_FLOW_BOX(flow), GTK_SELECTION_NONE); GPtrArray *files = g_ptr_array_new_with_free_func(g_free); const char *filename; @@ -319,12 +331,58 @@ static void collect_categories(const char *base_dir, GHashTable *seen, g_dir_close(top); } +static gint64 get_dir_time(const char *base, const char *name, + const char *attr) { + g_autofree char *path = g_build_filename(base, name, NULL); + GFile *file = g_file_new_for_path(path); + g_autofree char *attrs = + g_strconcat(attr, ",", G_FILE_ATTRIBUTE_TIME_MODIFIED, NULL); + GFileInfo *info = + g_file_query_info(file, attrs, G_FILE_QUERY_INFO_NONE, NULL, NULL); + gint64 t = 0; + if (info) { + if (g_file_info_has_attribute(info, attr)) + t = g_file_info_get_attribute_uint64(info, attr); + else + t = g_file_info_get_attribute_uint64(info, + G_FILE_ATTRIBUTE_TIME_MODIFIED); + g_object_unref(info); + } + g_object_unref(file); + return t; +} + +static const char *current_sort_order = "alpha-asc"; + static gint compare_entries(gconstpointer a, gconstpointer b) { char **ea = *(char ***)a; char **eb = *(char ***)b; - g_autofree char *ka = g_utf8_collate_key_for_filename(ea[1], -1); - g_autofree char *kb = g_utf8_collate_key_for_filename(eb[1], -1); - return strcmp(ka, kb); + const char *order = current_sort_order; + gboolean desc = g_str_has_suffix(order, "-desc"); + + if (g_str_has_prefix(order, "alpha")) { + g_autofree char *pa = g_build_filename(ea[0], ea[1], NULL); + g_autofree char *pb = g_build_filename(eb[0], eb[1], NULL); + g_autofree char *da = get_category_display_name(pa); + g_autofree char *db = get_category_display_name(pb); + g_autofree char *ka = g_utf8_collate_key_for_filename(da, -1); + g_autofree char *kb = g_utf8_collate_key_for_filename(db, -1); + gint r = strcmp(ka, kb); + return desc ? -r : r; + } + + const char *attr = g_str_has_prefix(order, "created") + ? G_FILE_ATTRIBUTE_TIME_CREATED + : G_FILE_ATTRIBUTE_TIME_MODIFIED; + gint64 ta = get_dir_time(ea[0], ea[1], attr); + gint64 tb = get_dir_time(eb[0], eb[1], attr); + gint r = (ta > tb) - (ta < tb); + if (r == 0) { + g_autofree char *ka = g_utf8_collate_key_for_filename(ea[1], -1); + g_autofree char *kb = g_utf8_collate_key_for_filename(eb[1], -1); + r = strcmp(ka, kb); + } + return desc ? -r : r; } static GPtrArray *collect_all_categories(void) { @@ -362,6 +420,7 @@ static void navigate_to(MoeMojiWindow *self, const char *page, gtk_stack_set_visible_child_name(self->view_stack, page); gboolean is_main = (g_strcmp0(page, "main") == 0); gtk_widget_set_visible(self->add_button, is_main); + gtk_widget_set_visible(self->sort_button, is_main); gtk_widget_set_visible(self->back_button, !is_main); gtk_widget_set_visible(self->menu_button, is_main); } @@ -392,65 +451,25 @@ static void on_new_entry_clicked(G_GNUC_UNUSED GtkButton *button, static gboolean is_valid_category_name(const char *text) { if (!text || text[0] == '\0') return FALSE; - gboolean has_non_space = FALSE; - for (const char *p = text; *p;) { - gunichar ch = g_utf8_get_char(p); - if (g_unichar_isalpha(ch) || g_unichar_isdigit(ch) || ch == '_' || - ch == '-') { - has_non_space = TRUE; - } else if (ch == ' ') { - /* space is allowed */ - } else { - return FALSE; - } - p = g_utf8_next_char(p); - } - return has_non_space; -} - -static char *normalize_category_name(const char *name) { - char *n = g_ascii_strdown(name, -1); - for (char *p = n; *p; p++) { - if (*p == ' ') - *p = '_'; - } - return n; -} - -static gboolean dir_has_category(const char *base, const char *norm_name) { - GDir *dir = g_dir_open(base, 0, NULL); - if (!dir) - return FALSE; - const char *name; - while ((name = g_dir_read_name(dir)) != NULL) { - g_autofree char *norm = normalize_category_name(name); - if (strcmp(norm, norm_name) == 0) { - g_autofree char *full = g_build_filename(base, name, NULL); - if (g_file_test(full, G_FILE_TEST_IS_DIR)) { - g_dir_close(dir); - return TRUE; - } - } - } - g_dir_close(dir); - return FALSE; -} - -static gboolean category_exists(const char *text) { g_autofree char *stripped = g_strstrip(g_strdup(text)); - g_autofree char *norm = normalize_category_name(stripped); - g_autofree char *user_base = - g_build_filename(g_get_user_data_dir(), "moemoji", "kaomoji", NULL); - if (dir_has_category(user_base, norm)) - return TRUE; - char *bundled = find_kaomoji_dir(); - if (bundled) { - gboolean exists = dir_has_category(bundled, norm); - g_free(bundled); - if (exists) - return TRUE; + return stripped[0] != '\0'; +} + +static gboolean category_name_taken(const char *name) { + g_autofree char *stripped = g_strstrip(g_strdup(name)); + GPtrArray *entries = collect_all_categories(); + gboolean found = FALSE; + for (guint i = 0; i < entries->len; i++) { + char **pair = g_ptr_array_index(entries, i); + g_autofree char *cat_path = g_build_filename(pair[0], pair[1], NULL); + g_autofree char *display = get_category_display_name(cat_path); + if (g_utf8_collate(display, stripped) == 0) { + found = TRUE; + break; + } } - return FALSE; + free_category_entries(entries); + return found; } static void on_category_name_changed(G_GNUC_UNUSED GtkEditable *editable, @@ -460,7 +479,7 @@ static void on_category_name_changed(G_GNUC_UNUSED GtkEditable *editable, gtk_editable_get_text(GTK_EDITABLE(self->category_name_entry)); gtk_widget_set_sensitive(self->category_save_button, is_valid_category_name(text) && - !category_exists(text)); + !category_name_taken(text)); } static void on_category_save_clicked(G_GNUC_UNUSED GtkButton *button, @@ -468,17 +487,15 @@ static void on_category_save_clicked(G_GNUC_UNUSED GtkButton *button, MoeMojiWindow *self = MOEMOJI_WINDOW(user_data); const char *text = gtk_editable_get_text(GTK_EDITABLE(self->category_name_entry)); - if (!is_valid_category_name(text) || category_exists(text)) + if (!is_valid_category_name(text) || category_name_taken(text)) return; - g_autofree char *dir_name = g_strdup(text); - g_strstrip(dir_name); - for (char *p = dir_name; *p; p++) { - if (*p == ' ') - *p = '_'; - } - g_autofree char *cat_path = g_build_filename(g_get_user_data_dir(), "moemoji", - "kaomoji", dir_name, NULL); + g_autofree char *stripped = g_strstrip(g_strdup(text)); + g_autofree char *uuid = g_uuid_string_random(); + g_autofree char *cat_path = + g_build_filename(g_get_user_data_dir(), "moemoji", "kaomoji", uuid, NULL); g_mkdir_with_parents(cat_path, 0755); + g_autofree char *name_file = g_build_filename(cat_path, ".name", NULL); + g_file_set_contents(name_file, stripped, -1, NULL); reload_categories(self); navigate_to(self, "main", FALSE); @@ -505,8 +522,8 @@ static void build_pick_category_page(MoeMojiWindow *self, for (guint i = 0; i < entries->len; i++) { char **pair = g_ptr_array_index(entries, i); - g_autofree char *display = make_display_name(pair[1]); g_autofree char *full_path = g_build_filename(pair[0], pair[1], NULL); + g_autofree char *display = get_category_display_name(full_path); GtkWidget *btn = gtk_button_new_with_label(display); gtk_widget_add_css_class(btn, "category-chip"); gtk_widget_add_css_class(btn, "flat"); @@ -676,7 +693,7 @@ static GtkWidget *build_add_category_page(MoeMojiWindow *self) { return box; } -static GtkWidget *build_pick_category_page_widget(MoeMojiWindow *self) { +static GtkWidget *build_pick_category_page_widget(void) { GtkWidget *wrapper = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_widget_set_vexpand(wrapper, TRUE); gtk_widget_set_halign(wrapper, GTK_ALIGN_CENTER); @@ -711,7 +728,6 @@ static GtkWidget *build_pick_category_page_widget(MoeMojiWindow *self) { gtk_box_append(GTK_BOX(wrapper), clamp); g_object_set_data(G_OBJECT(wrapper), "pick-flow", pick_flow); - (void)self; return wrapper; } @@ -847,6 +863,51 @@ static void on_manage_delete_category_response(AdwAlertDialog *dialog, } } +static void on_rename_category_response(AdwAlertDialog *dialog, + GAsyncResult *res, gpointer user_data) { + MoeMojiWindow *self = MOEMOJI_WINDOW(user_data); + const char *response = adw_alert_dialog_choose_finish(dialog, res); + if (g_strcmp0(response, "rename") != 0) + return; + const char *cat_path = g_object_get_data(G_OBJECT(dialog), "cat-path"); + GtkEditable *entry = + GTK_EDITABLE(g_object_get_data(G_OBJECT(dialog), "name-entry")); + const char *raw = gtk_editable_get_text(entry); + g_autofree char *stripped = g_strstrip(g_strdup(raw)); + if (stripped[0] == '\0') + return; + g_autofree char *name_file = g_build_filename(cat_path, ".name", NULL); + g_file_set_contents(name_file, stripped, -1, NULL); + reload_categories(self); + populate_manage_page(self); +} + +static void on_manage_rename_category(GtkButton *button, gpointer user_data) { + MoeMojiWindow *self = MOEMOJI_WINDOW(user_data); + const char *cat_path = g_object_get_data(G_OBJECT(button), "cat-path"); + const char *cat_name = g_object_get_data(G_OBJECT(button), "cat-name"); + + AdwAlertDialog *dialog = + ADW_ALERT_DIALOG(adw_alert_dialog_new("Rename Category", NULL)); + adw_alert_dialog_add_responses(dialog, "cancel", "Cancel", "rename", "Rename", + NULL); + adw_alert_dialog_set_response_appearance(dialog, "rename", + ADW_RESPONSE_SUGGESTED); + adw_alert_dialog_set_default_response(dialog, "rename"); + adw_alert_dialog_set_close_response(dialog, "cancel"); + + GtkWidget *entry = gtk_entry_new(); + gtk_editable_set_text(GTK_EDITABLE(entry), cat_name); + adw_alert_dialog_set_extra_child(dialog, entry); + + g_object_set_data_full(G_OBJECT(dialog), "cat-path", g_strdup(cat_path), + g_free); + g_object_set_data(G_OBJECT(dialog), "name-entry", entry); + adw_alert_dialog_choose(dialog, GTK_WIDGET(self), NULL, + (GAsyncReadyCallback)on_rename_category_response, + self); +} + static void on_manage_delete_category(GtkButton *button, gpointer user_data) { MoeMojiWindow *self = MOEMOJI_WINDOW(user_data); const char *cat_path = g_object_get_data(G_OBJECT(button), "cat-path"); @@ -888,7 +949,7 @@ static void populate_manage_page(MoeMojiWindow *self) { for (guint i = 0; i < entries->len; i++) { char **pair = g_ptr_array_index(entries, i); g_autofree char *cat_path = g_build_filename(pair[0], pair[1], NULL); - g_autofree char *display_name = make_display_name(pair[1]); + g_autofree char *display_name = get_category_display_name(cat_path); GtkWidget *cat_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8); gtk_widget_set_margin_top(cat_hbox, 8); @@ -899,6 +960,19 @@ static void populate_manage_page(MoeMojiWindow *self) { gtk_widget_set_hexpand(cat_label, TRUE); gtk_box_append(GTK_BOX(cat_hbox), cat_label); + GtkWidget *cat_rename_btn = + gtk_button_new_from_icon_name("document-edit-symbolic"); + gtk_widget_add_css_class(cat_rename_btn, "manage-cat-rename"); + gtk_widget_add_css_class(cat_rename_btn, "circular"); + gtk_widget_set_valign(cat_rename_btn, GTK_ALIGN_CENTER); + g_object_set_data_full(G_OBJECT(cat_rename_btn), "cat-path", + g_strdup(cat_path), g_free); + g_object_set_data_full(G_OBJECT(cat_rename_btn), "cat-name", + g_strdup(display_name), g_free); + g_signal_connect(cat_rename_btn, "clicked", + G_CALLBACK(on_manage_rename_category), self); + gtk_box_append(GTK_BOX(cat_hbox), cat_rename_btn); + GtkWidget *cat_del_btn = gtk_button_new_from_icon_name("window-close-symbolic"); gtk_widget_add_css_class(cat_del_btn, "manage-cat-delete"); @@ -1231,35 +1305,112 @@ static void on_import_activated(G_GNUC_UNUSED GSimpleAction *action, g_object_unref(dialog); } +static void update_sort_button_icon(MoeMojiWindow *self) { + g_autofree char *order = + g_settings_get_string(self->settings, "category-sort"); + const char *icon = g_str_has_suffix(order, "-desc") + ? "view-sort-descending-symbolic" + : "view-sort-ascending-symbolic"; + gtk_menu_button_set_icon_name(GTK_MENU_BUTTON(self->sort_button), icon); +} + +static void on_sort_order_changed(GSimpleAction *action, GVariant *parameter, + gpointer user_data) { + MoeMojiWindow *self = MOEMOJI_WINDOW(user_data); + g_simple_action_set_state(action, parameter); + const char *order = g_variant_get_string(parameter, NULL); + g_settings_set_string(self->settings, "category-sort", order); + current_sort_order = order; + update_sort_button_icon(self); + reload_categories(self); +} + static void moemoji_window_class_init(MoeMojiWindowClass *klass) { GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); gtk_widget_class_set_template_from_resource( widget_class, "/jp/angeltech/MoeMoji/moemoji-window.ui"); + gtk_widget_class_bind_template_child(widget_class, MoeMojiWindow, + wrapper_box); gtk_widget_class_bind_template_child(widget_class, MoeMojiWindow, outer_box); gtk_widget_class_bind_template_child(widget_class, MoeMojiWindow, content_box); gtk_widget_class_bind_template_child(widget_class, MoeMojiWindow, search_entry); - gtk_widget_class_bind_template_child(widget_class, MoeMojiWindow, header_bar); gtk_widget_class_bind_template_child(widget_class, MoeMojiWindow, kaomoji_scroll); gtk_widget_class_bind_template_child(widget_class, MoeMojiWindow, view_stack); - gtk_widget_class_bind_template_child(widget_class, MoeMojiWindow, add_button); - gtk_widget_class_bind_template_child(widget_class, MoeMojiWindow, - back_button); - gtk_widget_class_bind_template_child(widget_class, MoeMojiWindow, - menu_button); } static void moemoji_window_init(MoeMojiWindow *self) { gtk_widget_init_template(GTK_WIDGET(self)); gtk_widget_add_css_class(GTK_WIDGET(self), "wallpaper-bg"); - gtk_widget_add_css_class(GTK_WIDGET(self->header_bar), "wallpaper-bg"); gtk_widget_add_css_class(GTK_WIDGET(self->content_box), "content-area"); + + GtkWidget *empty_titlebar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_widget_set_visible(empty_titlebar, FALSE); + gtk_window_set_titlebar(GTK_WINDOW(self), empty_titlebar); + + self->header_bar = GTK_WIDGET(adw_header_bar_new()); + gtk_widget_add_css_class(self->header_bar, "flat"); + adw_header_bar_set_show_end_title_buttons(ADW_HEADER_BAR(self->header_bar), + TRUE); + self->settings = g_settings_new("jp.angeltech.MoeMoji"); + + self->add_button = gtk_button_new_from_icon_name("list-add-symbolic"); + adw_header_bar_pack_start(ADW_HEADER_BAR(self->header_bar), self->add_button); + + self->sort_button = GTK_WIDGET(gtk_menu_button_new()); + GMenu *sort_menu = g_menu_new(); + g_menu_append(sort_menu, "Alphabetically ↑", "win.sort-order::alpha-asc"); + g_menu_append(sort_menu, "Alphabetically ↓", "win.sort-order::alpha-desc"); + g_menu_append(sort_menu, "Modified ↑", "win.sort-order::modified-asc"); + g_menu_append(sort_menu, "Modified ↓", "win.sort-order::modified-desc"); + g_menu_append(sort_menu, "Created ↑", "win.sort-order::created-asc"); + g_menu_append(sort_menu, "Created ↓", "win.sort-order::created-desc"); + gtk_menu_button_set_menu_model(GTK_MENU_BUTTON(self->sort_button), + G_MENU_MODEL(sort_menu)); + g_object_unref(sort_menu); + adw_header_bar_pack_start(ADW_HEADER_BAR(self->header_bar), + self->sort_button); + + g_autofree char *saved_order = + g_settings_get_string(self->settings, "category-sort"); + GSimpleAction *sort_action = g_simple_action_new_stateful( + "sort-order", G_VARIANT_TYPE_STRING, g_variant_new_string(saved_order)); + g_signal_connect(sort_action, "change-state", + G_CALLBACK(on_sort_order_changed), self); + g_action_map_add_action(G_ACTION_MAP(self), G_ACTION(sort_action)); + current_sort_order = + g_variant_get_string(g_action_get_state(G_ACTION(sort_action)), NULL); + update_sort_button_icon(self); + g_object_unref(sort_action); + + self->back_button = gtk_button_new_from_icon_name("go-previous-symbolic"); + gtk_widget_set_visible(self->back_button, FALSE); + adw_header_bar_pack_start(ADW_HEADER_BAR(self->header_bar), + self->back_button); + + self->menu_button = GTK_WIDGET(gtk_menu_button_new()); + gtk_menu_button_set_icon_name(GTK_MENU_BUTTON(self->menu_button), + "open-menu-symbolic"); + GMenu *primary_menu = g_menu_new(); + GMenu *sec1 = g_menu_new(); + g_menu_append(sec1, "Manage…", "win.manage"); + g_menu_append_section(primary_menu, NULL, G_MENU_MODEL(sec1)); + g_object_unref(sec1); + GMenu *sec2 = g_menu_new(); + g_menu_append(sec2, "Export…", "win.export"); + g_menu_append(sec2, "Import…", "win.import"); + g_menu_append_section(primary_menu, NULL, G_MENU_MODEL(sec2)); + g_object_unref(sec2); + gtk_menu_button_set_menu_model(GTK_MENU_BUTTON(self->menu_button), + G_MENU_MODEL(primary_menu)); + g_object_unref(primary_menu); + adw_header_bar_pack_end(ADW_HEADER_BAR(self->header_bar), self->menu_button); + gtk_box_prepend(self->wrapper_box, self->header_bar); self->category_widgets = g_ptr_array_new_with_free_func(category_widgets_free); self->active_chip_index = -1; - self->selected_category_dir = NULL; GSimpleAction *export_action = g_simple_action_new("export", NULL); g_signal_connect(export_action, "activate", G_CALLBACK(on_export_activated), @@ -1287,7 +1438,7 @@ static void moemoji_window_init(MoeMojiWindow *self) { gtk_stack_add_named(self->view_stack, choice_page, "add-choice"); GtkWidget *cat_page = build_add_category_page(self); gtk_stack_add_named(self->view_stack, cat_page, "add-category"); - GtkWidget *pick_page = build_pick_category_page_widget(self); + GtkWidget *pick_page = build_pick_category_page_widget(); gtk_stack_add_named(self->view_stack, pick_page, "pick-category"); GtkWidget *entry_page = build_add_entry_page(self); gtk_stack_add_named(self->view_stack, entry_page, "add-entry"); diff --git a/src/moemoji-window.h b/src/moemoji-window.h index 872466e..81fcb6c 100644 --- a/src/moemoji-window.h +++ b/src/moemoji-window.h @@ -11,6 +11,7 @@ typedef struct { struct _MoeMojiWindow { GtkApplicationWindow parent_instance; + GtkBox *wrapper_box; GtkBox *outer_box; GtkBox *content_box; GtkSearchEntry *search_entry; @@ -22,8 +23,10 @@ struct _MoeMojiWindow { int active_chip_index; GtkStack *view_stack; GtkWidget *add_button; + GtkWidget *sort_button; GtkWidget *back_button; GtkWidget *menu_button; + GSettings *settings; GtkEntry *category_name_entry; GtkWidget *entry_text_view; GtkWidget *category_save_button; diff --git a/src/moemoji-window.ui b/src/moemoji-window.ui index 4628b3b..e7cbd64 100644 --- a/src/moemoji-window.ui +++ b/src/moemoji-window.ui @@ -7,87 +7,52 @@ True MoeMoji - - - True - - - list-add-symbolic - - - - - go-previous-symbolic - False - - - - - open-menu-symbolic - primary_menu - - - - - - - slide-left - 200 + + vertical - - main - - - vertical - - - Jump to category... - 6 - 6 - 6 - - - - - never - True + + slide-left + 200 + True + + + main + + + vertical - - vertical + + Jump to category... 6 6 6 - 6 - 4 + + + + + never + True + + + vertical + 6 + 6 + 6 + 6 + 4 + + - + - + - -
- - Manage… - win.manage - -
-
- - Export… - win.export - - - Import… - win.import - -
-
\ No newline at end of file diff --git a/src/style.css b/src/style.css index 1a68d8e..f0b68ad 100644 --- a/src/style.css +++ b/src/style.css @@ -1,10 +1,14 @@ .kaomoji-button { font-size: 14px; - min-width: 60px; min-height: 36px; padding: 4px 8px; } +.kaomoji-button label { + text-align: left; + text-shadow: -1px -1px 2px rgba(102, 34, 74, 0.8), 1px -1px 0 rgba(102, 34, 74, 0.8), -1px 1px 0 rgba(102, 34, 74, 0.8), 1px 1px 0 rgba(102, 34, 74, 0.8); +} + .kaomoji-wide { min-width: 100%; } @@ -41,14 +45,6 @@ background-color: transparent; } -#header_bar { - background-color: transparent; -} - -#header_bar > * { - background-color: transparent; -} - .category-bar { background-color: rgba(0, 0, 0, 0.4); border-radius: 14px; @@ -98,6 +94,14 @@ color: @destructive_fg_color; } +.manage-cat-rename { + min-width: 24px; + min-height: 24px; + padding: 2px; + background-color: #c8a600; + color: white; +} + .manage-cat-delete { min-width: 24px; min-height: 24px; diff --git a/tests/meson.build b/tests/meson.build index 10c8058..63d80b2 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -24,11 +24,16 @@ test_moemoji = executable('test-moemoji', c_args: ['-DSRCDIR="' + meson.project_source_root() + '"'], ) -test('moemoji-unit', test_moemoji) +schema_dir = meson.project_build_root() / 'data' + +test('moemoji-unit', test_moemoji, + env: ['GSETTINGS_SCHEMA_DIR=' + schema_dir], +) custom_target('run-unit-tests', command: [test_moemoji], output: 'test-stamp', build_by_default: true, depends: test_moemoji, + env: ['GSETTINGS_SCHEMA_DIR=' + schema_dir], ) diff --git a/tests/test-moemoji.c b/tests/test-moemoji.c index 0bf0bdf..a57745a 100644 --- a/tests/test-moemoji.c +++ b/tests/test-moemoji.c @@ -6,13 +6,13 @@ static void test_display_name_underscores(void) { char *name = make_display_name("happy_faces"); - g_assert_cmpstr(name, ==, "Happy faces"); + g_assert_cmpstr(name, ==, "happy faces"); g_free(name); } static void test_display_name_no_underscores(void) { char *name = make_display_name("animals"); - g_assert_cmpstr(name, ==, "Animals"); + g_assert_cmpstr(name, ==, "animals"); g_free(name); } @@ -24,7 +24,7 @@ static void test_display_name_already_upper(void) { static void test_display_name_single_char(void) { char *name = make_display_name("x"); - g_assert_cmpstr(name, ==, "X"); + g_assert_cmpstr(name, ==, "x"); g_free(name); } @@ -142,6 +142,17 @@ static GResource *test_res = NULL; static GtkWidget *test_win = NULL; static MoeMojiWindow *test_self = NULL; +static void cleanup_user_kaomoji_dir(void) { + char *kaomoji_parent = + g_build_filename(g_get_user_data_dir(), "moemoji", "kaomoji", NULL); + g_rmdir(kaomoji_parent); + g_free(kaomoji_parent); + char *moemoji_parent = + g_build_filename(g_get_user_data_dir(), "moemoji", NULL); + g_rmdir(moemoji_parent); + g_free(moemoji_parent); +} + static void window_test_setup(void) { if (!test_res) { test_res = moemoji_get_resource(); @@ -277,14 +288,7 @@ static void test_add_category_creates_dir(void) { g_assert_true(found); window_test_teardown(); g_rmdir(cat_dir); - char *kaomoji_parent = - g_build_filename(g_get_user_data_dir(), "moemoji", "kaomoji", NULL); - g_rmdir(kaomoji_parent); - g_free(kaomoji_parent); - char *moemoji_parent = - g_build_filename(g_get_user_data_dir(), "moemoji", NULL); - g_rmdir(moemoji_parent); - g_free(moemoji_parent); + cleanup_user_kaomoji_dir(); g_free(cat_dir); } @@ -334,14 +338,7 @@ static void test_add_entry_creates_file(void) { g_unlink(fpath); g_unlink(fpath2); g_rmdir(cat_dir); - char *kaomoji_parent = - g_build_filename(g_get_user_data_dir(), "moemoji", "kaomoji", NULL); - g_rmdir(kaomoji_parent); - g_free(kaomoji_parent); - char *moemoji_parent = - g_build_filename(g_get_user_data_dir(), "moemoji", NULL); - g_rmdir(moemoji_parent); - g_free(moemoji_parent); + cleanup_user_kaomoji_dir(); g_free(cat_dir); g_free(fpath); g_free(fpath2); @@ -400,14 +397,7 @@ static void test_export_creates_archive(void) { g_free(fpath); g_rmdir(cat_dir); g_free(cat_dir); - char *kaomoji_parent = - g_build_filename(g_get_user_data_dir(), "moemoji", "kaomoji", NULL); - g_rmdir(kaomoji_parent); - g_free(kaomoji_parent); - char *moemoji_parent = - g_build_filename(g_get_user_data_dir(), "moemoji", NULL); - g_rmdir(moemoji_parent); - g_free(moemoji_parent); + cleanup_user_kaomoji_dir(); g_free(user_dir); } @@ -466,11 +456,7 @@ static void test_import_extracts_and_loads(void) { char *imported_cat = g_build_filename(user_dir, "ZZZ_import_test", NULL); g_rmdir(imported_cat); g_free(imported_cat); - g_rmdir(user_dir); - char *moemoji_parent = - g_build_filename(g_get_user_data_dir(), "moemoji", NULL); - g_rmdir(moemoji_parent); - g_free(moemoji_parent); + cleanup_user_kaomoji_dir(); g_free(user_dir); g_unlink(fpath); @@ -502,11 +488,14 @@ static void test_category_name_validation(void) { "my-cool_category"); g_assert_true(gtk_widget_get_sensitive(test_self->category_save_button)); gtk_editable_set_text(GTK_EDITABLE(test_self->category_name_entry), - "bad/name"); - g_assert_false(gtk_widget_get_sensitive(test_self->category_save_button)); + "Кириллица"); + g_assert_true(gtk_widget_get_sensitive(test_self->category_save_button)); gtk_editable_set_text(GTK_EDITABLE(test_self->category_name_entry), - "bad.name"); - g_assert_false(gtk_widget_get_sensitive(test_self->category_save_button)); + "日本語カテゴリ"); + g_assert_true(gtk_widget_get_sensitive(test_self->category_save_button)); + gtk_editable_set_text(GTK_EDITABLE(test_self->category_name_entry), + "symbols & stuff!!"); + g_assert_true(gtk_widget_get_sensitive(test_self->category_save_button)); window_test_teardown(); }