commit 9b67d565baf5ce0f555cb38abdda22696cbfe778
parent 5df934d452aaedf319028740987de0e0dcac52d5
Author: TheJackiMonster <thejackimonster@gmail.com>
Date: Thu, 25 Nov 2021 22:45:04 +0100
Added emoji picker
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
Diffstat:
12 files changed, 898 insertions(+), 6 deletions(-)
diff --git a/.gitmodules b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "submodules/gnome-characters"]
+ path = submodules/gnome-characters
+ url = https://gitlab.gnome.org/GNOME/gnome-characters.git
diff --git a/Makefile b/Makefile
@@ -15,6 +15,7 @@ SOURCES = messenger_gtk.c\
ui/messenger.c\
ui/new_contact.c\
ui/new_platform.c\
+ ui/picker.c\
ui/profile_entry.c\
ui/settings.c
@@ -22,6 +23,7 @@ HEADERS =
LIBRARIES = gnunetchat
PACKAGES = gnunetutil libhandy-1 gtk+-3.0 libnotify zbar libqrencode
+INCLUDES = submodules/gnome-characters/lib
GNU_CC ?= gcc
GNU_LD ?= gcc
@@ -38,6 +40,7 @@ OBJECT_FILES = $(SOURCE_FILES:%.c=%.o)
HEADER_FILES = $(addprefix $(SOURCE_DIR), $(HEADERS))
LIBRARY_FLAGS = $(addprefix -l, $(LIBRARIES))
PACKAGE_FLAGS = $(shell pkg-config --cflags --libs $(PACKAGES))
+INCLUDE_FLAGS = $(addprefix -I, $(INCLUDES))
all: $(BINARY)
@@ -48,7 +51,7 @@ release: CFLAGS += $(RELEASEFLAGS)
release: $(BINARY)
%.o: %.c
- $(GNU_CC) $(CFLAGS) -c $< -o $@ $(LIBRARY_FLAGS) $(PACKAGE_FLAGS)
+ $(GNU_CC) $(CFLAGS) -c $< -o $@ $(LIBRARY_FLAGS) $(PACKAGE_FLAGS) $(INCLUDE_FLAGS)
$(BINARY): $(OBJECT_FILES)
$(GNU_LD) $(LDFLAGS) $^ -o $@ $(LIBRARY_FLAGS) $(PACKAGE_FLAGS)
diff --git a/resources/css/style.css b/resources/css/style.css
@@ -61,6 +61,14 @@
padding: 2px 4px;
}
+.picker-switcher-box {
+ padding: 0px 8px;
+}
+
+.emoji-flow-box {
+ font-size: large;
+}
+
.settings-entry {
margin: 8px;
}
diff --git a/resources/ui/chat.ui b/resources/ui/chat.ui
@@ -169,6 +169,22 @@ Author: Tobias Frisch
</packing>
</child>
<child>
+ <object class="GtkRevealer" id="picker_revealer">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="transition-type">slide-up</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
@@ -263,7 +279,8 @@ Author: Tobias Frisch
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">2</property>
+ <property name="pack-type">end</property>
+ <property name="position">3</property>
</packing>
</child>
</object>
diff --git a/resources/ui/picker.ui b/resources/ui/picker.ui
@@ -0,0 +1,508 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.38.2
+
+Copyright (C) 2021 GNUnet e.V.
+
+GNUnet is free software: you can redistribute it and/or modify it
+under the terms of the GNU Affero General Public License as published
+by the Free Software Foundation, either version 3 of the License,
+or (at your option) any later version.
+
+GNUnet is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+SPDX-License-Identifier: AGPL3.0-or-later
+Author: Tobias Frisch
+
+-->
+<interface>
+ <requires lib="gtk+" version="3.24"/>
+ <requires lib="libhandy" version="1.2"/>
+ <object class="GtkBox" id="picker_box">
+ <property name="height-request">250</property>
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkStack" id="picker_stack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="vscrollbar-policy">never</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="HdyViewSwitcherBar" id="emoji_switcher_bar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="stack">emoji_stack</property>
+ <property name="reveal">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStack" id="emoji_stack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkFlowBox" id="recent_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">8</property>
+ <property name="homogeneous">True</property>
+ <property name="max-children-per-line">8</property>
+ <property name="selection-mode">none</property>
+ <style>
+ <class name="emoji-flow-box"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">recent</property>
+ <property name="icon-name">emoji-recent-symbolic</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkFlowBox" id="people_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">8</property>
+ <property name="homogeneous">True</property>
+ <property name="max-children-per-line">8</property>
+ <property name="selection-mode">none</property>
+ <style>
+ <class name="emoji-flow-box"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">people</property>
+ <property name="icon-name">emoji-people-symbolic</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkFlowBox" id="nature_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">8</property>
+ <property name="homogeneous">True</property>
+ <property name="max-children-per-line">8</property>
+ <property name="selection-mode">none</property>
+ <style>
+ <class name="emoji-flow-box"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">nature</property>
+ <property name="icon-name">emoji-nature-symbolic</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkFlowBox" id="food_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">8</property>
+ <property name="homogeneous">True</property>
+ <property name="max-children-per-line">8</property>
+ <property name="selection-mode">none</property>
+ <style>
+ <class name="emoji-flow-box"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">food</property>
+ <property name="icon-name">emoji-food-symbolic</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkFlowBox" id="activities_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">8</property>
+ <property name="homogeneous">True</property>
+ <property name="max-children-per-line">8</property>
+ <property name="selection-mode">none</property>
+ <style>
+ <class name="emoji-flow-box"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">activities</property>
+ <property name="icon-name">emoji-activities-symbolic</property>
+ <property name="position">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkFlowBox" id="travel_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">8</property>
+ <property name="homogeneous">True</property>
+ <property name="max-children-per-line">8</property>
+ <property name="selection-mode">none</property>
+ <style>
+ <class name="emoji-flow-box"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">travel</property>
+ <property name="icon-name">emoji-travel-symbolic</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkFlowBox" id="objects_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">8</property>
+ <property name="homogeneous">True</property>
+ <property name="max-children-per-line">8</property>
+ <property name="selection-mode">none</property>
+ <style>
+ <class name="emoji-flow-box"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">objects</property>
+ <property name="icon-name">emoji-objects-symbolic</property>
+ <property name="position">6</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkFlowBox" id="symbols_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">8</property>
+ <property name="homogeneous">True</property>
+ <property name="max-children-per-line">8</property>
+ <property name="selection-mode">none</property>
+ <style>
+ <class name="emoji-flow-box"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">symbols</property>
+ <property name="icon-name">emoji-symbols-symbolic</property>
+ <property name="position">7</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkFlowBox" id="flags_flow_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">8</property>
+ <property name="homogeneous">True</property>
+ <property name="max-children-per-line">8</property>
+ <property name="selection-mode">none</property>
+ <style>
+ <class name="emoji-flow-box"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">flags</property>
+ <property name="icon-name">emoji-flags-symbolic</property>
+ <property name="position">8</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="HdySearchBar" id="emoji_search_bar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="show-close-button">True</property>
+ <child>
+ <object class="GtkSearchEntry" id="emoji_search_entry">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="primary-icon-name">edit-find-symbolic</property>
+ <property name="primary-icon-activatable">False</property>
+ <property name="primary-icon-sensitive">False</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">emoji</property>
+ <property name="title" translatable="yes">Emoji</property>
+ <property name="icon-name">face-smile-symbolic</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="name">gif</property>
+ <property name="title" translatable="yes">GIF</property>
+ <property name="icon-name">video-x-generic-symbolic</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="name">stickers</property>
+ <property name="title" translatable="yes">Stickers</property>
+ <property name="icon-name">image-x-generic-symbolic</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkButton" id="search_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="valign">center</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">system-search-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="HdyViewSwitcherBar" id="picker_switcher_bar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="policy">auto</property>
+ <property name="stack">picker_stack</property>
+ <property name="reveal">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="settings_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="valign">center</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">preferences-other-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <style>
+ <class name="picker-switcher-box"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/src/application.c b/src/application.c
@@ -157,8 +157,6 @@ application_run(MESSENGER_Application *app)
pthread_join(app->chat.tid, NULL);
- ui_messenger_cleanup(&(app->ui.messenger));
-
g_hash_table_destroy(app->ui.bindings);
notify_uninit();
diff --git a/src/ui/chat.c b/src/ui/chat.c
@@ -25,6 +25,7 @@
#include "chat.h"
#include "messenger.h"
+#include "picker.h"
#include "../application.h"
static void
@@ -67,7 +68,7 @@ handle_send_text_buffer_changed(GtkTextBuffer *buffer,
gtk_image_set_from_icon_name(
symbol,
- 0 < g_utf8_strlen(text, 1)?
+ 0 < strlen(text)?
"mail-send-symbolic" :
"audio-input-microphone-symbolic",
GTK_ICON_SIZE_BUTTON
@@ -86,7 +87,7 @@ _send_text_from_view(MESSENGER_Application *app,
const gchar *text = gtk_text_buffer_get_text(buffer, &start, &end, TRUE);
- if (0 == g_utf8_strlen(text, 1))
+ if (0 == strlen(text))
return FALSE;
struct GNUNET_CHAT_Context *context = g_hash_table_lookup(
@@ -132,6 +133,16 @@ handle_send_text_key_press (GtkWidget *widget,
return _send_text_from_view(app, GTK_TEXT_VIEW(widget));
}
+static void
+handle_picker_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ GtkRevealer *revealer = GTK_REVEALER(user_data);
+ gboolean reveal = !gtk_revealer_get_child_revealed(revealer);
+
+ gtk_revealer_set_reveal_child(revealer, reveal);
+}
+
UI_CHAT_Handle*
ui_chat_new(MESSENGER_Application *app)
{
@@ -239,12 +250,32 @@ ui_chat_new(MESSENGER_Application *app)
handle->send_text_view
);
+ handle->picker_revealer = GTK_REVEALER(
+ gtk_builder_get_object(handle->builder, "picker_revealer")
+ );
+
+ handle->picker = ui_picker_new(app, handle);
+
+ gtk_container_add(
+ GTK_CONTAINER(handle->picker_revealer),
+ handle->picker->picker_box
+ );
+
+ g_signal_connect(
+ handle->emoji_button,
+ "clicked",
+ G_CALLBACK(handle_picker_button_click),
+ handle->picker_revealer
+ );
+
return handle;
}
void
ui_chat_delete(UI_CHAT_Handle *handle)
{
+ ui_picker_delete(handle->picker);
+
g_object_unref(handle->builder);
g_free(handle);
diff --git a/src/ui/chat.h b/src/ui/chat.h
@@ -30,6 +30,7 @@
#include <libnotify/notify.h>
typedef struct MESSENGER_Application MESSENGER_Application;
+typedef struct UI_PICKER_Handle UI_PICKER_Handle;
typedef struct UI_CHAT_Handle
{
@@ -49,6 +50,10 @@ typedef struct UI_CHAT_Handle
GtkButton *emoji_button;
GtkButton *send_record_button;
GtkImage *send_record_symbol;
+
+ GtkRevealer *picker_revealer;
+
+ UI_PICKER_Handle *picker;
} UI_CHAT_Handle;
UI_CHAT_Handle*
diff --git a/src/ui/messenger.c b/src/ui/messenger.c
@@ -150,6 +150,8 @@ handle_main_window_destroy(UNUSED GtkWidget *window,
{
MESSENGER_Application *app = (MESSENGER_Application*) user_data;
+ ui_messenger_cleanup(&(app->ui.messenger));
+
application_exit(app, MESSENGER_QUIT);
}
diff --git a/src/ui/picker.c b/src/ui/picker.c
@@ -0,0 +1,251 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2021 GNUnet e.V.
+
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ SPDX-License-Identifier: AGPL3.0-or-later
+ */
+/*
+ * @author Tobias Frisch
+ * @file ui/picker.c
+ */
+
+#include "picker.h"
+
+#include "../application.h"
+
+#include <emoji.h>
+
+static void
+handle_emoji_button_click(GtkButton *button,
+ gpointer user_data)
+{
+ GtkTextView *text_view = GTK_TEXT_VIEW(user_data);
+ GtkTextBuffer *text_buffer = gtk_text_view_get_buffer(text_view);
+
+ const gchar *label = gtk_button_get_label(button);
+
+ if (label)
+ gtk_text_buffer_insert_at_cursor(text_buffer, label, strlen(label));
+}
+
+static void
+_add_emoji_buttons(GtkFlowBox *flow_box,
+ GtkTextView *text_view,
+ size_t characters_count,
+ const uint32_t *characters)
+{
+ for (size_t i = 0; i < characters_count; i++) {
+ GString *string = g_string_new("");
+ g_string_append_unichar(string, (gunichar) characters[i]);
+
+ GtkButton *emoji_button = GTK_BUTTON(
+ gtk_button_new_with_label(string->str)
+ );
+
+ gtk_button_set_relief(emoji_button, GTK_RELIEF_NONE);
+
+ g_signal_connect(
+ emoji_button,
+ "clicked",
+ G_CALLBACK(handle_emoji_button_click),
+ text_view
+ );
+
+ gtk_flow_box_insert(flow_box, GTK_WIDGET(emoji_button), -1);
+ gtk_widget_show(GTK_WIDGET(emoji_button));
+
+ g_string_free(string, TRUE);
+ }
+}
+
+static void
+handle_search_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ UI_PICKER_Handle *handle = (UI_PICKER_Handle*) user_data;
+
+ const gchar* picked = gtk_stack_get_visible_child_name(handle->picker_stack);
+
+ HdySearchBar *search_bar = NULL;
+
+ if (0 == g_strcmp0(picked, "emoji"))
+ search_bar = handle->emoji_search_bar;
+
+ if (search_bar)
+ hdy_search_bar_set_search_mode(
+ search_bar,
+ !hdy_search_bar_get_search_mode(search_bar)
+ );
+}
+
+UI_PICKER_Handle*
+ui_picker_new(UNUSED MESSENGER_Application *app,
+ UI_CHAT_Handle *chat)
+{
+ UI_PICKER_Handle *handle = g_malloc(sizeof(UI_PICKER_Handle));
+
+ handle->builder = gtk_builder_new_from_file(
+ "resources/ui/picker.ui"
+ );
+
+ handle->picker_box = GTK_WIDGET(
+ gtk_builder_get_object(handle->builder, "picker_box")
+ );
+
+ handle->picker_stack = GTK_STACK(
+ gtk_builder_get_object(handle->builder, "picker_stack")
+ );
+
+ handle->emoji_stack = GTK_STACK(
+ gtk_builder_get_object(handle->builder, "emoji_stack")
+ );
+
+ handle->picker_switcher_bar = HDY_VIEW_SWITCHER_BAR(
+ gtk_builder_get_object(handle->builder, "picker_switcher_bar")
+ );
+
+ handle->emoji_switcher_bar = HDY_VIEW_SWITCHER_BAR(
+ gtk_builder_get_object(handle->builder, "emoji_switcher_bar")
+ );
+
+ handle->recent_flow_box = GTK_FLOW_BOX(
+ gtk_builder_get_object(handle->builder, "recent_flow_box")
+ );
+
+ handle->people_flow_box = GTK_FLOW_BOX(
+ gtk_builder_get_object(handle->builder, "people_flow_box")
+ );
+
+ _add_emoji_buttons(
+ handle->people_flow_box,
+ chat->send_text_view,
+ EMOJI_SMILEYS_CHARACTER_COUNT,
+ emoji_smileys_characters
+ );
+
+ handle->nature_flow_box = GTK_FLOW_BOX(
+ gtk_builder_get_object(handle->builder, "nature_flow_box")
+ );
+
+ _add_emoji_buttons(
+ handle->nature_flow_box,
+ chat->send_text_view,
+ EMOJI_ANIMALS_CHARACTER_COUNT,
+ emoji_animals_characters
+ );
+
+ handle->food_flow_box = GTK_FLOW_BOX(
+ gtk_builder_get_object(handle->builder, "food_flow_box")
+ );
+
+ _add_emoji_buttons(
+ handle->food_flow_box,
+ chat->send_text_view,
+ EMOJI_FOOD_CHARACTER_COUNT,
+ emoji_food_characters
+ );
+
+ handle->activities_flow_box = GTK_FLOW_BOX(
+ gtk_builder_get_object(handle->builder, "activities_flow_box")
+ );
+
+ _add_emoji_buttons(
+ handle->activities_flow_box,
+ chat->send_text_view,
+ EMOJI_ACTIVITIES_CHARACTER_COUNT,
+ emoji_activities_characters
+ );
+
+ handle->travel_flow_box = GTK_FLOW_BOX(
+ gtk_builder_get_object(handle->builder, "travel_flow_box")
+ );
+
+ _add_emoji_buttons(
+ handle->travel_flow_box,
+ chat->send_text_view,
+ EMOJI_TRAVEL_CHARACTER_COUNT,
+ emoji_travel_characters
+ );
+
+ handle->objects_flow_box = GTK_FLOW_BOX(
+ gtk_builder_get_object(handle->builder, "objects_flow_box")
+ );
+
+ _add_emoji_buttons(
+ handle->objects_flow_box,
+ chat->send_text_view,
+ EMOJI_OBJECTS_CHARACTER_COUNT,
+ emoji_objects_characters
+ );
+
+ handle->symbols_flow_box = GTK_FLOW_BOX(
+ gtk_builder_get_object(handle->builder, "symbols_flow_box")
+ );
+
+ _add_emoji_buttons(
+ handle->symbols_flow_box,
+ chat->send_text_view,
+ EMOJI_SYMBOLS_CHARACTER_COUNT,
+ emoji_symbols_characters
+ );
+
+ handle->flags_flow_box = GTK_FLOW_BOX(
+ gtk_builder_get_object(handle->builder, "flags_flow_box")
+ );
+
+ _add_emoji_buttons(
+ handle->flags_flow_box,
+ chat->send_text_view,
+ EMOJI_FLAGS_CHARACTER_COUNT,
+ emoji_flags_characters
+ );
+
+ handle->emoji_search_bar = HDY_SEARCH_BAR(
+ gtk_builder_get_object(handle->builder, "emoji_search_bar")
+ );
+
+ handle->emoji_search_entry = GTK_SEARCH_ENTRY(
+ gtk_builder_get_object(handle->builder, "emoji_search_entry")
+ );
+
+ handle->search_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "search_button")
+ );
+
+ g_signal_connect(
+ handle->search_button,
+ "clicked",
+ G_CALLBACK(handle_search_button_click),
+ handle
+ );
+
+ handle->settings_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "settings_button")
+ );
+
+ return handle;
+}
+
+void
+ui_picker_delete(UI_PICKER_Handle *handle)
+{
+ hdy_view_switcher_bar_set_stack(handle->picker_switcher_bar, NULL);
+ hdy_view_switcher_bar_set_stack(handle->emoji_switcher_bar, NULL);
+
+ g_object_unref(handle->builder);
+
+ g_free(handle);
+}
diff --git a/src/ui/picker.h b/src/ui/picker.h
@@ -0,0 +1,65 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2021 GNUnet e.V.
+
+ GNUnet is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+ SPDX-License-Identifier: AGPL3.0-or-later
+ */
+/*
+ * @author Tobias Frisch
+ * @file ui/picker.h
+ */
+
+#ifndef UI_PICKER_H_
+#define UI_PICKER_H_
+
+#include "chat.h"
+
+typedef struct UI_PICKER_Handle
+{
+ GtkBuilder *builder;
+ GtkWidget *picker_box;
+
+ GtkStack *picker_stack;
+ GtkStack *emoji_stack;
+
+ HdyViewSwitcherBar *picker_switcher_bar;
+ HdyViewSwitcherBar *emoji_switcher_bar;
+
+ GtkFlowBox *recent_flow_box;
+ GtkFlowBox *people_flow_box;
+ GtkFlowBox *nature_flow_box;
+ GtkFlowBox *food_flow_box;
+ GtkFlowBox *activities_flow_box;
+ GtkFlowBox *travel_flow_box;
+ GtkFlowBox *objects_flow_box;
+ GtkFlowBox *symbols_flow_box;
+ GtkFlowBox *flags_flow_box;
+
+ HdySearchBar *emoji_search_bar;
+ GtkSearchEntry *emoji_search_entry;
+
+ GtkButton *search_button;
+ GtkButton *settings_button;
+} UI_PICKER_Handle;
+
+UI_PICKER_Handle*
+ui_picker_new(MESSENGER_Application *app,
+ UI_CHAT_Handle *chat);
+
+void
+ui_picker_delete(UI_PICKER_Handle *handle);
+
+#endif /* UI_PICKER_H_ */
diff --git a/submodules/gnome-characters b/submodules/gnome-characters
@@ -0,0 +1 @@
+Subproject commit f732b513cd5b8882d4176ed6ada1a78aba61a636