messenger-gtk

Gtk+3 graphical user interfaces for GNUnet Messenger
Log | Files | Refs | Submodules | README | LICENSE

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:
Mresources/ui.gresource.xml | 1+
Aresources/ui/#messenger.ui# | 978+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mresources/ui/chat.ui | 274-------------------------------------------------------------------------------
Aresources/ui/chat_title.ui | 306+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mresources/ui/messenger.ui | 346++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/event.c | 7+++++++
Msrc/ui/chat.c | 501++++++-------------------------------------------------------------------------
Msrc/ui/chat.h | 47++---------------------------------------------
Msrc/ui/chat_entry.c | 6++++++
Asrc/ui/chat_title.c | 543+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ui/chat_title.h | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/ui/file_load_entry.c | 8++++----
Msrc/ui/file_load_entry.h | 6+++---
Msrc/ui/meson.build | 1+
Msrc/ui/messenger.c | 101+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/ui/messenger.h | 8++++++--
Msrc/ui/send_file.c | 8++++----
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