commit 8ac4536fbfe1bbcc6da753e3bea2944d0c937323
parent 43019c37a2a12147c401d75327e19e2ac383d6f4
Author: TheJackiMonster <thejackimonster@gmail.com>
Date: Mon, 14 Mar 2022 14:33:21 +0100
Added interface to record audio messages
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
Diffstat:
| M | resources/ui/chat.ui | | | 212 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------- |
| M | src/ui/chat.c | | | 210 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------ |
| M | src/ui/chat.h | | | 12 | ++++++++++++ |
3 files changed, 370 insertions(+), 64 deletions(-)
diff --git a/resources/ui/chat.ui b/resources/ui/chat.ui
@@ -311,69 +311,181 @@ Author: Tobias Frisch
<property name="border-width">4</property>
<property name="spacing">4</property>
<child>
- <object class="GtkButton" id="attach_file_button">
+ <object class="GtkStack" id="send_stack">
<property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can-focus">True</property>
- <property name="receives-default">True</property>
- <property name="valign">center</property>
- <property name="relief">none</property>
+ <property name="can-focus">False</property>
+ <property name="transition-type">slide-up</property>
<child>
- <object class="GtkImage">
+ <object class="GtkBox" id="send_text_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="icon-name">mail-attachment-symbolic</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkButton" id="attach_file_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</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">mail-attachment-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="GtkTextView" id="send_text_view">
+ <property name="width-request">210</property>
+ <property name="height-request">48</property>
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can-focus">True</property>
+ <property name="valign">end</property>
+ <property name="editable">False</property>
+ <property name="wrap-mode">word-char</property>
+ <property name="left-margin">8</property>
+ <property name="right-margin">8</property>
+ <property name="top-margin">8</property>
+ <property name="bottom-margin">8</property>
+ <property name="input-hints">GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_WORD_COMPLETION | GTK_INPUT_HINT_INHIBIT_OSK | GTK_INPUT_HINT_EMOJI | GTK_INPUT_HINT_NONE</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="emoji_button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</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">face-smile-symbolic</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">page_send_text</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkTextView" id="send_text_view">
- <property name="width-request">210</property>
- <property name="height-request">48</property>
- <property name="visible">True</property>
- <property name="sensitive">False</property>
- <property name="can-focus">True</property>
- <property name="valign">end</property>
- <property name="editable">False</property>
- <property name="wrap-mode">word-char</property>
- <property name="left-margin">8</property>
- <property name="right-margin">8</property>
- <property name="top-margin">8</property>
- <property name="bottom-margin">8</property>
- <property name="input-hints">GTK_INPUT_HINT_SPELLCHECK | GTK_INPUT_HINT_WORD_COMPLETION | GTK_INPUT_HINT_INHIBIT_OSK | GTK_INPUT_HINT_EMOJI | GTK_INPUT_HINT_NONE</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="emoji_button">
- <property name="visible">True</property>
- <property name="sensitive">False</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">
+ <object class="GtkBox" id="send_recording_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="icon-name">face-smile-symbolic</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkButton" id="recording_close_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">window-close-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="GtkButton" id="recording_play_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" id="play_pause_symbol">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">media-playback-start-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</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>
+ <property name="valign">center</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkLabel" id="recording_label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">00:00</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkProgressBar" id="recording_progress_bar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
</object>
+ <packing>
+ <property name="name">page_send_recording</property>
+ <property name="position">1</property>
+ </packing>
</child>
</object>
<packing>
- <property name="expand">False</property>
+ <property name="expand">True</property>
<property name="fill">True</property>
- <property name="position">2</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
@@ -395,7 +507,7 @@ Author: Tobias Frisch
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">3</property>
+ <property name="position">1</property>
</packing>
</child>
</object>
diff --git a/src/ui/chat.c b/src/ui/chat.c
@@ -328,11 +328,10 @@ close_dialog:
}
static void
-handle_send_text_buffer_changed(GtkTextBuffer *buffer,
- gpointer user_data)
+_update_send_record_symbol(GtkTextBuffer *buffer,
+ GtkImage *symbol,
+ gboolean picker_revealed)
{
- GtkImage *symbol = GTK_IMAGE(user_data);
-
GtkTextIter start, end;
gtk_text_buffer_get_start_iter(buffer, &start);
gtk_text_buffer_get_end_iter(buffer, &end);
@@ -341,13 +340,26 @@ handle_send_text_buffer_changed(GtkTextBuffer *buffer,
gtk_image_set_from_icon_name(
symbol,
- 0 < strlen(text)?
+ (0 < strlen(text)) || (picker_revealed)?
"mail-send-symbolic" :
"audio-input-microphone-symbolic",
GTK_ICON_SIZE_BUTTON
);
}
+static void
+handle_send_text_buffer_changed(GtkTextBuffer *buffer,
+ gpointer user_data)
+{
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+
+ _update_send_record_symbol(
+ buffer,
+ handle->send_record_symbol,
+ gtk_revealer_get_child_revealed(handle->picker_revealer)
+ );
+}
+
static gboolean
_send_text_from_view(MESSENGER_Application *app,
GtkTextView *text_view)
@@ -375,19 +387,112 @@ _send_text_from_view(MESSENGER_Application *app,
}
static void
+_drop_any_recording(UI_CHAT_Handle *handle)
+{
+ _update_send_record_symbol(
+ gtk_text_view_get_buffer(handle->send_text_view),
+ handle->send_record_symbol,
+ FALSE
+ );
+
+ gtk_stack_set_visible_child(handle->send_stack, handle->send_text_box);
+
+ handle->recorded = FALSE;
+}
+
+static void
handle_send_record_button_click(GtkButton *button,
gpointer user_data)
{
MESSENGER_Application *app = (MESSENGER_Application*) user_data;
- GtkTextView *text_view = GTK_TEXT_VIEW(
- g_object_get_qdata(G_OBJECT(button), app->quarks.widget)
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) (
+ g_object_get_qdata(G_OBJECT(button), app->quarks.ui)
);
- if (!_send_text_from_view(app, text_view))
+ if ((handle->recorded) &&
+ (!gtk_revealer_get_child_revealed(handle->picker_revealer)) &&
+ (gtk_stack_get_visible_child(handle->send_stack) ==
+ handle->send_recording_box))
{
- // TODO: record audio and attach as file?
+ // TODO: send audio as file!
+
+ _drop_any_recording(handle);
+ return;
}
+
+ GtkTextView *text_view = GTK_TEXT_VIEW(
+ g_object_get_qdata(G_OBJECT(button), app->quarks.widget)
+ );
+
+ _send_text_from_view(app, text_view);
+}
+
+static gboolean
+handle_send_record_button_pressed(GtkWidget *widget,
+ UNUSED GdkEvent *event,
+ gpointer user_data)
+{
+ MESSENGER_Application *app = (MESSENGER_Application*) user_data;
+
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) (
+ g_object_get_qdata(G_OBJECT(widget), app->quarks.ui)
+ );
+
+ if ((handle->recorded) ||
+ (gtk_revealer_get_child_revealed(handle->picker_revealer)) ||
+ (handle->send_text_box != gtk_stack_get_visible_child(handle->send_stack)))
+ return FALSE;
+
+ gtk_image_set_from_icon_name(
+ handle->play_pause_symbol,
+ "media-playback-start-symbolic",
+ GTK_ICON_SIZE_BUTTON
+ );
+
+ gtk_image_set_from_icon_name(
+ handle->send_record_symbol,
+ "media-record-symbolic",
+ GTK_ICON_SIZE_BUTTON
+ );
+
+ gtk_widget_set_sensitive(GTK_WIDGET(handle->recording_play_button), FALSE);
+
+ gtk_stack_set_visible_child(handle->send_stack, handle->send_recording_box);
+
+ return TRUE;
+}
+
+static gboolean
+handle_send_record_button_released(GtkWidget *widget,
+ UNUSED GdkEvent *event,
+ gpointer user_data)
+{
+ MESSENGER_Application *app = (MESSENGER_Application*) user_data;
+
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) (
+ g_object_get_qdata(G_OBJECT(widget), app->quarks.ui)
+ );
+
+ if ((handle->recorded) ||
+ (gtk_revealer_get_child_revealed(handle->picker_revealer)) ||
+ (handle->send_recording_box != gtk_stack_get_visible_child(
+ handle->send_stack)))
+ return FALSE;
+
+ gtk_widget_set_sensitive(GTK_WIDGET(handle->recording_play_button), TRUE);
+
+ gtk_revealer_set_reveal_child(handle->picker_revealer, FALSE);
+
+ handle->recorded = TRUE;
+
+ gtk_image_set_from_icon_name(
+ handle->send_record_symbol,
+ "mail-send-symbolic",
+ GTK_ICON_SIZE_BUTTON
+ );
+
+ return TRUE;
}
static gboolean
@@ -407,13 +512,29 @@ handle_send_text_key_press (GtkWidget *widget,
}
static void
+handle_recording_close_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+
+ _drop_any_recording(handle);
+}
+
+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);
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+
+ gboolean reveal = !gtk_revealer_get_child_revealed(handle->picker_revealer);
- gtk_revealer_set_reveal_child(revealer, reveal);
+ gtk_revealer_set_reveal_child(handle->picker_revealer, reveal);
+
+ _update_send_record_symbol(
+ gtk_text_view_get_buffer(handle->send_text_view),
+ handle->send_record_symbol,
+ reveal
+ );
}
UI_CHAT_Handle*
@@ -424,6 +545,8 @@ ui_chat_new(MESSENGER_Application *app)
UI_CHAT_Handle *handle = g_malloc(sizeof(UI_CHAT_Handle));
UI_MESSENGER_Handle *messenger = &(app->ui.messenger);
+ handle->recorded = FALSE;
+
handle->app = app;
handle->messages = NULL;
@@ -605,6 +728,18 @@ ui_chat_new(MESSENGER_Application *app)
handle
);
+ handle->send_stack = GTK_STACK(
+ gtk_builder_get_object(handle->builder, "send_stack")
+ );
+
+ handle->send_text_box = GTK_WIDGET(
+ gtk_builder_get_object(handle->builder, "send_text_box")
+ );
+
+ handle->send_recording_box = GTK_WIDGET(
+ gtk_builder_get_object(handle->builder, "send_recording_box")
+ );
+
handle->attach_file_button = GTK_BUTTON(
gtk_builder_get_object(handle->builder, "attach_file_button")
);
@@ -640,7 +775,7 @@ ui_chat_new(MESSENGER_Application *app)
send_text_buffer,
"changed",
G_CALLBACK(handle_send_text_buffer_changed),
- handle->send_record_symbol
+ handle
);
g_signal_connect(
@@ -651,6 +786,20 @@ ui_chat_new(MESSENGER_Application *app)
);
g_signal_connect(
+ handle->send_record_button,
+ "button-press-event",
+ G_CALLBACK(handle_send_record_button_pressed),
+ app
+ );
+
+ g_signal_connect(
+ handle->send_record_button,
+ "button-release-event",
+ G_CALLBACK(handle_send_record_button_released),
+ app
+ );
+
+ g_signal_connect(
handle->send_text_view,
"key-press-event",
G_CALLBACK(handle_send_text_key_press),
@@ -675,6 +824,39 @@ ui_chat_new(MESSENGER_Application *app)
handle->send_text_view
);
+ g_object_set_qdata(
+ G_OBJECT(handle->send_record_button),
+ app->quarks.ui,
+ handle
+ );
+
+ handle->recording_close_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "recording_close_button")
+ );
+
+ g_signal_connect(
+ handle->recording_close_button,
+ "clicked",
+ G_CALLBACK(handle_recording_close_button_click),
+ handle
+ );
+
+ handle->recording_play_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "recording_play_button")
+ );
+
+ handle->play_pause_symbol = GTK_IMAGE(
+ gtk_builder_get_object(handle->builder, "play_pause_symbol")
+ );
+
+ handle->recording_label = GTK_LABEL(
+ gtk_builder_get_object(handle->builder, "recording_label")
+ );
+
+ handle->recording_progress_bar = GTK_PROGRESS_BAR(
+ gtk_builder_get_object(handle->builder, "recording_progress_bar")
+ );
+
handle->picker_revealer = GTK_REVEALER(
gtk_builder_get_object(handle->builder, "picker_revealer")
);
@@ -690,7 +872,7 @@ ui_chat_new(MESSENGER_Application *app)
handle->emoji_button,
"clicked",
G_CALLBACK(handle_picker_button_click),
- handle->picker_revealer
+ handle
);
return handle;
diff --git a/src/ui/chat.h b/src/ui/chat.h
@@ -38,6 +38,8 @@ typedef struct UI_FILE_LOAD_ENTRY_Handle UI_FILE_LOAD_ENTRY_Handle;
typedef struct UI_CHAT_Handle
{
+ gboolean recorded;
+
MESSENGER_Application *app;
GList *messages;
@@ -79,12 +81,22 @@ typedef struct UI_CHAT_Handle
GtkListBox *chat_files_listbox;
GtkListBox *messages_listbox;
+ GtkStack *send_stack;
+ GtkWidget *send_text_box;
+ GtkWidget *send_recording_box;
+
GtkButton *attach_file_button;
GtkTextView *send_text_view;
GtkButton *emoji_button;
GtkButton *send_record_button;
GtkImage *send_record_symbol;
+ GtkButton *recording_close_button;
+ GtkButton *recording_play_button;
+ GtkImage *play_pause_symbol;
+ GtkLabel *recording_label;
+ GtkProgressBar *recording_progress_bar;
+
GtkRevealer *picker_revealer;
UI_PICKER_Handle *picker;