commit 056af2fb44379238609a2a28ede614ee3c5defed
parent 898ff5665c89266889cd1e9a85fad73a5415a1ba
Author: TheJackiMonster <thejackimonster@gmail.com>
Date: Mon, 21 Nov 2022 22:29:06 +0100
Add window to play media with fullscreen toggle
Signed-off-by: TheJackiMonster <thejackimonster@gmail.com>
Diffstat:
7 files changed, 675 insertions(+), 1 deletion(-)
diff --git a/resources/ui.gresource.xml b/resources/ui.gresource.xml
@@ -22,6 +22,7 @@
<file compressed="true">ui/new_platform.ui</file>
<file compressed="true">ui/new_account.ui</file>
<file compressed="true">ui/picker.ui</file>
+ <file compressed="true">ui/play_media.ui</file>
<file compressed="true">ui/account_entry.ui</file>
<file compressed="true">ui/send_file.ui</file>
<file compressed="true">ui/settings.ui</file>
diff --git a/resources/ui/play_media.ui b/resources/ui/play_media.ui
@@ -0,0 +1,288 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.40.0
+
+Copyright (C) 2022 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="HdyWindow" id="play_media_window">
+ <property name="width-request">250</property>
+ <property name="height-request">180</property>
+ <property name="can-focus">False</property>
+ <property name="modal">True</property>
+ <property name="window-position">center-on-parent</property>
+ <property name="type-hint">dialog</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkRevealer" id="header_revealer">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="reveal-child">True</property>
+ <child>
+ <object class="HdyWindowHandle">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="HdyHeaderBar" id="title_bar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="show-close-button">True</property>
+ <child>
+ <object class="GtkButton" id="back_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">go-previous-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </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="HdyFlap" id="controls_flap">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="flap-position">end</property>
+ <property name="modal">False</property>
+ <child type="content">
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">folder-videos-symbolic</property>
+ <property name="icon_size">6</property>
+ </object>
+ </child>
+ <child type="separator">
+ <object class="GtkSeparator">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ </object>
+ </child>
+ <child type="flap">
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">4</property>
+ <property name="spacing">8</property>
+ <child>
+ <object class="GtkButton" id="play_pause_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkStack" id="play_symbol_stack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">media-playback-start-symbolic</property>
+ </object>
+ <packing>
+ <property name="name">play_page</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">media-playback-pause-symbolic</property>
+ </object>
+ <packing>
+ <property name="name">pause_page</property>
+ <property name="position">1</property>
+ </packing>
+ </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="GtkVolumeButton" id="volume_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="focus-on-click">False</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ <property name="orientation">vertical</property>
+ <property name="icons">audio-volume-muted-symbolic
+audio-volume-high-symbolic
+audio-volume-low-symbolic
+audio-volume-medium-symbolic</property>
+ <child internal-child="plus_button">
+ <object class="GtkButton">
+ <property name="can-focus">False</property>
+ <property name="receives-default">False</property>
+ </object>
+ </child>
+ <child internal-child="minus_button">
+ <object class="GtkButton">
+ <property name="can-focus">False</property>
+ <property name="receives-default">False</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="GtkLabel" id="timeline_label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">0:00 / 0:00</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="fullscreen_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkStack" id="fullscreen_symbol_stack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">view-fullscreen-symbolic</property>
+ </object>
+ <packing>
+ <property name="name">scale_up_page</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">view-restore-symbolic</property>
+ </object>
+ <packing>
+ <property name="name">scale_down_page</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">3</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="relief">none</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">emblem-system-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">4</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkProgressBar" id="timeline_progress_bar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="margin-start">4</property>
+ <property name="margin-end">4</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/src/application.h b/src/application.h
@@ -42,6 +42,7 @@
#include "ui/new_group.h"
#include "ui/new_lobby.h"
#include "ui/new_platform.h"
+#include "ui/play_media.h"
#include "ui/send_file.h"
#include "ui/settings.h"
@@ -100,6 +101,7 @@ typedef struct MESSENGER_Application
UI_DELETE_MESSAGES_Handle delete_messages;
UI_INVITE_CONTACT_Handle invite_contact;
UI_SEND_FILE_Handle send_file;
+ UI_PLAY_MEDIA_Handle play_media;
UI_NEW_CONTACT_Handle new_contact;
UI_NEW_GROUP_Handle new_group;
diff --git a/src/ui/Makefile.am b/src/ui/Makefile.am
@@ -32,6 +32,7 @@ libui_a_SOURCES = \
new_lobby.c new_lobby.h \
new_platform.c new_platform.h \
picker.c picker.h \
+ play_media.c play_media.h \
send_file.c send_file.h \
settings.c settings.h
diff --git a/src/ui/picker.c b/src/ui/picker.c
@@ -95,8 +95,17 @@ handle_search_button_click(UNUSED GtkButton *button,
);
}
+static void
+handle_settings_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ MESSENGER_Application *app = (MESSENGER_Application*) user_data;
+ ui_play_media_window_init(app, &(app->ui.play_media));
+ gtk_widget_show(GTK_WIDGET(app->ui.play_media.window));
+}
+
UI_PICKER_Handle*
-ui_picker_new(UNUSED MESSENGER_Application *app,
+ui_picker_new(MESSENGER_Application *app,
UI_CHAT_Handle *chat)
{
UI_PICKER_Handle *handle = g_malloc(sizeof(UI_PICKER_Handle));
@@ -244,6 +253,13 @@ ui_picker_new(UNUSED MESSENGER_Application *app,
gtk_builder_get_object(handle->builder, "settings_button")
);
+ g_signal_connect(
+ handle->settings_button,
+ "clicked",
+ G_CALLBACK(handle_settings_button_click),
+ app
+ );
+
return handle;
}
diff --git a/src/ui/play_media.c b/src/ui/play_media.c
@@ -0,0 +1,287 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2022 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/play_media.c
+ */
+
+#include "play_media.h"
+
+#include "../application.h"
+#include "../ui.h"
+
+static void
+handle_back_button_click(GtkButton *button,
+ gpointer user_data)
+{
+ GtkWindow *window = GTK_WINDOW(user_data);
+ gtk_window_close(window);
+}
+
+static void
+_pause_playing_media(UI_PLAY_MEDIA_Handle *handle)
+{
+ //
+
+ handle->playing = FALSE;
+}
+
+static void
+_continue_playing_media(UI_PLAY_MEDIA_Handle *handle)
+{
+ //
+
+ handle->playing = TRUE;
+}
+
+static void
+handle_play_pause_button_click(GtkButton *button,
+ gpointer user_data)
+{
+ UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) user_data;
+
+ if (handle->playing)
+ _pause_playing_media(handle);
+ else
+ _continue_playing_media(handle);
+
+ gtk_stack_set_visible_child_name(
+ handle->play_symbol_stack,
+ handle->playing? "pause_page" : "play_page"
+ );
+}
+
+static void
+handle_fullscreen_button_click(GtkButton *button,
+ gpointer user_data)
+{
+ UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) user_data;
+
+ gtk_revealer_set_reveal_child(handle->header_revealer, handle->fullscreen);
+ hdy_flap_set_reveal_flap(handle->controls_flap, handle->fullscreen);
+
+ handle->fullscreen = !(handle->fullscreen);
+
+ if (!(handle->fullscreen))
+ gtk_window_unfullscreen(GTK_WINDOW(handle->window));
+
+ gtk_widget_hide(GTK_WIDGET(handle->window));
+
+ gtk_window_set_type_hint(
+ GTK_WINDOW(handle->window),
+ handle->fullscreen?
+ GDK_WINDOW_TYPE_HINT_NORMAL :
+ GDK_WINDOW_TYPE_HINT_DIALOG
+ );
+
+ gtk_window_set_modal(GTK_WINDOW(handle->window), !(handle->fullscreen));
+
+ gtk_window_set_position(
+ GTK_WINDOW(handle->window),
+ handle->fullscreen? GTK_WIN_POS_NONE : GTK_WIN_POS_CENTER_ON_PARENT
+ );
+
+ gtk_window_set_transient_for(
+ GTK_WINDOW(handle->window),
+ handle->fullscreen? NULL : handle->parent
+ );
+
+ gtk_widget_show_all(GTK_WIDGET(handle->window));
+
+ if (handle->fullscreen)
+ gtk_window_fullscreen(GTK_WINDOW(handle->window));
+
+ gtk_stack_set_visible_child_name(
+ handle->fullscreen_symbol_stack,
+ handle->fullscreen? "scale_down_page" : "scale_up_page"
+ );
+}
+
+static gboolean
+handle_media_motion_lost(gpointer user_data)
+{
+ UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) user_data;
+
+ if (!(hdy_flap_get_reveal_flap(handle->controls_flap)))
+ return FALSE;
+
+ hdy_flap_set_reveal_flap(handle->controls_flap, FALSE);
+ handle->motion_lost = 0;
+ return FALSE;
+}
+
+static gboolean
+handle_media_motion_notify(GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ UI_PLAY_MEDIA_Handle *handle = (UI_PLAY_MEDIA_Handle*) user_data;
+
+ if (hdy_flap_get_reveal_flap(handle->controls_flap))
+ return FALSE;
+
+ if (handle->motion_lost)
+ g_source_remove(handle->motion_lost);
+
+ hdy_flap_set_reveal_flap(handle->controls_flap, TRUE);
+ handle->motion_lost = g_timeout_add_seconds(
+ 3,
+ G_SOURCE_FUNC(handle_media_motion_lost),
+ handle
+ );
+
+ return FALSE;
+}
+
+static void
+handle_window_destroy(UNUSED GtkWidget *window,
+ gpointer user_data)
+{
+ ui_play_media_window_cleanup((UI_PLAY_MEDIA_Handle*) user_data);
+}
+
+void
+ui_play_media_window_init(MESSENGER_Application *app,
+ UI_PLAY_MEDIA_Handle *handle)
+{
+ GNUNET_assert((app) && (handle));
+
+ handle->parent = GTK_WINDOW(app->ui.messenger.main_window);
+
+ handle->builder = gtk_builder_new_from_resource(
+ application_get_resource_path(app, "ui/play_media.ui")
+ );
+
+ handle->window = HDY_WINDOW(
+ gtk_builder_get_object(handle->builder, "play_media_window")
+ );
+
+ gtk_window_set_position(
+ GTK_WINDOW(handle->window),
+ GTK_WIN_POS_CENTER_ON_PARENT
+ );
+
+ gtk_window_set_transient_for(
+ GTK_WINDOW(handle->window),
+ handle->parent
+ );
+
+ handle->header_revealer = GTK_REVEALER(
+ gtk_builder_get_object(handle->builder, "header_revealer")
+ );
+
+ handle->title_bar = HDY_HEADER_BAR(
+ gtk_builder_get_object(handle->builder, "title_bar")
+ );
+
+ hdy_header_bar_set_title(handle->title_bar, _("Play Media"));
+
+ handle->back_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "back_button")
+ );
+
+ g_signal_connect(
+ handle->back_button,
+ "clicked",
+ G_CALLBACK(handle_back_button_click),
+ handle->window
+ );
+
+ handle->controls_flap = HDY_FLAP(
+ gtk_builder_get_object(handle->builder, "controls_flap")
+ );
+
+ handle->play_pause_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "play_pause_button")
+ );
+
+ handle->play_symbol_stack = GTK_STACK(
+ gtk_builder_get_object(handle->builder, "play_symbol_stack")
+ );
+
+ g_signal_connect(
+ handle->play_pause_button,
+ "clicked",
+ G_CALLBACK(handle_play_pause_button_click),
+ handle
+ );
+
+ handle->volume_button = GTK_VOLUME_BUTTON(
+ gtk_builder_get_object(handle->builder, "volume_button")
+ );
+
+ handle->timeline_label = GTK_LABEL(
+ gtk_builder_get_object(handle->builder, "timeline_label")
+ );
+
+ handle->settings_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "settings_button")
+ );
+
+ handle->fullscreen_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "fullscreen_button")
+ );
+
+ handle->fullscreen_symbol_stack = GTK_STACK(
+ gtk_builder_get_object(handle->builder, "fullscreen_symbol_stack")
+ );
+
+ g_signal_connect(
+ handle->fullscreen_button,
+ "clicked",
+ G_CALLBACK(handle_fullscreen_button_click),
+ handle
+ );
+
+ g_signal_connect(
+ handle->window,
+ "motion-notify-event",
+ G_CALLBACK(handle_media_motion_notify),
+ handle
+ );
+
+ gtk_widget_add_events(
+ GTK_WIDGET(handle->window),
+ GDK_POINTER_MOTION_HINT_MASK |
+ GDK_POINTER_MOTION_MASK
+ );
+
+ g_signal_connect(
+ handle->window,
+ "destroy",
+ G_CALLBACK(handle_window_destroy),
+ handle
+ );
+
+ gtk_widget_show_all(GTK_WIDGET(handle->window));
+}
+
+void
+ui_play_media_window_cleanup(UI_PLAY_MEDIA_Handle *handle)
+{
+ GNUNET_assert(handle);
+
+ g_object_unref(handle->builder);
+
+ if (handle->motion_lost)
+ g_source_remove(handle->motion_lost);
+
+ memset(handle, 0, sizeof(*handle));
+}
diff --git a/src/ui/play_media.h b/src/ui/play_media.h
@@ -0,0 +1,79 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2022 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/play_media.h
+ */
+
+#ifndef UI_PLAY_MEDIA_H_
+#define UI_PLAY_MEDIA_H_
+
+#include "messenger.h"
+
+typedef struct UI_PLAY_MEDIA_Handle
+{
+ gboolean playing;
+ gboolean fullscreen;
+
+ GtkWindow *parent;
+
+ GtkBuilder *builder;
+ HdyWindow *window;
+
+ GtkRevealer *header_revealer;
+ HdyHeaderBar *title_bar;
+ GtkButton *back_button;
+
+ HdyFlap *controls_flap;
+ GtkButton *play_pause_button;
+ GtkStack *play_symbol_stack;
+
+ GtkVolumeButton *volume_button;
+ GtkLabel *timeline_label;
+
+ GtkButton *settings_button;
+
+ GtkButton *fullscreen_button;
+ GtkStack *fullscreen_symbol_stack;
+
+ guint motion_lost;
+} UI_PLAY_MEDIA_Handle;
+
+/**
+ * Initializes a handle for the play media window
+ * of a given messenger application.
+ *
+ * @param app Messenger application
+ * @param handle Play media window handle
+ */
+void
+ui_play_media_window_init(MESSENGER_Application *app,
+ UI_PLAY_MEDIA_Handle *handle);
+
+/**
+ * Cleans up the allocated resources and resets the
+ * state of a given play media window handle.
+ *
+ * @param handle Play media window handle
+ */
+void
+ui_play_media_window_cleanup(UI_PLAY_MEDIA_Handle *handle);
+
+#endif /* UI_PLAY_MEDIA_H_ */