commit 95cbc8879703414f3bdecb12cf3df141b1ef728a
parent 4278733835274953112551f8b311892965c50a4c
Author: Jacki <jacki@thejackimonster.de>
Date: Sat, 11 May 2024 04:05:44 +0200
Use CSD design with header bars in leaflet
Signed-off-by: Jacki <jacki@thejackimonster.de>
Diffstat:
17 files changed, 2279 insertions(+), 990 deletions(-)
diff --git a/resources/ui.gresource.xml b/resources/ui.gresource.xml
@@ -4,6 +4,7 @@
<file compressed="true">ui/about.ui</file>
<file compressed="true">ui/accounts.ui</file>
<file compressed="true">ui/chat_entry.ui</file>
+ <file compressed="true">ui/chat_title.ui</file>
<file compressed="true">ui/chat.ui</file>
<file compressed="true">ui/contact_entry.ui</file>
<file compressed="true">ui/contact_info.ui</file>
diff --git a/resources/ui/#messenger.ui# b/resources/ui/#messenger.ui#
@@ -0,0 +1,978 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.40.0
+
+Copyright (C) 2021‑‑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="GtkApplicationWindow" id="main_window">
+ <property name="can-focus">False</property>
+ <property name="icon-name">org.gnunet.Messenger</property>
+ <property name="startup-id">org.gnunet.Messenger</property>
+ <property name="show-menubar">False</property>
+ <child>
+ <object class="HdyLeaflet" id="leaflet_chat">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hhomogeneous-folded">False</property>
+ <property name="vhomogeneous-folded">False</property>
+ <property name="can-swipe-back">True</property>
+ <child>
+ <object class="GtkBox" id="nav_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="HdyFlap" id="flap_user_details">
+ <property name="width-request">300</property>
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="reveal-flap">False</property>
+ <property name="fold-policy">always</property>
+ <child type="content">
+ <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="shadow-type">in</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkListBox" id="chats_listbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </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="width-request">240</property>
+ <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="border-width">16</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">16</property>
+ <child>
+ <object class="GtkButton" id="profile_button">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="receives-default">True</property>
+ <property name="halign">start</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="HdyAvatar" id="profile_avatar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="size">64</property>
+ </object>
+ </child>
+ <style>
+ <class name="profile-button"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">2</property>
+ <child>
+ <object class="GtkLabel" id="profile_label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="ellipsize">end</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="profile_key_label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="ellipsize">end</property>
+ <property name="max-width-chars">30</property>
+ <property name="xalign">0</property>
+ <style>
+ <class name="profile-key"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </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">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">8</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">8</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkButton" id="hide_user_details_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">go-previous-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="lobby_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="halign">center</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">dialog-password-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="account_details_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkImage" id="account_details_symbol">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">go-down-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</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>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="shadow-type">none</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="account_details_revealer">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="height-request">250</property>
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkListBox" id="accounts_listbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkListBoxRow" id="add_account_listbox_row">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="selectable">False</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">8</property>
+ <child>
+ <object class="GtkImage">
+ <property name="width-request">36</property>
+ <property name="height-request">36</property>
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">list-add-symbolic</property>
+ <property name="icon_size">3</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">Add Account</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <style>
+ <class name="account-entry"/>
+ </style>
+ </object>
+ </child>
+ </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="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkButton" id="new_contact_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</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">16</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">contact-new-symbolic</property>
+ <property name="icon_size">3</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="new-contact-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">New Contact</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</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="GtkButton" id="new_group_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</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">16</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">system-users-symbolic</property>
+ <property name="icon_size">3</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="new-group-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">New Group</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</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">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="new_platform_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</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">16</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">network-wired-symbolic</property>
+ <property name="icon_size">3</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="new-platform-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">New Platform</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</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">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="contacts_button">
+ <property name="visible">True</property>
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ <property name="always-show-image">True</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">16</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">avatar-default-symbolic</property>
+ <property name="icon_size">3</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="contacts-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">Contacts</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</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">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>
+ <property name="always-show-image">True</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">16</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">emblem-system-symbolic</property>
+ <property name="icon_size">3</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="settings-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">Settings</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</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">4</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="about_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="GtkBox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="border-width">4</property>
+ <property name="spacing">16</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">help-about-symbolic</property>
+ <property name="icon_size">3</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="about-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">About</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</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">5</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>
+ <property name="border-width">16</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="application-name-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="application-version-label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">start</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">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <style>
+ <class name="flap-background"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">nav</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="main_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkStack" id="chats_stack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkBox" id="no_chat_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="label" translatable="yes">Select a chat to start messaging...</property>
+ <style>
+ <class name="message-box"/>
+ <class name="status"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</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">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">main</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="titlebar">
+ <object class="HdyTitleBar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="HdyLeaflet" id="leaflet_title">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hhomogeneous-folded">False</property>
+ <property name="vhomogeneous-folded">False</property>
+ <child>
+ <object class="GtkHeaderBar" id="nav_bar">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">4</property>
+ <child type="title">
+ <object class="GtkStack" id="chats_title_stack">
+ <property name="width-request">204</property>
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="transition-type">slide-down</property>
+ <child>
+ <object class="GtkBox" id="title_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">GNUnet Messenger</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <style>
+ <class name="header-box"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">title_page</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="search_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkSearchEntry" id="chats_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>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <style>
+ <class name="header-box"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">search_page</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="user_details_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">open-menu-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="chats_search_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="search_icon_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">edit-find-symbolic</property>
+ </object>
+ <packing>
+ <property name="name">title_page</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">window-close-symbolic</property>
+ </object>
+ <packing>
+ <property name="name">search_page</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">nav</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHeaderBar" id="main_bar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">0</property>
+ <child type="title">
+ <object class="GtkStack" id="chat_title_stack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="transition-type">slide-down</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">main</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <object class="GtkSizeGroup">
+ <property name="mode">vertical</property>
+ <widgets>
+ <widget name="nav_bar"/>
+ <widget name="main_bar"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup">
+ <property name="mode">vertical</property>
+ <widgets>
+ <widget name="nav_box"/>
+ <widget name="main_box"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup">
+ <widgets>
+ <widget name="new-contact-label"/>
+ <widget name="new-group-label"/>
+ <widget name="new-platform-label"/>
+ <widget name="contacts-label"/>
+ <widget name="settings-label"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup">
+ <widgets>
+ <widget name="nav_box"/>
+ <widget name="nav_bar"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup">
+ <widgets>
+ <widget name="main_box"/>
+ <widget name="main_bar"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/resources/ui/chat.ui b/resources/ui/chat.ui
@@ -40,268 +40,6 @@ Author: Tobias Frisch
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
- <object class="GtkStack" id="chat_title_stack">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="transition-type">slide-down</property>
- <child>
- <object class="GtkBox" id="title_box">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="border-width">8</property>
- <property name="spacing">8</property>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="margin-start">4</property>
- <property name="margin-end">4</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel" id="chat_title">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="ellipsize">end</property>
- <property name="single-line-mode">True</property>
- <property name="xalign">0</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="chat_subtitle">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="ellipsize">end</property>
- <property name="single-line-mode">True</property>
- <property name="xalign">0</property>
- <attributes>
- <attribute name="weight" value="light"/>
- </attributes>
- <style>
- <class name="header-subtitle"/>
- </style>
- </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">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="back_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">go-previous-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="chat_details_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">view-more-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">0</property>
- </packing>
- </child>
- <child>
- <object class="HdyAvatar" id="chat_avatar">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="size">32</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="chat_search_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">edit-find-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>
- <child>
- <object class="GtkButton" id="chat_load_button">
- <property name="can-focus">True</property>
- <property name="receives-default">True</property>
- <property name="relief">none</property>
- <child>
- <object class="GtkSpinner">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="active">True</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>
- <style>
- <class name="header-box"/>
- </style>
- </object>
- <packing>
- <property name="name">page_title</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="selection_box">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="border-width">8</property>
- <property name="spacing">8</property>
- <child>
- <object class="GtkButton" id="selection_close_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">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="GtkLabel" id="selection_count_label">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <attributes>
- <attribute name="weight" value="semibold"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="selection_delete_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">user-trash-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>
- <child>
- <object class="GtkButton" id="selection_tag_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">bookmark-new-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">3</property>
- </packing>
- </child>
- <style>
- <class name="header-box"/>
- </style>
- </object>
- <packing>
- <property name="name">page_selection</property>
- <property name="position">1</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="HdySearchBar" id="chat_search_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
@@ -1144,18 +882,6 @@ Author: Tobias Frisch
</packing>
</child>
</object>
- <object class="GtkPopover" id="chat_load_popover">
- <property name="can-focus">False</property>
- <property name="relative-to">chat_load_button</property>
- <property name="position">bottom</property>
- <child>
- <object class="GtkListBox" id="chat_load_listbox">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="selection-mode">none</property>
- </object>
- </child>
- </object>
<object class="GtkPopover" id="send_popover">
<property name="can-focus">False</property>
<property name="relative-to">send_record_button</property>
diff --git a/resources/ui/chat_title.ui b/resources/ui/chat_title.ui
@@ -0,0 +1,306 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.40.0
+
+Copyright (C) 2024 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="chat_title_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <child>
+ <object class="GtkStack" id="chat_title_stack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="transition-type">slide-down</property>
+ <child>
+ <object class="GtkBox" id="title_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">8</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>
+ <property name="relief">none</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>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="HdyAvatar" id="chat_avatar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="size">32</property>
+ </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="border-width">4</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="chat_subtitle">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="ellipsize">end</property>
+ <property name="single-line-mode">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="light"/>
+ </attributes>
+ <style>
+ <class name="header-subtitle"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="chat_title">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="ellipsize">end</property>
+ <property name="single-line-mode">True</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </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>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="chat_details_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">view-more-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">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="chat_search_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">edit-find-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>
+ <child>
+ <object class="GtkButton" id="chat_load_button">
+ <property name="can-focus">True</property>
+ <property name="receives-default">True</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkSpinner">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="active">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack-type">end</property>
+ <property name="position">5</property>
+ </packing>
+ </child>
+ <style>
+ <class name="header-box"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">title_page</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="selection_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">8</property>
+ <child>
+ <object class="GtkButton" id="selection_close_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">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="GtkLabel" id="selection_count_label">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <attributes>
+ <attribute name="weight" value="semibold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="selection_delete_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">user-trash-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>
+ <child>
+ <object class="GtkButton" id="selection_tag_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">bookmark-new-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">3</property>
+ </packing>
+ </child>
+ <style>
+ <class name="header-box"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">selection_page</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <style>
+ <class name="header-box"/>
+ </style>
+ </object>
+ <object class="GtkPopover" id="chat_load_popover">
+ <property name="can-focus">False</property>
+ <property name="relative-to">chat_load_button</property>
+ <property name="position">bottom</property>
+ <child>
+ <object class="GtkListBox" id="chat_load_listbox">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="selection-mode">none</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/resources/ui/messenger.ui b/resources/ui/messenger.ui
@@ -27,6 +27,7 @@ Author: Tobias Frisch
<property name="can-focus">False</property>
<property name="icon-name">org.gnunet.Messenger</property>
<property name="startup-id">org.gnunet.Messenger</property>
+ <property name="show-menubar">False</property>
<child>
<object class="HdyLeaflet" id="leaflet_chat">
<property name="visible">True</property>
@@ -35,7 +36,7 @@ Author: Tobias Frisch
<property name="vhomogeneous-folded">False</property>
<property name="can-swipe-back">True</property>
<child>
- <object class="GtkBox">
+ <object class="GtkBox" id="nav_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
@@ -52,139 +53,6 @@ Author: Tobias Frisch
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
- <object class="GtkStack" id="chats_title_stack">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="transition-type">slide-down</property>
- <child>
- <object class="GtkBox" id="title_box">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="border-width">8</property>
- <property name="spacing">8</property>
- <child>
- <object class="GtkButton" id="user_details_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">open-menu-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="GtkLabel">
- <property name="width-request">200</property>
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="label" translatable="yes">GNUnet Messenger</property>
- <property name="xalign">0</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="chats_search_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">edit-find-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="header-box"/>
- </style>
- </object>
- <packing>
- <property name="name">title_page</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="search_box">
- <property name="visible">True</property>
- <property name="can-focus">False</property>
- <property name="border-width">8</property>
- <property name="spacing">8</property>
- <child>
- <object class="GtkSearchEntry" id="chats_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>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="chats_search_end_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">window-close-symbolic</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- <style>
- <class name="header-box"/>
- </style>
- </object>
- <packing>
- <property name="name">search_page</property>
- <property name="position">1</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="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
@@ -206,7 +74,7 @@ Author: Tobias Frisch
<property name="expand">True</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
- <property name="position">2</property>
+ <property name="position">0</property>
</packing>
</child>
</object>
@@ -395,7 +263,7 @@ Author: Tobias Frisch
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">1</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
@@ -775,7 +643,7 @@ Author: Tobias Frisch
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">6</property>
+ <property name="position">5</property>
</packing>
</child>
</object>
@@ -834,7 +702,7 @@ Author: Tobias Frisch
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
- <property name="position">2</property>
+ <property name="position">1</property>
</packing>
</child>
<style>
@@ -846,14 +714,17 @@ Author: Tobias Frisch
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
+ <property name="pack-type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
+ <packing>
+ <property name="name">nav</property>
+ </packing>
</child>
<child>
- <object class="GtkBox">
- <property name="name">chats-box</property>
+ <object class="GtkBox" id="main_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
@@ -891,25 +762,198 @@ Author: Tobias Frisch
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
+ <property name="pack-type">end</property>
<property name="position">0</property>
</packing>
</child>
</object>
+ <packing>
+ <property name="name">main</property>
+ </packing>
</child>
</object>
</child>
<child type="titlebar">
- <object class="HdyHeaderBar" id="title_bar">
+ <object class="HdyTitleBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
- <property name="title" translatable="yes">Messenger</property>
- <property name="subtitle" translatable="yes">GNUnet</property>
- <property name="show-close-button">True</property>
- <property name="interpolate-size">True</property>
+ <child>
+ <object class="HdyLeaflet" id="leaflet_title">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hhomogeneous-folded">False</property>
+ <property name="vhomogeneous-folded">False</property>
+ <child>
+ <object class="GtkHeaderBar" id="nav_bar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="spacing">4</property>
+ <child type="title">
+ <object class="GtkStack" id="chats_title_stack">
+ <property name="width-request">204</property>
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="transition-type">slide-down</property>
+ <child>
+ <object class="GtkBox" id="title_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="label" translatable="yes">GNUnet Messenger</property>
+ <property name="xalign">0</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <style>
+ <class name="header-box"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">title_page</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="search_box">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <child>
+ <object class="GtkSearchEntry" id="chats_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>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <style>
+ <class name="header-box"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">search_page</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="user_details_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">open-menu-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="chats_search_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="search_icon_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">edit-find-symbolic</property>
+ </object>
+ <packing>
+ <property name="name">title_page</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="icon-name">window-close-symbolic</property>
+ </object>
+ <packing>
+ <property name="name">search_page</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">nav</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHeaderBar" id="main_bar">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">0</property>
+ <child type="title">
+ <object class="GtkStack" id="chat_title_stack">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="transition-type">slide-down</property>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">main</property>
+ </packing>
+ </child>
+ </object>
+ </child>
</object>
</child>
</object>
<object class="GtkSizeGroup">
+ <property name="mode">vertical</property>
+ <widgets>
+ <widget name="nav_bar"/>
+ <widget name="main_bar"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup">
+ <property name="mode">vertical</property>
+ <widgets>
+ <widget name="nav_box"/>
+ <widget name="main_box"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup">
<widgets>
<widget name="new-contact-label"/>
<widget name="new-group-label"/>
@@ -918,4 +962,16 @@ Author: Tobias Frisch
<widget name="settings-label"/>
</widgets>
</object>
+ <object class="GtkSizeGroup">
+ <widgets>
+ <widget name="nav_box"/>
+ <widget name="nav_bar"/>
+ </widgets>
+ </object>
+ <object class="GtkSizeGroup">
+ <widgets>
+ <widget name="main_box"/>
+ <widget name="main_bar"/>
+ </widgets>
+ </object>
</interface>
diff --git a/src/event.c b/src/event.c
@@ -31,7 +31,9 @@
#include "ui.h"
#include "ui/chat_entry.h"
+#include "ui/chat_title.h"
#include "ui/message.h"
+
#include <gnunet/gnunet_chat_lib.h>
#include <gnunet/gnunet_common.h>
@@ -270,6 +272,11 @@ _add_new_chat_entry(MESSENGER_Application *app,
entry->chat->chat_box
);
+ gtk_container_add(
+ GTK_CONTAINER(ui->chat_title_stack),
+ entry->chat->title->chat_title_box
+ );
+
ui->chat_entries = g_list_append(ui->chat_entries, entry);
GtkWidget *row = gtk_widget_get_parent(entry->entry_box);
diff --git a/src/ui/chat.c b/src/ui/chat.c
@@ -31,6 +31,7 @@
#include <stdlib.h>
#include "chat_entry.h"
+#include "chat_title.h"
#include "file_entry.h"
#include "file_load_entry.h"
#include "media_preview.h"
@@ -38,10 +39,8 @@
#include "messenger.h"
#include "picker.h"
#include "account_entry.h"
-#include "delete_messages.h"
#include "../application.h"
-#include "../contact.h"
#include "../file.h"
#include "../ui.h"
@@ -79,20 +78,6 @@ handle_chat_details_via_button_click(UNUSED GtkButton* button,
}
static void
-handle_popover_via_button_click(UNUSED GtkButton *button,
- gpointer user_data)
-{
- g_assert(user_data);
-
- GtkPopover *popover = GTK_POPOVER(user_data);
-
- if (gtk_widget_is_visible(GTK_WIDGET(popover)))
- gtk_popover_popdown(popover);
- else
- gtk_popover_popup(popover);
-}
-
-static void
handle_chat_contacts_listbox_row_activated(GtkListBox *listbox,
GtkListBoxRow *row,
gpointer user_data)
@@ -164,22 +149,6 @@ handle_chat_messages_listbox_size_allocate(UNUSED GtkWidget *widget,
}
static void
-handle_back_button_click(UNUSED GtkButton *button,
- gpointer user_data)
-{
- g_assert(user_data);
-
- HdyLeaflet *leaflet = HDY_LEAFLET(user_data);
-
- GList *children = gtk_container_get_children(GTK_CONTAINER(leaflet));
-
- if (children) {
- hdy_leaflet_set_visible_child(leaflet, GTK_WIDGET(children->data));
- g_list_free(children);
- }
-}
-
-static void
handle_reveal_identity_button_click(GtkButton *button,
gpointer user_data)
{
@@ -406,7 +375,7 @@ handle_chat_messages_selected_rows_changed(GtkListBox *listbox,
{
g_assert((listbox) && (user_data));
- UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+ UI_CHAT_TITLE_Handle *handle = (UI_CHAT_TITLE_Handle*) user_data;
GList *selected = gtk_list_box_get_selected_rows(listbox);
uint32_t count = 0;
@@ -435,154 +404,6 @@ handle_chat_messages_selected_rows_changed(GtkListBox *listbox,
}
static void
-handle_chat_selection_close_button_click(UNUSED GtkButton *button,
- gpointer user_data)
-{
- g_assert(user_data);
-
- GtkListBox *listbox = GTK_LIST_BOX(user_data);
-
- gtk_list_box_unselect_all(listbox);
-}
-
-void
-_new_tag_callback(MESSENGER_Application *app,
- GList *selected,
- const char *tag,
- gpointer user_data)
-{
- g_assert((app) && (user_data));
-
- UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
- UI_MESSAGE_Handle *message;
-
- if ((!(handle->context)) || (!tag))
- goto unselect;
-
- while (selected)
- {
- GtkListBoxRow *row = GTK_LIST_BOX_ROW(selected->data);
-
- if (!row)
- goto skip_row;
-
- message = (UI_MESSAGE_Handle*) g_object_get_qdata(
- G_OBJECT(row),
- app->quarks.ui
- );
-
- if ((!message) || (!(message->msg)))
- goto skip_row;
-
- GNUNET_CHAT_context_send_tag(
- handle->context,
- message->msg,
- tag
- );
-
- skip_row:
- selected = selected->next;
- }
-
-unselect:
- gtk_list_box_unselect_all(handle->messages_listbox);
-}
-
-static void
-handle_chat_selection_tag_button_click(UNUSED GtkButton *button,
- gpointer user_data)
-{
- g_assert(user_data);
-
- UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
-
- MESSENGER_Application *app = handle->app;
-
- GList *selected = gtk_list_box_get_selected_rows(handle->messages_listbox);
-
- ui_new_tag_dialog_init(app, &(app->ui.new_tag));
-
- ui_new_tag_dialog_link(
- &(app->ui.new_tag),
- _new_tag_callback,
- selected,
- handle
- );
-
- gtk_widget_show(GTK_WIDGET(app->ui.new_tag.dialog));
-}
-
-void
-_delete_messages_callback(MESSENGER_Application *app,
- GList *selected,
- gulong delay)
-{
- g_assert(app);
-
- UI_MESSAGE_Handle *message;
-
- while (selected)
- {
- GtkListBoxRow *row = GTK_LIST_BOX_ROW(selected->data);
-
- if (!row)
- goto skip_row;
-
- message = (UI_MESSAGE_Handle*) g_object_get_qdata(
- G_OBJECT(row),
- app->quarks.ui
- );
-
- if ((!message) || (!(message->msg)))
- goto skip_row;
-
- GNUNET_CHAT_message_delete(
- message->msg,
- GNUNET_TIME_relative_multiply(
- GNUNET_TIME_relative_get_second_(),
- delay
- )
- );
-
- skip_row:
- selected = selected->next;
- }
-}
-
-static void
-handle_chat_selection_delete_button_click(UNUSED GtkButton *button,
- gpointer user_data)
-{
- g_assert(user_data);
-
- UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
-
- MESSENGER_Application *app = handle->app;
-
- GList *selected = gtk_list_box_get_selected_rows(handle->messages_listbox);
-
- if (app->settings.hide_delete_dialog)
- {
- _delete_messages_callback(app, selected, 0);
-
- if (selected)
- g_list_free(selected);
- }
- else
- {
- ui_delete_messages_dialog_init(app, &(app->ui.delete_messages));
-
- ui_delete_messages_dialog_link(
- &(app->ui.delete_messages),
- _delete_messages_callback,
- selected
- );
-
- gtk_widget_show(GTK_WIDGET(app->ui.delete_messages.dialog));
- }
-}
-
-static void
handle_attach_file_button_click(GtkButton *button,
gpointer user_data)
{
@@ -753,8 +574,8 @@ handle_sending_recording_upload_file(UNUSED void *cls,
file_update_upload_info(file, completed, size);
- if ((completed >= size) && (file_load->chat))
- ui_chat_remove_file_load(file_load->chat, file_load);
+ if ((completed >= size) && (file_load->chat_title))
+ ui_chat_title_remove_file_load(file_load->chat_title, file_load);
}
static void
@@ -789,7 +610,7 @@ handle_send_record_button_click(GtkButton *button,
{
file_create_info(file);
- ui_chat_add_file_load(handle, file_load);
+ ui_chat_title_add_file_load(handle->title, file_load);
}
else if (file_load)
ui_file_load_entry_delete(file_load);
@@ -1104,20 +925,6 @@ handle_recording_play_button_click(UNUSED GtkButton *button,
}
static void
-handle_search_button_click(UNUSED GtkButton *button,
- gpointer user_data)
-{
- g_assert(user_data);
-
- HdySearchBar *search_bar = HDY_SEARCH_BAR(user_data);
-
- hdy_search_bar_set_search_mode(
- search_bar,
- !hdy_search_bar_get_search_mode(search_bar)
- );
-}
-
-static void
handle_search_entry_search_changed(UNUSED GtkSearchEntry* search_entry,
gpointer user_data)
{
@@ -1323,10 +1130,9 @@ UI_CHAT_Handle*
ui_chat_new(MESSENGER_Application *app,
struct GNUNET_CHAT_Context *context)
{
- g_assert(app);
+ g_assert((app) && (context));
UI_CHAT_Handle *handle = g_malloc(sizeof(UI_CHAT_Handle));
- UI_MESSENGER_Handle *messenger = &(app->ui.messenger);
memset(handle, 0, sizeof(*handle));
@@ -1335,7 +1141,7 @@ ui_chat_new(MESSENGER_Application *app,
handle->app = app;
handle->context = context;
- handle->loads = NULL;
+ handle->title = ui_chat_title_new(handle->app, handle);
handle->builder = ui_builder_from_resource(
application_get_resource_path(app, "ui/chat.ui")
@@ -1345,76 +1151,10 @@ ui_chat_new(MESSENGER_Application *app,
gtk_builder_get_object(handle->builder, "chat_box")
);
- handle->back_button = GTK_BUTTON(
- gtk_builder_get_object(handle->builder, "back_button")
- );
-
- g_object_bind_property(
- messenger->leaflet_chat,
- "folded",
- handle->back_button,
- "visible",
- G_BINDING_SYNC_CREATE
- );
-
- g_signal_connect(
- handle->back_button,
- "clicked",
- G_CALLBACK(handle_back_button_click),
- messenger->leaflet_chat
- );
-
handle->flap_chat_details = HDY_FLAP(
gtk_builder_get_object(handle->builder, "flap_chat_details")
);
- handle->chat_title_stack = GTK_STACK(
- gtk_builder_get_object(handle->builder, "chat_title_stack")
- );
-
- handle->title_box = GTK_WIDGET(
- gtk_builder_get_object(handle->builder, "title_box")
- );
-
- handle->selection_box = GTK_WIDGET(
- gtk_builder_get_object(handle->builder, "selection_box")
- );
-
- handle->chat_avatar = HDY_AVATAR(
- gtk_builder_get_object(handle->builder, "chat_avatar")
- );
-
- handle->chat_title = GTK_LABEL(
- gtk_builder_get_object(handle->builder, "chat_title")
- );
-
- handle->chat_subtitle = GTK_LABEL(
- gtk_builder_get_object(handle->builder, "chat_subtitle")
- );
-
- handle->chat_load_button = GTK_BUTTON(
- gtk_builder_get_object(handle->builder, "chat_load_button")
- );
-
- handle->chat_load_popover = GTK_POPOVER(
- gtk_builder_get_object(handle->builder, "chat_load_popover")
- );
-
- handle->chat_load_listbox = GTK_LIST_BOX(
- gtk_builder_get_object(handle->builder, "chat_load_listbox")
- );
-
- g_signal_connect(
- handle->chat_load_button,
- "clicked",
- G_CALLBACK(handle_popover_via_button_click),
- handle->chat_load_popover
- );
-
- handle->chat_search_button = GTK_BUTTON(
- gtk_builder_get_object(handle->builder, "chat_search_button")
- );
-
handle->chat_search_bar = HDY_SEARCH_BAR(
gtk_builder_get_object(handle->builder, "chat_search_bar")
);
@@ -1423,24 +1163,6 @@ ui_chat_new(MESSENGER_Application *app,
gtk_builder_get_object(handle->builder, "chat_search_entry")
);
- g_signal_connect(
- handle->chat_search_button,
- "clicked",
- G_CALLBACK(handle_search_button_click),
- handle->chat_search_bar
- );
-
- handle->chat_details_button = GTK_BUTTON(
- gtk_builder_get_object(handle->builder, "chat_details_button")
- );
-
- g_signal_connect(
- handle->chat_details_button,
- "clicked",
- G_CALLBACK(handle_chat_details_via_button_click),
- handle
- );
-
handle->chat_details_label = GTK_LABEL(
gtk_builder_get_object(handle->builder, "chat_details_label")
);
@@ -1524,22 +1246,6 @@ ui_chat_new(MESSENGER_Application *app,
gtk_builder_get_object(handle->builder, "chat_notifications_switch")
);
- handle->selection_close_button = GTK_BUTTON(
- gtk_builder_get_object(handle->builder, "selection_close_button")
- );
-
- handle->selection_count_label = GTK_LABEL(
- gtk_builder_get_object(handle->builder, "selection_count_label")
- );
-
- handle->selection_tag_button = GTK_BUTTON(
- gtk_builder_get_object(handle->builder, "selection_tag_button")
- );
-
- handle->selection_delete_button = GTK_BUTTON(
- gtk_builder_get_object(handle->builder, "selection_delete_button")
- );
-
handle->chat_scrolled_window = GTK_SCROLLED_WINDOW(
gtk_builder_get_object(handle->builder, "chat_scrolled_window")
);
@@ -1592,28 +1298,7 @@ ui_chat_new(MESSENGER_Application *app,
handle->messages_listbox,
"selected-rows-changed",
G_CALLBACK(handle_chat_messages_selected_rows_changed),
- handle
- );
-
- g_signal_connect(
- handle->selection_close_button,
- "clicked",
- G_CALLBACK(handle_chat_selection_close_button_click),
- handle->messages_listbox
- );
-
- g_signal_connect(
- handle->selection_tag_button,
- "clicked",
- G_CALLBACK(handle_chat_selection_tag_button_click),
- handle
- );
-
- g_signal_connect(
- handle->selection_delete_button,
- "clicked",
- G_CALLBACK(handle_chat_selection_delete_button_click),
- handle
+ handle->title
);
g_signal_connect(
@@ -2069,41 +1754,40 @@ _chat_update_media(UI_CHAT_Handle *handle,
);
}
-static void
-_chat_update_contact(UI_CHAT_Handle *handle,
- MESSENGER_Application *app,
- struct GNUNET_CHAT_Contact* contact)
+static const gchar*
+_chat_get_default_subtitle(UI_CHAT_Handle *handle,
+ MESSENGER_Application *app,
+ struct GNUNET_CHAT_Group* group)
{
g_assert((handle) && (app));
- struct GNUNET_CHAT_Contact *prev = g_object_get_qdata(
- G_OBJECT(handle->chat_avatar),
- app->quarks.data
+ GList *rows = gtk_container_get_children(
+ GTK_CONTAINER(handle->messages_listbox)
);
- if (prev)
- {
- contact_remove_name_label_from_info(contact, handle->chat_title);
- contact_remove_name_avatar_from_info(contact, handle->chat_avatar);
+ if (!rows)
+ return NULL;
- contact_remove_name_label_from_info(contact, handle->chat_details_label);
- contact_remove_name_avatar_from_info(contact, handle->chat_details_avatar);
- }
-
- if (contact)
+ UI_MESSAGE_Handle *last_message = NULL;
+ for (GList *row = rows; row; row = row->next)
{
- contact_add_name_label_to_info(contact, handle->chat_title);
- contact_add_name_avatar_to_info(contact, handle->chat_avatar);
+ UI_MESSAGE_Handle *message = (UI_MESSAGE_Handle*) g_object_get_qdata(
+ G_OBJECT(row->data), app->quarks.ui
+ );
- contact_add_name_label_to_info(contact, handle->chat_details_label);
- contact_add_name_avatar_to_info(contact, handle->chat_details_avatar);
+ if (!message)
+ continue;
+
+ ui_message_refresh(message);
+ last_message = message;
}
- g_object_set_qdata(
- G_OBJECT(handle->chat_avatar),
- app->quarks.data,
- contact
- );
+ g_list_free(rows);
+
+ if ((!last_message) || (!(last_message->timestamp_label)))
+ return NULL;
+
+ return group? NULL : gtk_label_get_text(last_message->timestamp_label);
}
void
@@ -2118,48 +1802,14 @@ ui_chat_update(UI_CHAT_Handle *handle,
contact = GNUNET_CHAT_context_get_contact(handle->context);
group = GNUNET_CHAT_context_get_group(handle->context);
- const char *icon = "action-unavailable-symbolic";
-
- GString *subtitle = g_string_new("");
-
- _chat_update_contact(handle, app, contact);
-
- if (contact)
- icon = "avatar-default-symbolic";
- else if (group)
- {
- const char *title = GNUNET_CHAT_group_get_name(group);
-
- if ((title) && ('#' == *title))
- icon = "network-wired-symbolic";
- else
- icon = "system-users-symbolic";
-
- g_string_append_printf(
- subtitle,
- _("%d members"),
- GNUNET_CHAT_group_iterate_contacts(group, NULL, NULL)
- );
-
- ui_label_set_text(handle->chat_title, title);
- ui_avatar_set_text(handle->chat_avatar, title);
-
- ui_label_set_text(handle->chat_details_label, title);
- ui_avatar_set_text(handle->chat_details_avatar, title);
- }
-
- hdy_avatar_set_icon_name(handle->chat_avatar, icon);
- hdy_avatar_set_icon_name(handle->chat_details_avatar, icon);
-
- if (subtitle->len > 0)
- gtk_label_set_text(handle->chat_subtitle, subtitle->str);
-
- g_string_free(subtitle, TRUE);
-
_chat_update_contacts(handle, app, group);
_chat_update_files(handle, app, handle->context);
_chat_update_media(handle, app, handle->context);
+ const gchar *subtitle = _chat_get_default_subtitle(handle, app, group);
+
+ ui_chat_title_update(handle->title, app, subtitle);
+
g_object_set_qdata(
G_OBJECT(handle->reveal_identity_button),
app->quarks.data,
@@ -2201,37 +1851,6 @@ ui_chat_update(UI_CHAT_Handle *handle,
gtk_widget_set_sensitive(GTK_WIDGET(handle->attach_file_button), activated);
gtk_widget_set_sensitive(GTK_WIDGET(handle->emoji_button), activated);
gtk_widget_set_sensitive(GTK_WIDGET(handle->send_record_button), activated);
-
- GList *rows = gtk_container_get_children(
- GTK_CONTAINER(handle->messages_listbox)
- );
-
- if (!rows)
- return;
-
- UI_MESSAGE_Handle *last_message = NULL;
- for (GList *row = rows; row; row = row->next)
- {
- UI_MESSAGE_Handle *message = (UI_MESSAGE_Handle*) g_object_get_qdata(
- G_OBJECT(row->data), app->quarks.ui
- );
-
- if (!message)
- continue;
-
- ui_message_refresh(message);
- last_message = message;
- }
-
- g_list_free(rows);
-
- if ((!last_message) || (!(last_message->timestamp_label)))
- return;
-
- const gchar *time = gtk_label_get_text(last_message->timestamp_label);
-
- if (!group)
- gtk_label_set_text(handle->chat_subtitle, time);
}
void
@@ -2239,8 +1858,6 @@ ui_chat_delete(UI_CHAT_Handle *handle)
{
g_assert(handle);
- _chat_update_contact(handle, handle->app, NULL);
-
GList *message_rows = gtk_container_get_children(GTK_CONTAINER(handle->messages_listbox));
GList *row_element = message_rows;
@@ -2271,8 +1888,7 @@ ui_chat_delete(UI_CHAT_Handle *handle)
_chat_update_media(handle, handle->app, NULL);
_chat_update_files(handle, handle->app, NULL);
- if (handle->loads)
- g_list_free_full(handle->loads, (GDestroyNotify) ui_file_load_entry_delete);
+ ui_chat_title_delete(handle->title);
g_object_unref(handle->builder);
@@ -2335,46 +1951,3 @@ ui_chat_remove_message(UI_CHAT_Handle *handle,
ui_message_delete(message, app);
}
-
-void
-ui_chat_add_file_load(UI_CHAT_Handle *handle,
- UI_FILE_LOAD_ENTRY_Handle *file_load)
-{
- g_assert((handle) && (file_load));
-
- gtk_container_add(
- GTK_CONTAINER(handle->chat_load_listbox),
- file_load->entry_box
- );
-
- handle->loads = g_list_append(handle->loads, file_load);
-
- gtk_widget_show(GTK_WIDGET(handle->chat_load_button));
-
- file_load->chat = handle;
-}
-
-void
-ui_chat_remove_file_load(UI_CHAT_Handle *handle,
- UI_FILE_LOAD_ENTRY_Handle *file_load)
-{
- g_assert((handle) && (file_load) && (handle == file_load->chat) &&
- (file_load->entry_box));
-
- handle->loads = g_list_remove(handle->loads, file_load);
-
- gtk_container_remove(
- GTK_CONTAINER(handle->chat_load_listbox),
- gtk_widget_get_parent(file_load->entry_box)
- );
-
- if (handle->loads)
- return;
-
- if (gtk_widget_is_visible(GTK_WIDGET(handle->chat_load_popover)))
- gtk_popover_popdown(handle->chat_load_popover);
-
- gtk_widget_hide(GTK_WIDGET(handle->chat_load_button));
-
- file_load->chat = NULL;
-}
diff --git a/src/ui/chat.h b/src/ui/chat.h
@@ -38,7 +38,7 @@
typedef struct MESSENGER_Application MESSENGER_Application;
typedef struct UI_MESSAGE_Handle UI_MESSAGE_Handle;
typedef struct UI_PICKER_Handle UI_PICKER_Handle;
-typedef struct UI_FILE_LOAD_ENTRY_Handle UI_FILE_LOAD_ENTRY_Handle;
+typedef struct UI_CHAT_TITLE_Handle UI_CHAT_TITLE_Handle;
typedef struct UI_CHAT_Handle
{
@@ -67,33 +67,17 @@ typedef struct UI_CHAT_Handle
MESSENGER_Application *app;
struct GNUNET_CHAT_Context *context;
+ UI_CHAT_TITLE_Handle *title;
gdouble edge_value;
- GList *loads;
GtkBuilder *builder;
GtkWidget *chat_box;
- GtkButton *back_button;
-
HdyFlap *flap_chat_details;
- GtkStack *chat_title_stack;
- GtkWidget *title_box;
- GtkWidget *selection_box;
-
- HdyAvatar *chat_avatar;
- GtkLabel *chat_title;
- GtkLabel *chat_subtitle;
-
- GtkButton *chat_load_button;
- GtkPopover *chat_load_popover;
- GtkListBox *chat_load_listbox;
-
- GtkButton *chat_search_button;
HdySearchBar *chat_search_bar;
GtkSearchEntry *chat_search_entry;
- GtkButton *chat_details_button;
GtkLabel *chat_details_label;
GtkButton *hide_chat_details_button;
GtkBox *chat_details_contacts_box;
@@ -110,11 +94,6 @@ typedef struct UI_CHAT_Handle
GtkSwitch *chat_notifications_switch;
- GtkButton *selection_close_button;
- GtkLabel *selection_count_label;
- GtkButton *selection_tag_button;
- GtkButton *selection_delete_button;
-
GtkScrolledWindow *chat_scrolled_window;
GtkListBox *chat_contacts_listbox;
@@ -209,26 +188,4 @@ ui_chat_remove_message(UI_CHAT_Handle *handle,
MESSENGER_Application *app,
UI_MESSAGE_Handle *message);
-/**
- * Add a file load entry handle to a given chat
- * handle to get listed by it.
- *
- * @param handle Chat handle
- * @param file_load File load entry handle
- */
-void
-ui_chat_add_file_load(UI_CHAT_Handle *handle,
- UI_FILE_LOAD_ENTRY_Handle *file_load);
-
-/**
- * Removes a file load entry handle from a given
- * chat handle to remove it from its list.
- *
- * @param handle Chat handle
- * @param file_load File load entry handle
- */
-void
-ui_chat_remove_file_load(UI_CHAT_Handle *handle,
- UI_FILE_LOAD_ENTRY_Handle *file_load);
-
#endif /* UI_CHAT_H_ */
diff --git a/src/ui/chat_entry.c b/src/ui/chat_entry.c
@@ -24,6 +24,7 @@
#include "chat_entry.h"
+#include "chat_title.h"
#include "message.h"
#include "../application.h"
@@ -276,6 +277,11 @@ ui_chat_entry_dispose(UI_CHAT_ENTRY_Handle *handle,
_chat_entry_update_contact(handle, app, NULL);
gtk_container_remove(
+ GTK_CONTAINER(ui->chat_title_stack),
+ handle->chat->title->chat_title_box
+ );
+
+ gtk_container_remove(
GTK_CONTAINER(ui->chats_stack),
handle->chat->chat_box
);
diff --git a/src/ui/chat_title.c b/src/ui/chat_title.c
@@ -0,0 +1,543 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2024 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/chat_title.c
+ */
+
+#include "chat_title.h"
+
+#include "chat.h"
+#include "file_load_entry.h"
+#include "delete_messages.h"
+#include "message.h"
+
+#include "../contact.h"
+#include "../ui.h"
+
+static void
+handle_back_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ g_assert(user_data);
+
+ HdyLeaflet *leaflet = HDY_LEAFLET(user_data);
+
+ GList *children = gtk_container_get_children(GTK_CONTAINER(leaflet));
+
+ if (children) {
+ hdy_leaflet_set_visible_child(leaflet, GTK_WIDGET(children->data));
+ g_list_free(children);
+ }
+}
+
+static gboolean
+_flap_chat_details_reveal_switch(gpointer user_data)
+{
+ g_assert(user_data);
+
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+ HdyFlap* flap = handle->flap_chat_details;
+
+ if (TRUE == hdy_flap_get_reveal_flap(flap)) {
+ hdy_flap_set_reveal_flap(flap, FALSE);
+ } else {
+ hdy_flap_set_reveal_flap(flap, TRUE);
+ }
+
+ gtk_widget_set_sensitive(GTK_WIDGET(handle->messages_listbox), TRUE);
+ return FALSE;
+}
+
+static void
+handle_chat_details_via_button_click(UNUSED GtkButton* button,
+ gpointer user_data)
+{
+ g_assert(user_data);
+
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+
+ gtk_widget_set_sensitive(GTK_WIDGET(handle->messages_listbox), FALSE);
+ util_idle_add(
+ G_SOURCE_FUNC(_flap_chat_details_reveal_switch),
+ handle
+ );
+}
+
+static void
+handle_popover_via_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ g_assert(user_data);
+
+ GtkPopover *popover = GTK_POPOVER(user_data);
+
+ if (gtk_widget_is_visible(GTK_WIDGET(popover)))
+ gtk_popover_popdown(popover);
+ else
+ gtk_popover_popup(popover);
+}
+
+static void
+handle_chat_selection_close_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ g_assert(user_data);
+
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+
+ gtk_list_box_unselect_all(handle->messages_listbox);
+}
+
+void
+_new_tag_callback(MESSENGER_Application *app,
+ GList *selected,
+ const char *tag,
+ gpointer user_data)
+{
+ g_assert((app) && (user_data));
+
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+ UI_MESSAGE_Handle *message;
+
+ if ((!(handle->context)) || (!tag))
+ goto unselect;
+
+ while (selected)
+ {
+ GtkListBoxRow *row = GTK_LIST_BOX_ROW(selected->data);
+
+ if (!row)
+ goto skip_row;
+
+ message = (UI_MESSAGE_Handle*) g_object_get_qdata(
+ G_OBJECT(row),
+ app->quarks.ui
+ );
+
+ if ((!message) || (!(message->msg)))
+ goto skip_row;
+
+ GNUNET_CHAT_context_send_tag(
+ handle->context,
+ message->msg,
+ tag
+ );
+
+ skip_row:
+ selected = selected->next;
+ }
+
+unselect:
+ gtk_list_box_unselect_all(handle->messages_listbox);
+}
+
+static void
+handle_chat_selection_tag_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ g_assert(user_data);
+
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+
+ MESSENGER_Application *app = handle->app;
+
+ GList *selected = gtk_list_box_get_selected_rows(handle->messages_listbox);
+
+ ui_new_tag_dialog_init(app, &(app->ui.new_tag));
+
+ ui_new_tag_dialog_link(
+ &(app->ui.new_tag),
+ _new_tag_callback,
+ selected,
+ handle
+ );
+
+ gtk_widget_show(GTK_WIDGET(app->ui.new_tag.dialog));
+}
+
+void
+_delete_messages_callback(MESSENGER_Application *app,
+ GList *selected,
+ gulong delay)
+{
+ g_assert(app);
+
+ UI_MESSAGE_Handle *message;
+
+ while (selected)
+ {
+ GtkListBoxRow *row = GTK_LIST_BOX_ROW(selected->data);
+
+ if (!row)
+ goto skip_row;
+
+ message = (UI_MESSAGE_Handle*) g_object_get_qdata(
+ G_OBJECT(row),
+ app->quarks.ui
+ );
+
+ if ((!message) || (!(message->msg)))
+ goto skip_row;
+
+ GNUNET_CHAT_message_delete(
+ message->msg,
+ GNUNET_TIME_relative_multiply(
+ GNUNET_TIME_relative_get_second_(),
+ delay
+ )
+ );
+
+ skip_row:
+ selected = selected->next;
+ }
+}
+
+static void
+handle_chat_selection_delete_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ g_assert(user_data);
+
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+
+ MESSENGER_Application *app = handle->app;
+
+ GList *selected = gtk_list_box_get_selected_rows(handle->messages_listbox);
+
+ if (app->settings.hide_delete_dialog)
+ {
+ _delete_messages_callback(app, selected, 0);
+
+ if (selected)
+ g_list_free(selected);
+ }
+ else
+ {
+ ui_delete_messages_dialog_init(app, &(app->ui.delete_messages));
+
+ ui_delete_messages_dialog_link(
+ &(app->ui.delete_messages),
+ _delete_messages_callback,
+ selected
+ );
+
+ gtk_widget_show(GTK_WIDGET(app->ui.delete_messages.dialog));
+ }
+}
+
+static void
+handle_search_button_click(UNUSED GtkButton *button,
+ gpointer user_data)
+{
+ g_assert(user_data);
+
+ UI_CHAT_Handle *handle = (UI_CHAT_Handle*) user_data;
+
+ hdy_search_bar_set_search_mode(
+ handle->chat_search_bar,
+ !hdy_search_bar_get_search_mode(handle->chat_search_bar)
+ );
+}
+
+UI_CHAT_TITLE_Handle*
+ui_chat_title_new(MESSENGER_Application *app,
+ UI_CHAT_Handle *chat)
+{
+ g_assert((app) && (chat));
+
+ UI_CHAT_TITLE_Handle *handle = g_malloc(sizeof(UI_CHAT_TITLE_Handle));
+ UI_MESSENGER_Handle *messenger = &(app->ui.messenger);
+
+ handle->contact = NULL;
+
+ handle->chat = chat;
+ handle->loads = NULL;
+
+ handle->builder = ui_builder_from_resource(
+ application_get_resource_path(app, "ui/chat_title.ui")
+ );
+
+ handle->chat_title_box = GTK_WIDGET(
+ gtk_builder_get_object(handle->builder, "chat_title_box")
+ );
+
+ handle->back_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "back_button")
+ );
+
+ g_object_bind_property(
+ messenger->leaflet_chat,
+ "folded",
+ handle->back_button,
+ "visible",
+ G_BINDING_SYNC_CREATE
+ );
+
+ g_signal_connect(
+ handle->back_button,
+ "clicked",
+ G_CALLBACK(handle_back_button_click),
+ messenger->leaflet_chat
+ );
+
+ handle->chat_title_stack = GTK_STACK(
+ gtk_builder_get_object(handle->builder, "chat_title_stack")
+ );
+
+ handle->title_box = GTK_WIDGET(
+ gtk_builder_get_object(handle->builder, "title_box")
+ );
+
+ handle->selection_box = GTK_WIDGET(
+ gtk_builder_get_object(handle->builder, "selection_box")
+ );
+
+ handle->chat_avatar = HDY_AVATAR(
+ gtk_builder_get_object(handle->builder, "chat_avatar")
+ );
+
+ handle->chat_title = GTK_LABEL(
+ gtk_builder_get_object(handle->builder, "chat_title")
+ );
+
+ handle->chat_subtitle = GTK_LABEL(
+ gtk_builder_get_object(handle->builder, "chat_subtitle")
+ );
+
+ handle->chat_load_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "chat_load_button")
+ );
+
+ handle->chat_load_popover = GTK_POPOVER(
+ gtk_builder_get_object(handle->builder, "chat_load_popover")
+ );
+
+ handle->chat_load_listbox = GTK_LIST_BOX(
+ gtk_builder_get_object(handle->builder, "chat_load_listbox")
+ );
+
+ g_signal_connect(
+ handle->chat_load_button,
+ "clicked",
+ G_CALLBACK(handle_popover_via_button_click),
+ handle->chat_load_popover
+ );
+
+ handle->chat_search_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "chat_search_button")
+ );
+
+ g_signal_connect(
+ handle->chat_search_button,
+ "clicked",
+ G_CALLBACK(handle_search_button_click),
+ handle->chat
+ );
+
+ handle->chat_details_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "chat_details_button")
+ );
+
+ g_signal_connect(
+ handle->chat_details_button,
+ "clicked",
+ G_CALLBACK(handle_chat_details_via_button_click),
+ handle->chat
+ );
+
+ handle->selection_close_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "selection_close_button")
+ );
+
+ handle->selection_count_label = GTK_LABEL(
+ gtk_builder_get_object(handle->builder, "selection_count_label")
+ );
+
+ handle->selection_tag_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "selection_tag_button")
+ );
+
+ handle->selection_delete_button = GTK_BUTTON(
+ gtk_builder_get_object(handle->builder, "selection_delete_button")
+ );
+
+ g_signal_connect(
+ handle->selection_close_button,
+ "clicked",
+ G_CALLBACK(handle_chat_selection_close_button_click),
+ handle->chat
+ );
+
+ g_signal_connect(
+ handle->selection_tag_button,
+ "clicked",
+ G_CALLBACK(handle_chat_selection_tag_button_click),
+ handle->chat
+ );
+
+ g_signal_connect(
+ handle->selection_delete_button,
+ "clicked",
+ G_CALLBACK(handle_chat_selection_delete_button_click),
+ handle->chat
+ );
+
+ return handle;
+}
+
+static void
+_chat_update_contact(UI_CHAT_TITLE_Handle *handle,
+ const struct GNUNET_CHAT_Contact* contact)
+{
+ g_assert(handle);
+
+ if (handle->contact)
+ {
+ contact_remove_name_label_from_info(handle->contact, handle->chat_title);
+ contact_remove_name_avatar_from_info(handle->contact, handle->chat_avatar);
+
+ contact_remove_name_label_from_info(handle->contact, handle->chat->chat_details_label);
+ contact_remove_name_avatar_from_info(handle->contact, handle->chat->chat_details_avatar);
+ }
+
+ if (contact)
+ {
+ contact_add_name_label_to_info(contact, handle->chat_title);
+ contact_add_name_avatar_to_info(contact, handle->chat_avatar);
+
+ contact_add_name_label_to_info(contact, handle->chat->chat_details_label);
+ contact_add_name_avatar_to_info(contact, handle->chat->chat_details_avatar);
+ }
+
+ handle->contact = contact;
+}
+
+void
+ui_chat_title_update(UI_CHAT_TITLE_Handle *handle,
+ MESSENGER_Application *app,
+ const gchar *subtitle)
+{
+ g_assert((handle) && (app));
+
+ UI_CHAT_Handle *chat = handle->chat;
+
+ struct GNUNET_CHAT_Contact* contact;
+ struct GNUNET_CHAT_Group* group;
+
+ contact = GNUNET_CHAT_context_get_contact(chat->context);
+ group = GNUNET_CHAT_context_get_group(chat->context);
+
+ const char *icon = "action-unavailable-symbolic";
+
+ GString *sub = g_string_new(subtitle? subtitle : "");
+
+ _chat_update_contact(handle, contact);
+
+ if (contact)
+ icon = "avatar-default-symbolic";
+ else if (group)
+ {
+ const char *title = GNUNET_CHAT_group_get_name(group);
+
+ if ((title) && ('#' == *title))
+ icon = "network-wired-symbolic";
+ else
+ icon = "system-users-symbolic";
+
+ g_string_append_printf(
+ sub,
+ _("%d members"),
+ GNUNET_CHAT_group_iterate_contacts(group, NULL, NULL)
+ );
+
+ ui_label_set_text(handle->chat_title, title);
+ ui_avatar_set_text(handle->chat_avatar, title);
+
+ ui_label_set_text(handle->chat->chat_details_label, title);
+ ui_avatar_set_text(handle->chat->chat_details_avatar, title);
+ }
+
+ hdy_avatar_set_icon_name(handle->chat_avatar, icon);
+ hdy_avatar_set_icon_name(handle->chat->chat_details_avatar, icon);
+
+ if (sub->len > 0)
+ gtk_label_set_text(handle->chat_subtitle, sub->str);
+
+ g_string_free(sub, TRUE);
+}
+
+void
+ui_chat_title_delete(UI_CHAT_TITLE_Handle *handle)
+{
+ g_assert(handle);
+
+ _chat_update_contact(handle, NULL);
+
+ if (handle->loads)
+ g_list_free_full(handle->loads, (GDestroyNotify) ui_file_load_entry_delete);
+
+ g_object_unref(handle->builder);
+
+ g_free(handle);
+}
+
+void
+ui_chat_title_add_file_load(UI_CHAT_TITLE_Handle *handle,
+ UI_FILE_LOAD_ENTRY_Handle *file_load)
+{
+ g_assert((handle) && (file_load));
+
+ gtk_container_add(
+ GTK_CONTAINER(handle->chat_load_listbox),
+ file_load->entry_box
+ );
+
+ handle->loads = g_list_append(handle->loads, file_load);
+
+ gtk_widget_show(GTK_WIDGET(handle->chat_load_button));
+
+ file_load->chat_title = handle;
+}
+
+void
+ui_chat_title_remove_file_load(UI_CHAT_TITLE_Handle *handle,
+ UI_FILE_LOAD_ENTRY_Handle *file_load)
+{
+ g_assert((handle) && (file_load) && (handle == file_load->chat_title) &&
+ (file_load->entry_box));
+
+ handle->loads = g_list_remove(handle->loads, file_load);
+
+ gtk_container_remove(
+ GTK_CONTAINER(handle->chat_load_listbox),
+ gtk_widget_get_parent(file_load->entry_box)
+ );
+
+ if (handle->loads)
+ return;
+
+ if (gtk_widget_is_visible(GTK_WIDGET(handle->chat_load_popover)))
+ gtk_popover_popdown(handle->chat_load_popover);
+
+ gtk_widget_hide(GTK_WIDGET(handle->chat_load_button));
+
+ file_load->chat_title = NULL;
+}
diff --git a/src/ui/chat_title.h b/src/ui/chat_title.h
@@ -0,0 +1,128 @@
+/*
+ This file is part of GNUnet.
+ Copyright (C) 2024 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/chat_title.h
+ */
+
+#ifndef UI_CHAT_TITLE_H_
+#define UI_CHAT_TITLE_H_
+
+#include <gtk-3.0/gtk/gtk.h>
+#include <libhandy-1/handy.h>
+
+#include <gnunet/gnunet_chat_lib.h>
+
+typedef struct MESSENGER_Application MESSENGER_Application;
+typedef struct UI_CHAT_Handle UI_CHAT_Handle;
+typedef struct UI_FILE_LOAD_ENTRY_Handle UI_FILE_LOAD_ENTRY_Handle;
+
+typedef struct UI_CHAT_TITLE_Handle
+{
+ const struct GNUNET_CHAT_Contact *contact;
+
+ UI_CHAT_Handle *chat;
+ GList *loads;
+
+ GtkBuilder *builder;
+ GtkWidget *chat_title_box;
+
+ GtkButton *back_button;
+
+ GtkStack *chat_title_stack;
+ GtkWidget *title_box;
+ GtkWidget *selection_box;
+
+ HdyAvatar *chat_avatar;
+ GtkLabel *chat_title;
+ GtkLabel *chat_subtitle;
+
+ GtkButton *chat_load_button;
+ GtkPopover *chat_load_popover;
+ GtkListBox *chat_load_listbox;
+
+ GtkButton *chat_search_button;
+ GtkButton *chat_details_button;
+
+ GtkButton *selection_close_button;
+ GtkLabel *selection_count_label;
+ GtkButton *selection_tag_button;
+ GtkButton *selection_delete_button;
+} UI_CHAT_TITLE_Handle;
+
+/**
+ * Allocates and creates a new chat title
+ * handle to manage a chat for a given
+ * messenger application.
+ *
+ * @param app Messenger application
+ * @param chat Chat handle
+ * @return New chat title handle
+ */
+UI_CHAT_TITLE_Handle*
+ui_chat_title_new(MESSENGER_Application *app,
+ UI_CHAT_Handle *chat);
+
+/**
+ * Updates a given chat title handle with
+ * the current state of a messenger application
+ * and the chat context the chat is representing.
+ *
+ * @param handle Chat title handle
+ * @param app Messenger application
+ * @param subtitle Default subtitle value
+ */
+void
+ui_chat_title_update(UI_CHAT_TITLE_Handle *handle,
+ MESSENGER_Application *app,
+ const gchar *subtitle);
+
+/**
+ * Frees its resources and destroys a given
+ * chat handle.
+ *
+ * @param handle Chat title handle
+ */
+void
+ui_chat_title_delete(UI_CHAT_TITLE_Handle *handle);
+
+/**
+ * Add a file load entry handle to a given chat
+ * title handle to get listed by it.
+ *
+ * @param handle Chat title handle
+ * @param file_load File load entry handle
+ */
+void
+ui_chat_title_add_file_load(UI_CHAT_TITLE_Handle *handle,
+ UI_FILE_LOAD_ENTRY_Handle *file_load);
+
+/**
+ * Removes a file load entry handle from a given
+ * chat title handle to remove it from its list.
+ *
+ * @param handle Chat title handle
+ * @param file_load File load entry handle
+ */
+void
+ui_chat_title_remove_file_load(UI_CHAT_TITLE_Handle *handle,
+ UI_FILE_LOAD_ENTRY_Handle *file_load);
+
+#endif /* UI_CHAT_H_ */
diff --git a/src/ui/file_load_entry.c b/src/ui/file_load_entry.c
@@ -27,7 +27,7 @@
#include "../application.h"
#include "../ui.h"
-#include "chat.h"
+#include "chat_title.h"
static void
handle_cancel_button_click(GNUNET_UNUSED GtkButton *button,
@@ -37,8 +37,8 @@ handle_cancel_button_click(GNUNET_UNUSED GtkButton *button,
UI_FILE_LOAD_ENTRY_Handle* handle = (UI_FILE_LOAD_ENTRY_Handle*) user_data;
- if (handle->chat)
- ui_chat_remove_file_load(handle->chat, handle);
+ if (handle->chat_title)
+ ui_chat_title_remove_file_load(handle->chat_title, handle);
// TODO: cancel upload?
}
@@ -50,7 +50,7 @@ ui_file_load_entry_new(MESSENGER_Application *app)
UI_FILE_LOAD_ENTRY_Handle* handle = g_malloc(sizeof(UI_FILE_LOAD_ENTRY_Handle));
- handle->chat = NULL;
+ handle->chat_title = NULL;
handle->builder = ui_builder_from_resource(
application_get_resource_path(app, "ui/file_load_entry.ui")
diff --git a/src/ui/file_load_entry.h b/src/ui/file_load_entry.h
@@ -1,6 +1,6 @@
/*
This file is part of GNUnet.
- Copyright (C) 2022 GNUnet e.V.
+ Copyright (C) 2022--2024 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
@@ -29,11 +29,11 @@
#include "messenger.h"
-typedef struct UI_CHAT_Handle UI_CHAT_Handle;
+typedef struct UI_CHAT_TITLE_Handle UI_CHAT_TITLE_Handle;
typedef struct UI_FILE_LOAD_ENTRY_Handle
{
- UI_CHAT_Handle *chat;
+ UI_CHAT_TITLE_Handle *chat_title;
GtkBuilder *builder;
diff --git a/src/ui/meson.build b/src/ui/meson.build
@@ -23,6 +23,7 @@ messenger_gtk_ui_sources = files([
'account_entry.c', 'account_entry.h',
'accounts.c', 'accounts.h',
'chat_entry.c', 'chat_entry.h',
+ 'chat_title.c', 'chat_title.h',
'chat.c', 'chat.h',
'contact_entry.c', 'contact_entry.h',
'contact_info.c', 'contact_info.h',
diff --git a/src/ui/messenger.c b/src/ui/messenger.c
@@ -28,6 +28,7 @@
#include "account_entry.h"
#include "chat_entry.h"
+#include "chat_title.h"
#include "contacts.h"
#include "message.h"
#include "new_contact.h"
@@ -278,18 +279,17 @@ handle_chats_listbox_row_activated(UNUSED GtkListBox* listbox,
if ((!entry) || (!(entry->chat)) || (!(entry->chat->chat_box)))
return;
- GtkStack *stack = app->ui.messenger.chats_stack;
- HdyLeaflet *leaflet = app->ui.messenger.leaflet_chat;
-
- GList *children = gtk_container_get_children(GTK_CONTAINER(leaflet));
+ UI_MESSENGER_Handle *ui = &(app->ui.messenger);
+ GList *children = gtk_container_get_children(GTK_CONTAINER(ui->leaflet_chat));
if ((children) && (children->next))
- hdy_leaflet_set_visible_child(leaflet, GTK_WIDGET(children->next->data));
+ hdy_leaflet_set_visible_child(ui->leaflet_chat, GTK_WIDGET(children->next->data));
if (children)
g_list_free(children);
- gtk_stack_set_visible_child(stack, entry->chat->chat_box);
+ gtk_stack_set_visible_child(ui->chats_stack, entry->chat->chat_box);
+ gtk_stack_set_visible_child(ui->chat_title_stack, entry->chat->title->chat_title_box);
}
static gint
@@ -369,19 +369,13 @@ handle_search_button_click(UNUSED GtkButton *button,
UI_MESSENGER_Handle *handle = (UI_MESSENGER_Handle*) user_data;
- gtk_stack_set_visible_child(handle->chats_title_stack, handle->search_box);
-}
-
-static void
-handle_search_end_button_click(UNUSED GtkButton *button,
- gpointer user_data)
-{
- g_assert(user_data);
-
- UI_MESSENGER_Handle *handle = (UI_MESSENGER_Handle*) user_data;
-
- gtk_stack_set_visible_child(handle->chats_title_stack, handle->title_box);
- gtk_entry_set_text(GTK_ENTRY(handle->chats_search_entry), "");
+ if (handle->search_box == gtk_stack_get_visible_child(handle->chats_title_stack))
+ {
+ gtk_stack_set_visible_child(handle->chats_title_stack, handle->title_box);
+ gtk_entry_set_text(GTK_ENTRY(handle->chats_search_entry), "");
+ }
+ else
+ gtk_stack_set_visible_child(handle->chats_title_stack, handle->search_box);
}
static void
@@ -454,16 +448,32 @@ ui_messenger_init(MESSENGER_Application *app,
1100, 700
);
+ handle->leaflet_title = HDY_LEAFLET(
+ gtk_builder_get_object(handle->builder, "leaflet_title")
+ );
+
handle->leaflet_chat = HDY_LEAFLET(
gtk_builder_get_object(handle->builder, "leaflet_chat")
);
+ g_object_bind_property(
+ handle->leaflet_chat,
+ "visible_child_name",
+ handle->leaflet_title,
+ "visible_child_name",
+ G_BINDING_SYNC_CREATE
+ );
+
handle->flap_user_details = HDY_FLAP(
gtk_builder_get_object(handle->builder, "flap_user_details")
);
- handle->title_bar = HDY_HEADER_BAR(
- gtk_builder_get_object(handle->builder, "title_bar")
+ handle->nav_bar = GTK_HEADER_BAR(
+ gtk_builder_get_object(handle->builder, "nav_bar")
+ );
+
+ handle->main_bar = GTK_HEADER_BAR(
+ gtk_builder_get_object(handle->builder, "main_bar")
);
GtkLabel* application_name_label = GTK_LABEL(
@@ -474,16 +484,6 @@ ui_messenger_init(MESSENGER_Application *app,
gtk_builder_get_object(handle->builder, "application-version-label")
);
- hdy_header_bar_set_title(
- handle->title_bar,
- MESSENGER_APPLICATION_TITLE
- );
-
- hdy_header_bar_set_subtitle(
- handle->title_bar,
- MESSENGER_APPLICATION_SUBTITLE
- );
-
gtk_label_set_text(
application_name_label,
MESSENGER_APPLICATION_APPNAME
@@ -497,20 +497,10 @@ ui_messenger_init(MESSENGER_Application *app,
g_object_bind_property(
handle->leaflet_chat,
"folded",
- handle->title_bar,
+ handle->main_bar,
"show-close-button",
G_BINDING_INVERT_BOOLEAN
);
-
- if (app->settings.mobile_design)
- g_object_bind_property(
- handle->leaflet_chat,
- "folded",
- handle->title_bar,
- "visible",
- G_BINDING_SYNC_CREATE |
- G_BINDING_INVERT_BOOLEAN
- );
handle->profile_button = GTK_BUTTON(
gtk_builder_get_object(handle->builder, "profile_button")
@@ -669,6 +659,14 @@ ui_messenger_init(MESSENGER_Application *app,
gtk_builder_get_object(handle->builder, "search_box")
);
+ g_object_bind_property(
+ handle->leaflet_chat,
+ "folded",
+ handle->nav_bar,
+ "hexpand",
+ G_BINDING_SYNC_CREATE
+ );
+
handle->user_details_button = GTK_BUTTON(
gtk_builder_get_object(handle->builder, "user_details_button")
);
@@ -695,15 +693,16 @@ ui_messenger_init(MESSENGER_Application *app,
gtk_builder_get_object(handle->builder, "chats_search_entry")
);
- handle->chats_search_end_button = GTK_BUTTON(
- gtk_builder_get_object(handle->builder, "chats_search_end_button")
+ handle->search_icon_stack = GTK_STACK(
+ gtk_builder_get_object(handle->builder, "search_icon_stack")
);
- g_signal_connect(
- handle->chats_search_end_button,
- "clicked",
- G_CALLBACK(handle_search_end_button_click),
- handle
+ g_object_bind_property(
+ handle->chats_title_stack,
+ "visible_child_name",
+ handle->search_icon_stack,
+ "visible_child_name",
+ G_BINDING_SYNC_CREATE
);
handle->chats_listbox = GTK_LIST_BOX(
@@ -746,6 +745,10 @@ ui_messenger_init(MESSENGER_Application *app,
gtk_builder_get_object(handle->builder, "no_chat_box")
);
+ handle->chat_title_stack = GTK_STACK(
+ gtk_builder_get_object(handle->builder, "chat_title_stack")
+ );
+
g_signal_connect(
handle->main_window,
"destroy",
diff --git a/src/ui/messenger.h b/src/ui/messenger.h
@@ -44,10 +44,12 @@ typedef struct UI_MESSENGER_Handle
GtkBuilder *builder;
GtkApplicationWindow *main_window;
+ HdyLeaflet *leaflet_title;
HdyLeaflet *leaflet_chat;
HdyFlap *flap_user_details;
- HdyHeaderBar *title_bar;
+ GtkHeaderBar *nav_bar;
+ GtkHeaderBar *main_bar;
GtkButton *profile_button;
HdyAvatar *profile_avatar;
@@ -78,12 +80,14 @@ typedef struct UI_MESSENGER_Handle
GtkButton *chats_search_button;
GtkSearchEntry *chats_search_entry;
- GtkButton *chats_search_end_button;
+ GtkStack *search_icon_stack;
GtkListBox *chats_listbox;
GtkStack *chats_stack;
GtkWidget *no_chat_box;
+
+ GtkStack *chat_title_stack;
} UI_MESSENGER_Handle;
/**
diff --git a/src/ui/send_file.c b/src/ui/send_file.c
@@ -24,8 +24,8 @@
#include "send_file.h"
-#include "chat.h"
#include "chat_entry.h"
+#include "chat_title.h"
#include "file_load_entry.h"
#include "../application.h"
@@ -59,8 +59,8 @@ handle_sending_upload_file(UNUSED void *cls,
file_update_upload_info(file, completed, size);
- if ((completed >= size) && (file_load->chat))
- ui_chat_remove_file_load(file_load->chat, file_load);
+ if ((completed >= size) && (file_load->chat_title))
+ ui_chat_title_remove_file_load(file_load->chat_title, file_load);
}
static void
@@ -124,7 +124,7 @@ handle_send_button_click(GtkButton *button,
file_create_info(file);
- ui_chat_add_file_load(handle, file_load);
+ ui_chat_title_add_file_load(handle->title, file_load);
}
static void