[fractal/wip/christopherdavis/port-to-libhandy-1.0: 2/2] fractal-gtk: Refactor window to use HdyDeck
- From: Christopher Davis <christopherdavis src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/wip/christopherdavis/port-to-libhandy-1.0: 2/2] fractal-gtk: Refactor window to use HdyDeck
- Date: Tue, 15 Sep 2020 07:34:56 +0000 (UTC)
commit 8d7809b1826981306759a3acdfc080c4714bcedb
Author: Christopher Davis <brainblasted disroot org>
Date: Fri Sep 11 02:00:00 2020 -0700
fractal-gtk: Refactor window to use HdyDeck
Helps simplify how we handle pages, as well as
adding support for swiping between the main view
and different subviews.
Cargo.lock | 1 +
fractal-gtk/Cargo.toml | 1 +
fractal-gtk/res/ui/account_settings.ui | 68 +-
fractal-gtk/res/ui/login_flow.ui | 575 +++++-----
fractal-gtk/res/ui/main_window.ui | 1208 +++++++++++-----------
fractal-gtk/res/ui/media_viewer.ui | 154 +--
fractal-gtk/res/ui/room_settings.ui | 68 +-
fractal-gtk/src/actions/global.rs | 14 +-
fractal-gtk/src/actions/login.rs | 44 +-
fractal-gtk/src/actions/message.rs | 8 +-
fractal-gtk/src/app/connect/autocomplete.rs | 12 +-
fractal-gtk/src/app/connect/headerbar.rs | 16 +-
fractal-gtk/src/app/connect/mod.rs | 2 +
fractal-gtk/src/app/connect/swipeable_widgets.rs | 57 +
fractal-gtk/src/app/mod.rs | 44 +-
fractal-gtk/src/appop/about.rs | 2 +-
fractal-gtk/src/appop/account.rs | 8 +-
fractal-gtk/src/appop/attach.rs | 2 +-
fractal-gtk/src/appop/media_viewer.rs | 19 +-
fractal-gtk/src/appop/message.rs | 2 +-
fractal-gtk/src/appop/mod.rs | 12 +-
fractal-gtk/src/appop/room.rs | 2 +-
fractal-gtk/src/appop/room_settings.rs | 24 +-
fractal-gtk/src/appop/state.rs | 132 ++-
fractal-gtk/src/main.rs | 6 +
fractal-gtk/src/meson.build | 1 +
fractal-gtk/src/widgets/kicked_dialog.rs | 2 +-
fractal-gtk/src/widgets/login.rs | 11 +-
fractal-gtk/src/widgets/room_settings.rs | 10 +-
29 files changed, 1262 insertions(+), 1243 deletions(-)
---
diff --git a/Cargo.lock b/Cargo.lock
index 6fa4b9ca..726c3d50 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -563,6 +563,7 @@ dependencies = [
"gstreamer-pbutils",
"gstreamer-player",
"gtk",
+ "gtk-sys",
"html2pango",
"itertools 0.8.2",
"lazy_static",
diff --git a/fractal-gtk/Cargo.toml b/fractal-gtk/Cargo.toml
index 61a0805f..5474556b 100644
--- a/fractal-gtk/Cargo.toml
+++ b/fractal-gtk/Cargo.toml
@@ -31,6 +31,7 @@ serde_json = "1.0.48"
letter-avatar = "1.3.0"
sourceview4 = "0.2.0"
gspell = "0.5.0"
+gtk-sys = "0.10.0"
[dependencies.gst]
version = "0.16.1"
diff --git a/fractal-gtk/res/ui/account_settings.ui b/fractal-gtk/res/ui/account_settings.ui
index 8e7730b1..bc550faa 100644
--- a/fractal-gtk/res/ui/account_settings.ui
+++ b/fractal-gtk/res/ui/account_settings.ui
@@ -5,12 +5,42 @@
<object class="GtkBox" id="account_settings_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="HdyHeaderBar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="show_close_button">True</property>
+ <property name="title" translatable="yes">Account Settings</property>
+ <child>
+ <object class="GtkButton" id="account_settings_back_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="action_name">app.deck-back</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>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="back_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Back</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
<child>
<object class="GtkScrolledWindow" id="account_settings_scroll">
<property name="width_request">200</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
+ <property name="expand">True</property>
<child>
<object class="GtkViewport">
<property name="width_request">200</property>
@@ -567,44 +597,6 @@
</object>
</child>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
- <object class="GtkBox" id="account_settings_headerbar">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkHeaderBar">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="show_close_button">True</property>
- <property name="expand">True</property>
- <property name="title" translatable="yes">Account Settings</property>
- <child>
- <object class="GtkButton" id="account_settings_back_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="action_name">app.back</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>
- <child internal-child="accessible">
- <object class="AtkObject" id="back_button-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">Back</property>
- </object>
- </child>
- </object>
- </child>
- </object>
</child>
</object>
<object class="GtkDialog" id="account_settings_email_dialog">
diff --git a/fractal-gtk/res/ui/login_flow.ui b/fractal-gtk/res/ui/login_flow.ui
index ebaac45a..5dccbc8e 100644
--- a/fractal-gtk/res/ui/login_flow.ui
+++ b/fractal-gtk/res/ui/login_flow.ui
@@ -2,63 +2,80 @@
<!-- Generated with glade 3.22.0 -->
<interface>
<requires lib="gtk+" version="3.22"/>
- <object class="GtkStack" id="login_flow_stack">
+ <object class="HdyDeck" id="login_flow_deck">
<property name="can_focus">False</property>
+ <property name="can_swipe_back">True</property>
<property name="hhomogeneous">True</property>
- <property name="transition_type">GTK_STACK_TRANSITION_TYPE_SLIDE_LEFT_RIGHT</property>
+ <property name="visible_child_name">greeter</property>
<child>
- <object class="GtkBox" id="login_greeter">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
<property name="orientation">vertical</property>
- <property name="spacing">18</property>
<child>
- <object class="GtkImage" id="login_greeter_image">
+ <object class="HdyHeaderBar" id="login_greeter_header">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="margin_start">18</property>
- <property name="margin_end">18</property>
- <property name="margin_top">18</property>
- <property name="pixel_size">128</property>
- <property name="icon_name">chat-icon</property>
+ <property name="show_close_button">True</property>
+ <property name="title" translatable="yes">Fractal</property>
</object>
</child>
<child>
- <object class="GtkLabel">
+ <object class="GtkBox" id="login_greeter">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Welcome to Fractal</property>
- <property name="margin_bottom">48</property>
- <property name="wrap">True</property>
- <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
- <attributes>
- <attribute name="weight" value="ultrabold"/>
- <attribute name="scale" value="1.7"/>
- </attributes>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="login_button">
- <property name="visible">True</property>
- <property name="use_underline">True</property>
- <property name="label" translatable="yes">_Log In</property>
- <property name="action_name">login.server_chooser</property>
- <property name="height-request">48</property>
- <style>
- <class name="suggested-action"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="create_account_button">
- <property name="visible">True</property>
- <property name="use_underline">True</property>
- <property name="label" translatable="yes">_Create Account</property>
- <property name="height-request">48</property>
- <property name="action_name">login.create-account</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="expand">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">18</property>
+ <child>
+ <object class="GtkImage" id="login_greeter_image">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="margin_start">18</property>
+ <property name="margin_end">18</property>
+ <property name="margin_top">18</property>
+ <property name="pixel_size">128</property>
+ <property name="icon_name">chat-icon</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Welcome to Fractal</property>
+ <property name="margin_bottom">48</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
+ <attributes>
+ <attribute name="weight" value="ultrabold"/>
+ <attribute name="scale" value="1.7"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="login_button">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="label" translatable="yes">_Log In</property>
+ <property name="action_name">login.server_chooser</property>
+ <property name="height-request">48</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="create_account_button">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="label" translatable="yes">_Create Account</property>
+ <property name="height-request">48</property>
+ <property name="action_name">login.create-account</property>
+ </object>
+ </child>
</object>
</child>
</object>
@@ -67,314 +84,310 @@
</packing>
</child>
<child>
- <object class="GtkBox" id="login_server_chooser">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
<property name="orientation">vertical</property>
- <property name="spacing">18</property>
+ <property name="expand">True</property>
<child>
- <object class="GtkImage">
+ <object class="HdyHeaderBar" id="login_server_chooser_header">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="margin_start">18</property>
- <property name="margin_end">18</property>
- <property name="pixel_size">128</property>
- <property name="icon_name">network-server-symbolic</property>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">What is your Provider?</property>
- <property name="margin_bottom">30</property>
- <property name="wrap">True</property>
- <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
- <attributes>
- <attribute name="weight" value="ultrabold"/>
- <attribute name="scale" value="1.7"/>
- </attributes>
+ <property name="show_close_button">True</property>
+ <property name="width_request">360</property>
+ <property name="title" translatable="yes">Choose Provider</property>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="action_name">login.back</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon_name">go-previous-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack_type">start</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="can_focus">True</property>
+ <property name="action_name">login.credentials</property>
+ <property name="label" translatable="yes">_Next</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ </packing>
+ </child>
</object>
</child>
<child>
- <object class="GtkBox">
+ <object class="GtkBox" id="login_server_chooser">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="expand">True</property>
<property name="orientation">vertical</property>
- <property name="spacing">6</property>
+ <property name="spacing">18</property>
<child>
- <object class="GtkEntry" id="server_chooser_entry">
+ <object class="GtkImage">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
<property name="halign">center</property>
- <property name="max_width_chars">-1</property>
- <property name="width_request">300</property>
- <property name="input_purpose">GTK_INPUT_PURPOSE_URL</property>
+ <property name="margin_start">18</property>
+ <property name="margin_end">18</property>
+ <property name="pixel_size">128</property>
+ <property name="icon_name">network-server-symbolic</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Matrix provider domain, e.g. myserver.co</property>
+ <property name="label" translatable="yes">What is your Provider?</property>
+ <property name="margin_bottom">30</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
+ <attributes>
+ <attribute name="weight" value="ultrabold"/>
+ <attribute name="scale" value="1.7"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkEntry" id="server_chooser_entry">
+ <property name="visible">True</property>
+ <property name="halign">center</property>
+ <property name="max_width_chars">-1</property>
+ <property name="width_request">300</property>
+ <property name="input_purpose">GTK_INPUT_PURPOSE_URL</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Matrix provider domain, e.g.
myserver.co</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
+ <style>
+ <class name="dim-label"/>
+ <class name="small-label"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="server_err_label">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="label" translatable="yes">The domain may not be empty.</property>
<property name="wrap">True</property>
<property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
<style>
- <class name="dim-label"/>
- <class name="small-label"/>
+ <class name="error-label"/>
</style>
</object>
</child>
</object>
</child>
- <child>
- <object class="GtkLabel" id="server_err_label">
- <property name="visible">False</property>
- <property name="can_focus">False</property>
- <property name="no_show_all">True</property>
- <property name="label" translatable="yes">The domain may not be empty.</property>
- <property name="wrap">True</property>
- <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
- <style>
- <class name="error-label"/>
- </style>
- </object>
- </child>
</object>
<packing>
<property name="name">server-chooser</property>
</packing>
</child>
<child>
- <object class="GtkGrid" id="login_credentials">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="column_spacing">12</property>
- <property name="row_spacing">24</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="use_underline">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">_User ID</property>
- <property name="halign">end</property>
- <property name="valign">end</property>
- <property name="wrap">True</property>
- <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
- <property name="mnemonic_widget">username_entry</property>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- </child>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkLabel">
+ <object class="GtkHeaderBar" id="login_credentials_header">
<property name="visible">True</property>
- <property name="use_underline">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">_Password</property>
- <property name="halign">end</property>
- <property name="wrap">True</property>
- <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
- <property name="mnemonic_widget">password_entry</property>
- <style>
- <class name="dim-label"/>
- </style>
+ <property name="show_close_button">True</property>
+ <property name="title" translatable="yes">Log In</property>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="action_name">login.back</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon_name">go-previous-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack_type">start</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="can_focus">True</property>
+ <property name="action_name">login.login</property>
+ <property name="label" translatable="yes">_Log In</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ </packing>
+ </child>
</object>
- <packing>
- <property name="top-attach">3</property>
- <property name="left-attach">0</property>
- </packing>
</child>
<child>
- <object class="GtkBox">
+ <object class="GtkGrid" id="login_credentials">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="expand">True</property>
+ <property name="column_spacing">12</property>
+ <property name="row_spacing">24</property>
<child>
- <object class="GtkEntry" id="username_entry">
+ <object class="GtkLabel">
<property name="visible">True</property>
- <property name="max_width_chars">-1</property>
- <property name="width_request">232</property>
- <property name="can_focus">True</property>
+ <property name="use_underline">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">_User ID</property>
+ <property name="halign">end</property>
+ <property name="valign">end</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
+ <property name="mnemonic_widget">username_entry</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
+ <property name="use_underline">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">User name, email, or phone number</property>
- <property name="halign">start</property>
+ <property name="label" translatable="yes">_Password</property>
+ <property name="halign">end</property>
<property name="wrap">True</property>
<property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
+ <property name="mnemonic_widget">password_entry</property>
<style>
<class name="dim-label"/>
- <class name="small-font"/>
</style>
</object>
+ <packing>
+ <property name="top-attach">3</property>
+ <property name="left-attach">0</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="left-attach">1</property>
- <property name="height">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="password_entry">
- <property name="visible">True</property>
- <property name="max_width_chars">-1</property>
- <property name="width_request">232</property>
- <property name="can_focus">True</property>
- <property name="visibility">False</property>
- <property name="input_purpose">GTK_INPUT_PURPOSE_PASSWORD</property>
- </object>
- <packing>
- <property name="top-attach">3</property>
- <property name="left-attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLinkButton" id="forgot_password">
- <property name="use_underline">True</property>
- <property name="label" translatable="yes">_Forgot Password?</property>
- <property name="uri">https://riot.im/app/#/login</property>
- <property name="halign">start</property>
- <style>
- <class name="forgot-password"/>
- </style>
- </object>
- <packing>
- <property name="top-attach">4</property>
- <property name="left-attach">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkLabel" id="credentials_err_label">
- <property name="visible">False</property>
- <property name="can_focus">False</property>
- <property name="no_show_all">True</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">Invalid username or password</property>
- <property name="wrap">True</property>
- <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
- <style>
- <class name="error-label"/>
- </style>
- </object>
- <packing>
- <property name="top-attach">5</property>
- <property name="left-attach">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="name">credentials</property>
- </packing>
- </child>
- </object>
- <object class="GtkStack" id="login_flow_headers">
- <property name="can_focus">False</property>
- <property name="hhomogeneous">True</property>
- <property name="visible_child_name" bind-source="login_flow_stack" bind-property="visible-child-name"
bind-flags="sync-create"/>
- <property name="transition_duration" bind-source="login_flow_stack" bind-property="transition-duration"
bind-flags="sync-create"/>
- <property name="transition_type" bind-source="login_flow_stack" bind-property="transition-type"
bind-flags="sync-create"/>
- <child>
- <object class="GtkHeaderBar" id="login_greeter_header">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="show_close_button">True</property>
- <property name="title" translatable="yes">Fractal</property>
- </object>
- <packing>
- <property name="name">greeter</property>
- </packing>
- </child>
- <child>
- <object class="GtkHeaderBar" id="login_server_chooser_header">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="show_close_button">True</property>
- <property name="width_request">360</property>
- <property name="title" translatable="yes">Choose Provider</property>
- <child>
- <object class="GtkButton">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="action_name">login.back</property>
<child>
- <object class="GtkImage">
+ <object class="GtkBox">
<property name="visible">True</property>
- <property name="icon_name">go-previous-symbolic</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkEntry" id="username_entry">
+ <property name="visible">True</property>
+ <property name="max_width_chars">-1</property>
+ <property name="width_request">232</property>
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">User name, email, or phone number</property>
+ <property name="halign">start</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
+ <style>
+ <class name="dim-label"/>
+ <class name="small-font"/>
+ </style>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="left-attach">1</property>
+ <property name="height">2</property>
+ </packing>
</child>
- </object>
- <packing>
- <property name="pack_type">start</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton">
- <property name="visible">True</property>
- <property name="use_underline">True</property>
- <property name="can_focus">True</property>
- <property name="action_name">login.credentials</property>
- <property name="label" translatable="yes">_Next</property>
- <style>
- <class name="suggested-action"/>
- </style>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="name">server-chooser</property>
- </packing>
- </child>
- <child>
- <object class="GtkHeaderBar" id="login_credentials_header">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="show_close_button">True</property>
- <property name="title" translatable="yes">Log In</property>
- <child>
- <object class="GtkButton">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="action_name">login.back</property>
<child>
- <object class="GtkImage">
+ <object class="GtkEntry" id="password_entry">
<property name="visible">True</property>
- <property name="icon_name">go-previous-symbolic</property>
+ <property name="max_width_chars">-1</property>
+ <property name="width_request">232</property>
+ <property name="can_focus">True</property>
+ <property name="visibility">False</property>
+ <property name="input_purpose">GTK_INPUT_PURPOSE_PASSWORD</property>
</object>
+ <packing>
+ <property name="top-attach">3</property>
+ <property name="left-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLinkButton" id="forgot_password">
+ <property name="use_underline">True</property>
+ <property name="label" translatable="yes">_Forgot Password?</property>
+ <property name="uri">https://riot.im/app/#/login</property>
+ <property name="halign">start</property>
+ <style>
+ <class name="forgot-password"/>
+ </style>
+ </object>
+ <packing>
+ <property name="top-attach">4</property>
+ <property name="left-attach">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="credentials_err_label">
+ <property name="visible">False</property>
+ <property name="can_focus">False</property>
+ <property name="no_show_all">True</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Invalid username or password</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
+ <style>
+ <class name="error-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="top-attach">5</property>
+ <property name="left-attach">1</property>
+ </packing>
</child>
</object>
<packing>
- <property name="pack_type">start</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton">
- <property name="visible">True</property>
- <property name="use_underline">True</property>
- <property name="can_focus">True</property>
- <property name="action_name">login.login</property>
- <property name="label" translatable="yes">_Log In</property>
- <style>
- <class name="suggested-action"/>
- </style>
- </object>
- <packing>
- <property name="pack_type">end</property>
+ <property name="name">credentials</property>
</packing>
</child>
</object>
diff --git a/fractal-gtk/res/ui/main_window.ui b/fractal-gtk/res/ui/main_window.ui
index 4762cd2f..105da575 100644
--- a/fractal-gtk/res/ui/main_window.ui
+++ b/fractal-gtk/res/ui/main_window.ui
@@ -2,610 +2,699 @@
<!-- Generated with glade 3.20.2 -->
<interface>
<requires lib="gtk+" version="3.20"/>
- <object class="GtkApplicationWindow" id="main_window">
+ <object class="HdyApplicationWindow" id="main_window">
<property name="can_focus">False</property>
<property name="default_width">860</property>
<property name="default_height">640</property>
<property name="show_menubar">False</property>
<child>
- <object class="GtkStack" id="main_content_stack">
- <property name="can_focus">False</property>
- <property name="hhomogeneous">False</property>
+ <object class="GtkBox">
+ <property name="visible">True</property>
<child>
- <object class="HdyLeaflet" id="chat_state_leaflet">
- <property name="can-swipe-back" bind-source="header_leaflet" bind-property="can-swipe-back"
bind-flags="bidirectional|sync-create"/>
- <property name="child-transition-duration" bind-source="header_leaflet"
bind-property="child-transition-duration" bind-flags="bidirectional|sync-create"/>
- <property name="mode-transition-duration" bind-source="header_leaflet"
bind-property="mode-transition-duration" bind-flags="bidirectional|sync-create"/>
- <property name="transition-type" bind-source="header_leaflet" bind-property="transition-type"
bind-flags="bidirectional|sync-create"/>
- <property name="visible">True</property>
+ <object class="GtkStack" id="main_content_stack">
<property name="can_focus">False</property>
- <property name="hhomogeneous-folded">True</property>
+ <property name="hhomogeneous">False</property>
<child>
- <object class="GtkBox" id="sidebar-box">
- <property name="width_request">200</property>
+ <object class="HdyDeck" id="main_deck">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">fill</property>
- <property name="hexpand">False</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkSearchBar" id="room_list_searchbar">
- <property name="width_request">200</property>
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkSearchEntry" id="room_list_search">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="primary_icon_name">edit-find-symbolic</property>
- <property name="primary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">False</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
+ <property name="expand">True</property>
+ <property name="can_swipe_back">True</property>
+ <property name="visible_child_name">chat</property>
+ <property name="hhomogeneous">False</property>
<child>
- <object class="GtkScrolledWindow" id="roomlist_scroll">
- <property name="width_request">200</property>
+ <object class="HdyLeaflet" id="chat_page">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
+ <property name="visible_child">room_list</property>
+ <property name="can_swipe_back">True</property>
<child>
- <object class="GtkViewport">
- <property name="width_request">200</property>
+ <object class="GtkBox" id="room_list">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="shadow_type">none</property>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkBox" id="room_container">
+ <object class="HdyHeaderBar" id="left-header"> <!--left titlebar-->
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="orientation">vertical</property>
+ <property name="halign">fill</property>
+ <property name="show-close-button">True</property>
<child>
- <placeholder/>
+ <object class="GtkMenuButton" id="main_menu_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="popover">user_popover</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>
+ <accessibility>
+
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-main_menu_button">
+ <property name="AtkObject::accessible_name"
translatable="yes">User</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="add_room_menu">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="popover">add_room_popover</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">list-add-symbolic</property>
+ </object>
+ </child>
+ <accessibility>
+
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-add_room_menu">
+ <property name="AtkObject::accessible_name"
translatable="yes">Add</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToggleButton" id="room_search_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">system-search-symbolic</property>
+ </object>
+ </child>
+ <accelerator key="k" signal="activate" modifiers="GDK_CONTROL_MASK"/>
+ <style>
+ <class name="room-search-button"/>
+ </style>
+ <accessibility>
+
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-room_search_button">
+ <property name="AtkObject::accessible_name" translatable="yes">Room
search</property>
+ </object>
+ </child>
+ </object>
</child>
- <style>
- <class name="rooms-sidebar"/>
- <class name="sidebar"/>
- </style>
</object>
</child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="name">sidebar</property>
- </packing>
- </child>
- <child>
- <object class="GtkSeparator" id="content_separator">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <style>
- <class name="sidebar"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkOverlay" id="inapp">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkStack" id="room_view_stack">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkBox" id="focused_room">
- <property name="name">room</property>
- <property name="can_focus">False</property>
<child>
- <object class="GtkBox">
+ <object class="GtkBox" id="sidebar-box">
+ <property name="width_request">200</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="halign">fill</property>
+ <property name="hexpand">False</property>
+ <property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
- <object class="GtkBox" id="history_container">
+ <object class="GtkSearchBar" id="room_list_searchbar">
+ <property name="width_request">200</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkSearchEntry" id="room_list_search">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="primary_icon_name">edit-find-symbolic</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">False</property>
+ </object>
+ </child>
</object>
<packing>
- <property name="expand">True</property>
+ <property name="expand">False</property>
<property name="fill">True</property>
- <property name="position">1</property>
+ <property name="position">0</property>
</packing>
</child>
<child>
- <object class="GtkBox" id="room_parent">
+ <object class="GtkScrolledWindow" id="roomlist_scroll">
+ <property name="width_request">200</property>
<property name="visible">True</property>
- <style>
- <class name="message-input-area" />
- </style>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="width_request">200</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkBox" id="room_container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <placeholder/>
+ </child>
+ <style>
+ <class name="rooms-sidebar"/>
+ <class name="sidebar"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
+ <packing>
+ <property name="expand">True</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>
</object>
<packing>
- <property name="name">room_view</property>
- <property name="title">room_view</property>
+ <property name="name">sidebar</property>
</packing>
</child>
<child>
- <object class="GtkSpinner">
+ <object class="GtkSeparator" id="header_separator">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="active">True</property>
+ <property name="orientation">vertical</property>
+ <style>
+ <class name="sidebar"/>
+ </style>
</object>
<packing>
- <property name="name">loading</property>
- <property name="title">loading</property>
- <property name="position">1</property>
+ <property name="navigatable">False</property>
</packing>
</child>
<child>
- <object class="GtkBox">
+ <object class="GtkBox" id="room_view">
<property name="visible">True</property>
- <property name="can_focus">False</property>
<property name="orientation">vertical</property>
- <property name="margin_bottom">30</property>
- <property name="valign">center</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_bottom">16</property>
- <property name="resource">/org/gnome/Fractal/icons/chat-icon.svg</property>
- </object>
- </child>
<child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">No room selected</property>
- <property name="margin_bottom">3</property>
- <property name="justify">center</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- </attributes>
- <style>
- <class name="noroom-title"/>
- </style>
+ <object class="HdyHeaderBar" id="room_header_bar"> <!--right titlebar-->
+ <property name="show-close-button">True</property>
+ <property name="has-subtitle">False</property>
+ <property name="hexpand">true</property>
+ <property name="width-request">360</property>
+ <child>
+ <object class="GtkRevealer">
+ <property name="reveal-child" bind-source="chat_page" bind-property="folded"
bind-flags="sync-create"/>
+ <property name="transition-duration" bind-source="chat_page"
bind-property="mode-transition-duration" bind-flags="bidirectional|sync-create"/>
+ <property name="transition-type">crossfade</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkButton" id="leaflet_back_button">
+ <property name="action_name">app.back</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">go-previous-symbolic</property>
+ </object>
+ </child>
+ <accessibility>
+
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-leaflet_back_button">
+ <property name="AtkObject::accessible_name"
translatable="yes">Back</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="title">
+ <object class="GtkScrolledWindow">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="valign">center</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">never</property>
+ <property name="propagate_natural_height">True</property>
+ <property name="propagate_natural_width">False</property>
+ <child>
+ <object class="GtkBox" id="room_info">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="room_name">
+ <property name="can_focus">False</property>
+ <!-- Translators: This string is replaced not user-visible -->
+ <property name="label">Room name</property>
+ <property name="ellipsize">end</property>
+ <style>
+ <class name="title"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="room_topic">
+ <property name="can_focus">False</property>
+ <!-- Translators: This string is replaced not user-visible -->
+ <property name="label">Room topic</property>
+ <property name="ellipsize">end</property>
+ <style>
+ <class name="subtitle"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="room_menu_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="popover">room_popover</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>
+ <accessibility>
+ </accessibility>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-room_menu_button">
+ <property name="AtkObject::accessible_name" translatable="yes">Room
Menu</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
</object>
</child>
<child>
- <object class="GtkLabel">
+ <object class="GtkOverlay" id="inapp">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="label" translatable="yes">Join a room to start
chatting</property>
- <property name="justify">center</property>
- <style>
- <class name="noroom-description"/>
- </style>
- </object>
- </child>
- </object>
- <packing>
- <property name="name">noroom</property>
- <property name="title" translatable="yes">No room</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="index">-1</property>
- </packing>
- </child>
- <child type="overlay">
- <object class="GtkOverlay" id="inapp_notify">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="valign">start</property>
- <property name="halign">center</property>
- <child>
- <object class="GtkRevealer" id="inapp_revealer">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">center</property>
- <child>
- <object class="GtkFrame" id="inapp_frame">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label_xalign">0</property>
- <property name="shadow_type">none</property>
<child>
- <object class="GtkBox" id="inapp_box">
+ <object class="GtkStack" id="room_view_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="spacing">10</property>
<child>
- <object class="GtkSpinner" id="inapp_spinner">
+ <object class="GtkBox" id="focused_room">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="history_container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="room_parent">
+ <property name="visible">True</property>
+ <style>
+ <class name="message-input-area" />
+ </style>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">room_view</property>
+ <property name="title">room_view</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinner">
<property name="visible">True</property>
- <property name="active">True</property>
<property name="can_focus">False</property>
+ <property name="active">True</property>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
+ <property name="name">loading</property>
+ <property name="title">loading</property>
+ <property name="position">1</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="inapp_label">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="margin_bottom">30</property>
+ <property name="valign">center</property>
+ <property name="expand">True</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_bottom">16</property>
+ <property
name="resource">/org/gnome/Fractal/icons/chat-icon.svg</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">No room selected</property>
+ <property name="margin_bottom">3</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ <style>
+ <class name="noroom-title"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Join a room to start
chatting</property>
+ <property name="justify">center</property>
+ <style>
+ <class name="noroom-description"/>
+ </style>
+ </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>
+ <property name="name">noroom</property>
+ <property name="title" translatable="yes">No room</property>
+ <property name="position">2</property>
</packing>
</child>
</object>
+ <packing>
+ <property name="index">-1</property>
+ </packing>
</child>
- <child type="label_item">
- <placeholder/>
- </child>
- <style>
- <class name="app-notification"/>
- </style>
- </object>
- </child>
- </object>
- <packing>
- <property name="pass_through">True</property>
- <property name="index">-1</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="name">content</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="name">chat</property>
- <property name="title" translatable="yes">Chat</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="directory_state">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkScrolledWindow" id="directory_scroll">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hscrollbar_policy">never</property>
- <child>
- <object class="GtkViewport">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkStack" id="directory_stack">
- <property name="can_focus">False</property>
- <child>
- <object class="GtkBox" id="directory_spinner">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkSpinner">
+ <child type="overlay">
+ <object class="GtkOverlay" id="inapp_notify">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="active">True</property>
+ <property name="valign">start</property>
+ <property name="halign">center</property>
+ <child>
+ <object class="GtkRevealer" id="inapp_revealer">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <child>
+ <object class="GtkFrame" id="inapp_frame">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkBox" id="inapp_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkSpinner" id="inapp_spinner">
+ <property name="visible">True</property>
+ <property name="active">True</property>
+ <property name="can_focus">False</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="inapp_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child type="label_item">
+ <placeholder/>
+ </child>
+ <style>
+ <class name="app-notification"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pass_through">True</property>
+ <property name="index">-1</property>
+ </packing>
+ </child>
</object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
</child>
</object>
</child>
</object>
- </child>
- </object>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="name">directory</property>
- <property name="title" translatable="yes">Directory</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="loading_state">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkSpinner">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="active">True</property>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="name">loading</property>
- <property name="title" translatable="yes">Loading</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- </child>
- <child type="titlebar">
- <object class="HdyTitleBar">
- <property name="visible">True</property>
- <child>
- <object class="GtkStack" id="headerbar_stack">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">True</property>
- <property name="hhomogeneous">False</property>
- <child>
- <object class="HdyLeaflet" id="header_leaflet"> <!--message view-->
- <property name="visible">True</property>
- <property name="can-swipe-back">True</property>
- <property name="transition-type">over</property>
- <property name="hhomogeneous-folded">True</property>
- <child>
- <object class="GtkHeaderBar" id="left-header"> <!--left titlebar-->
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="halign">fill</property>
- <property name="show-close-button">True</property>
- <child>
- <object class="GtkMenuButton" id="main_menu_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="popover">user_popover</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>
- <accessibility>
-
- </accessibility>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-main_menu_button">
- <property name="AtkObject::accessible_name" translatable="yes">User</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack_type">end</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkMenuButton" id="add_room_menu">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="popover">add_room_popover</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">list-add-symbolic</property>
- </object>
- </child>
- <accessibility>
-
- </accessibility>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-add_room_menu">
- <property name="AtkObject::accessible_name" translatable="yes">Add</property>
- </object>
- </child>
- </object>
<packing>
- <property name="pack_type">end</property>
- <property name="position">1</property>
+ <property name="name">content</property>
</packing>
</child>
- <child>
- <object class="GtkToggleButton" id="room_search_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">system-search-symbolic</property>
- </object>
- </child>
- <accelerator key="k" signal="activate" modifiers="GDK_CONTROL_MASK"/>
- <style>
- <class name="room-search-button"/>
- </style>
- <accessibility>
-
- </accessibility>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-room_search_button">
- <property name="AtkObject::accessible_name" translatable="yes">Room
search</property>
- </object>
- </child>
- </object>
- </child>
</object>
<packing>
- <property name="name">sidebar</property>
+ <property name="name">chat</property>
</packing>
</child>
<child>
- <object class="GtkSeparator" id="header_separator">
- <property name="visible">True</property>
+ <object class="GtkStack" id="subview_stack">
<property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <style>
- <class name="sidebar"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkHeaderBar" id="room_header_bar"> <!--right titlebar-->
- <property name="show-close-button">True</property>
- <property name="has-subtitle">False</property>
- <property name="hexpand">true</property>
- <property name="width-request">360</property>
+ <property name="hhomogeneous">False</property>
<child>
- <object class="GtkRevealer">
- <property name="reveal-child" bind-source="header_leaflet" bind-property="folded"
bind-flags="sync-create"/>
- <property name="transition-duration" bind-source="header_leaflet"
bind-property="mode-transition-duration" bind-flags="bidirectional|sync-create"/>
- <property name="transition-type">crossfade</property>
+ <object class="GtkBox">
<property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkButton" id="leaflet_back_button">
- <property name="action_name">app.back</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
+ <object class="HdyHeaderBar">
+ <property name="can_focus">False</property>
+ <property name="show_close_button">True</property>
+ <property name="width_request">360</property>
+ <property name="centering_policy">HDY_CENTERING_POLICY_STRICT</property>
<child>
- <object class="GtkImage">
+ <object class="GtkButton" id="back_button">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">go-previous-symbolic</property>
- </object>
- </child>
- <accessibility>
-
- </accessibility>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-leaflet_back_button">
- <property name="AtkObject::accessible_name"
translatable="yes">Back</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="action_name">app.deck-back</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>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="back_button-atkobject">
+ <property name="AtkObject::accessible-name"
translatable="yes">Back</property>
+ </object>
+ </child>
</object>
</child>
- </object>
- </child>
- </object>
- </child>
- <child type="title">
- <object class="GtkScrolledWindow">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">True</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">never</property>
- <property name="propagate_natural_height">True</property>
- <property name="propagate_natural_width">False</property>
- <child>
- <object class="GtkBox" id="room_info">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel" id="room_name">
+ <child type="title">
+ <object class="HdyClamp">
<property name="can_focus">False</property>
- <!-- Translators: This string is replaced not user-visible -->
- <property name="label">Room name</property>
- <property name="ellipsize">end</property>
- <style>
- <class name="title"/>
- </style>
+ <property name="visible">True</property>
+ <property name="maximum_size">288</property>
+ <property name="tightening_threshold">288</property>
+ <child>
+ <object class="GtkSearchEntry" id="directory_search_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hexpand">True</property>
+ <property name="primary_icon_name">edit-find-symbolic</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">False</property>
+ </object>
+ </child>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
</child>
<child>
- <object class="GtkLabel" id="room_topic">
- <property name="can_focus">False</property>
- <!-- Translators: This string is replaced not user-visible -->
- <property name="label">Room topic</property>
- <property name="ellipsize">end</property>
- <style>
- <class name="subtitle"/>
- </style>
+ <object class="GtkMenuButton" id="server_chooser_menu">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="popover">server_chooser_popover</property>
+ <child>
+ <object class="HdySqueezer">
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="directory_choice_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Default Matrix
Server</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">pan-down-symbolic</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">network-server-symbolic</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">pan-down-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
<packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
+ <property name="pack_type">end</property>
</packing>
</child>
</object>
</child>
- </object>
- </child>
- <child>
- <object class="GtkMenuButton" id="room_menu_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="popover">room_popover</property>
<child>
- <object class="GtkImage">
+ <object class="GtkBox" id="directory_state">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="icon_name">view-more-symbolic</property>
- </object>
- </child>
- <accessibility>
- </accessibility>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-room_menu_button">
- <property name="AtkObject::accessible_name" translatable="yes">Room
Menu</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow" id="directory_scroll">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="expand">True</property>
+ <property name="halign">fill</property>
+ <property name="valign">fill</property>
+ <child>
+ <object class="GtkViewport">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkStack" id="directory_stack">
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkBox" id="directory_spinner">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkSpinner">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="active">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
</object>
</child>
</object>
<packing>
- <property name="pack_type">end</property>
- <property name="position">1</property>
+ <property name="name">directory</property>
</packing>
</child>
</object>
<packing>
- <property name="name">content</property>
+ <property name="name">subview</property>
</packing>
</child>
</object>
<packing>
- <property name="name">normal</property>
- <property name="title">normal</property>
- <property name="position">1</property>
+ <property name="name">main_view</property>
</packing>
</child>
<child>
@@ -614,147 +703,34 @@
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
- <object class="GtkHeaderBar">
+ <object class="HdyHeaderBar">
<property name="can_focus">False</property>
<property name="show-close-button">True</property>
<property name="title">Fractal</property>
</object>
</child>
- </object>
- <packing>
- <property name="name">loading</property>
- <property name="title">loading</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
<child>
- <object class="HdyHeaderBar">
+ <object class="GtkBox" id="loading_state">
+ <property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="show_close_button">True</property>
- <property name="width_request">360</property>
- <property name="centering_policy">HDY_CENTERING_POLICY_STRICT</property>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkButton" id="back_button">
+ <object class="GtkSpinner">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="action_name">app.back</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>
- <child internal-child="accessible">
- <object class="AtkObject" id="back_button-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">Back</property>
- </object>
- </child>
- </object>
- </child>
- <child type="title">
- <object class="HdyClamp">
<property name="can_focus">False</property>
- <property name="visible">True</property>
- <property name="maximum_size">288</property>
- <property name="tightening_threshold">288</property>
- <child>
- <object class="GtkSearchEntry" id="directory_search_entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="hexpand">True</property>
- <property name="primary_icon_name">edit-find-symbolic</property>
- <property name="primary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">False</property>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkMenuButton" id="server_chooser_menu">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="popover">server_chooser_popover</property>
- <child>
- <object class="HdySqueezer">
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkLabel" id="directory_choice_label">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="label" translatable="yes">Default Matrix
Server</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">pan-down-symbolic</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">network-server-symbolic</property>
- </object>
- </child>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">pan-down-symbolic</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
+ <property name="active">True</property>
+ <property name="expand">True</property>
+ <property name="valign">fill</property>
+ <property name="halign">fill</property>
</object>
<packing>
- <property name="pack_type">end</property>
</packing>
</child>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
</child>
</object>
<packing>
- <property name="name">back</property>
- <property name="title" translatable="yes">Back</property>
- <property name="position">2</property>
+ <property name="name">loading</property>
</packing>
</child>
</object>
@@ -765,38 +741,10 @@
<class name="main-window"/>
</style>
</object>
-<!-- Synchronize left header and sidebar -->
- <object class="GtkSizeGroup">
- <property name="mode">horizontal</property>
- <widgets>
- <widget name="left-header"/>
- <widget name="sidebar-box"/>
- </widgets>
- </object>
- <object class="GtkSizeGroup">
- <property name="mode">horizontal</property>
- <widgets>
- <widget name="inapp"/>
- <widget name="room_header_bar"/>
- </widgets>
- </object>
- <object class="GtkSizeGroup">
- <property name="mode">horizontal</property>
- <widgets>
- <widget name="header_separator"/>
- <widget name="content_separator"/>
- </widgets>
- </object>
<object class="HdyHeaderGroup">
<headerbars>
<headerbar name="left-header"/>
<headerbar name="room_header_bar"/>
</headerbars>
</object>
- <object class="HdySwipeGroup" id="swipe_group">
- <swipeables>
- <swipeable name="chat_state_leaflet"/>
- <swipeable name="header_leaflet"/>
- </swipeables>
- </object>
</interface>
diff --git a/fractal-gtk/res/ui/media_viewer.ui b/fractal-gtk/res/ui/media_viewer.ui
index 3ecf81a5..4ebdaf56 100644
--- a/fractal-gtk/res/ui/media_viewer.ui
+++ b/fractal-gtk/res/ui/media_viewer.ui
@@ -5,7 +5,84 @@
<object class="GtkBox" id="media_viewer_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="homogeneous">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkBox" id="media_viewer_headerbar_box">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <child>
+ <object class="GtkHeaderBar" id="media_viewer_headerbar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <!-- Translators: This string is replaced not user-visible -->
+ <property name="title">Media viewer</property>
+ <property name="show_close_button">True</property>
+ <child>
+ <object class="GtkButton" id="media_viewer_back_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="action_name">app.deck-back</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>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="media_viewer_back_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Back</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkMenuButton" id="media_viewer_menu_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">view-more-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="full_screen_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="tooltip_text" translatable="yes">Toggle fullscreen</property>
+ <child>
+ <object class="GtkImage" id="full_screen_button_icon">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">view-fullscreen-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="pack_type">end</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
<child>
<object class="GtkOverlay">
<property name="visible">True</property>
@@ -208,79 +285,4 @@
</packing>
</child>
</object>
- <object class="GtkBox" id="media_viewer_headerbar_box">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkHeaderBar" id="media_viewer_headerbar">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <!-- Translators: This string is replaced not user-visible -->
- <property name="title">Media viewer</property>
- <property name="show_close_button">True</property>
- <child>
- <object class="GtkButton" id="media_viewer_back_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="action_name">app.back</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>
- <child internal-child="accessible">
- <object class="AtkObject" id="media_viewer_back_button-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">Back</property>
- </object>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkMenuButton" id="media_viewer_menu_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">view-more-symbolic</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack_type">end</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="full_screen_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="tooltip_text" translatable="yes">Toggle fullscreen</property>
- <child>
- <object class="GtkImage" id="full_screen_button_icon">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">view-fullscreen-symbolic</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
</interface>
diff --git a/fractal-gtk/res/ui/room_settings.ui b/fractal-gtk/res/ui/room_settings.ui
index 5d91404b..1832290b 100644
--- a/fractal-gtk/res/ui/room_settings.ui
+++ b/fractal-gtk/res/ui/room_settings.ui
@@ -5,9 +5,39 @@
<object class="GtkBox" id="room_settings_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="HdyHeaderBar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="show_close_button">True</property>
+ <property name="title" translatable="yes">Details</property>
+ <child>
+ <object class="GtkButton" id="room_settings_back_button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="action_name">app.deck-back</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>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="room_settings_back_button-atkobject">
+ <property name="AtkObject::accessible-name" translatable="yes">Back</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
<child>
<object class="GtkScrolledWindow" id="room_settings_scroll">
<property name="visible">True</property>
+ <property name="expand">True</property>
<property name="can_focus">True</property>
<property name="hscrollbar_policy">never</property>
<child>
@@ -999,44 +1029,6 @@
</object>
</child>
</object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
- <object class="GtkBox" id="room_settings_headerbar">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkHeaderBar">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="show_close_button">True</property>
- <property name="expand">True</property>
- <property name="title" translatable="yes">Details</property>
- <child>
- <object class="GtkButton" id="room_settings_back_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <property name="action_name">app.back</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>
- <child internal-child="accessible">
- <object class="AtkObject" id="room_settings_back_button-atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">Back</property>
- </object>
- </child>
- </object>
- </child>
- </object>
</child>
</object>
</interface>
diff --git a/fractal-gtk/src/actions/global.rs b/fractal-gtk/src/actions/global.rs
index 3d2b5d47..a18afe0a 100644
--- a/fractal-gtk/src/actions/global.rs
+++ b/fractal-gtk/src/actions/global.rs
@@ -13,8 +13,9 @@ use fractal_api::identifiers::{EventId, RoomId};
use gio::prelude::*;
use gio::SimpleAction;
use gtk::prelude::*;
+use libhandy::prelude::*;
-#[derive(Debug, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq)]
pub enum AppState {
Login,
Loading,
@@ -81,6 +82,7 @@ pub fn new(app: >k::Application, op: &Arc<Mutex<AppOp>>) {
let main_menu = SimpleAction::new("main_menu", None);
let open_room = SimpleAction::new("open-room", glib::VariantTy::new("s").ok());
+ let deck_back = SimpleAction::new("deck-back", None);
let back = SimpleAction::new("back", None);
let media_viewer = SimpleAction::new("open-media-viewer", glib::VariantTy::new("s").ok());
let account = SimpleAction::new("open-account-settings", None);
@@ -115,6 +117,7 @@ pub fn new(app: >k::Application, op: &Arc<Mutex<AppOp>>) {
app.add_action(&shortcuts);
app.add_action(&about);
app.add_action(&open_room);
+ app.add_action(&deck_back);
app.add_action(&back);
app.add_action(&directory);
app.add_action(&room_settings);
@@ -264,6 +267,13 @@ pub fn new(app: >k::Application, op: &Arc<Mutex<AppOp>>) {
back.borrow_mut().push(AppState::MediaViewer);
}));
+ deck_back.connect_activate(clone!(@strong op => move |_, _| {
+ let deck = op.lock().unwrap().deck.clone();
+ if deck.get_can_swipe_back() {
+ deck.navigate(libhandy::NavigationDirection::Back);
+ }
+ }));
+
let mv = op.lock().unwrap().media_viewer.clone();
let back_weak = Rc::downgrade(&back_history);
back.connect_activate(clone!(@weak mv => move |_, _| {
@@ -389,7 +399,7 @@ pub fn activate_action(action_group_name: &str, action_name: &str) {
.unwrap()
.ui
.builder
- .get_object::<gtk::Window>("main_window")
+ .get_object::<libhandy::ApplicationWindow>("main_window")
.expect("Can't find main_window in ui file.");
if let Some(action_group) = main_window.get_action_group(action_group_name) {
action_group.activate_action(action_name, None);
diff --git a/fractal-gtk/src/actions/login.rs b/fractal-gtk/src/actions/login.rs
index 8bac5a90..e4c007d0 100644
--- a/fractal-gtk/src/actions/login.rs
+++ b/fractal-gtk/src/actions/login.rs
@@ -1,3 +1,4 @@
+use libhandy::prelude::*;
use log::{debug, warn};
use std::cell::RefCell;
use std::rc::Rc;
@@ -41,8 +42,7 @@ impl ToString for LoginState {
}
pub fn new(
- stack: >k::Stack,
- headers: >k::Stack,
+ deck: &libhandy::Deck,
server_entry: >k::Entry,
err_label: >k::Label,
) -> SimpleActionGroup {
@@ -60,8 +60,8 @@ pub fn new(
actions.add_action(&back);
actions.add_action(&login);
- create_account.connect_activate(clone!(@weak stack => move |_, _| {
- let toplevel = stack
+ create_account.connect_activate(clone!(@weak deck => move |_, _| {
+ let toplevel = deck
.get_toplevel()
.expect("Could not grab toplevel widget")
.downcast::<gtk::Window>()
@@ -73,40 +73,25 @@ pub fn new(
}
}));
- let back_history: Rc<RefCell<Vec<LoginState>>> = Rc::new(RefCell::new(vec![]));
-
- server_chooser.connect_activate(
- clone!(@weak stack, @weak back_history as back => move |_, _| {
- let state = LoginState::ServerChooser;
- stack.set_visible_child_name(&state.to_string());
- back.borrow_mut().push(state);
- }),
- );
+ server_chooser.connect_activate(clone!(@weak deck => move |_, _| {
+ deck.navigate(libhandy::NavigationDirection::Forward);
+ }));
credentials.connect_activate(clone!(
- @weak stack,
- @weak back_history as back,
+ @weak err_label,
@weak server_entry,
- @weak err_label
- => move |_, _| {
+ @weak deck => move |_, _| {
if server_entry.get_text().is_empty() {
err_label.show();
} else {
err_label.hide();
- let state = LoginState::Credentials;
- stack.set_visible_child_name(&state.to_string());
- back.borrow_mut().push(state);
+ deck.navigate(libhandy::NavigationDirection::Forward);
}
}));
- back.connect_activate(clone!(@weak stack => move |_, _| {
- back_history.borrow_mut().pop();
- if let Some(state) = back_history.borrow().last() {
- debug!("Go back to state {}", state.to_string());
- stack.set_visible_child_name(&state.to_string());
- } else {
- debug!("There is no state to go back to. Go back to state greeter");
- stack.set_visible_child_name(&LoginState::Greeter.to_string());
+ back.connect_activate(clone!(@weak deck => move |_, _| {
+ if let Some(_) = deck.get_adjacent_child(libhandy::NavigationDirection::Back) {
+ deck.navigate(libhandy::NavigationDirection::Back);
}
}));
@@ -123,8 +108,7 @@ pub fn new(
})
});
- stack.insert_action_group("login", Some(&actions));
- headers.insert_action_group("login", Some(&actions));
+ deck.insert_action_group("login", Some(&actions));
actions
}
diff --git a/fractal-gtk/src/actions/message.rs b/fractal-gtk/src/actions/message.rs
index d08d2f2d..7ccb496c 100644
--- a/fractal-gtk/src/actions/message.rs
+++ b/fractal-gtk/src/actions/message.rs
@@ -63,13 +63,13 @@ pub fn new(
actions.add_action(&show_source);
actions.add_action(&load_more_messages);
- let parent: gtk::Window = ui
+ let parent: libhandy::ApplicationWindow = ui
.builder
.get_object("main_window")
.expect("Can't find main_window in ui file.");
show_source.connect_activate(clone!(@weak parent => move |_, data| {
let viewer = SourceDialog::new();
- viewer.set_parent_window(&parent);
+ viewer.set_parent_window(&parent.upcast_ref());
if let Some(m) = get_message(data) {
let error = i18n("This message has no source.");
let source = m.source.as_ref().unwrap_or(&error);
@@ -80,7 +80,7 @@ pub fn new(
let window = ui
.builder
- .get_object::<gtk::ApplicationWindow>("main_window")
+ .get_object::<libhandy::ApplicationWindow>("main_window")
.expect("Couldn't find main_window in ui file.");
reply.connect_activate(clone!(
@weak back_history,
@@ -162,7 +162,7 @@ pub fn new(
Continue(true)
},
Ok(Ok(fname)) => {
- if let Some(path) = save(&window, &name, &[]) {
+ if let Some(path) = save(&window.upcast_ref(), &name, &[]) {
// TODO use glib to copy file
if fs::copy(fname, path).is_err() {
ErrorDialog::new(false, &i18n("Couldn’t save file"));
diff --git a/fractal-gtk/src/app/connect/autocomplete.rs b/fractal-gtk/src/app/connect/autocomplete.rs
index d7c0b9e1..a67c4b6e 100644
--- a/fractal-gtk/src/app/connect/autocomplete.rs
+++ b/fractal-gtk/src/app/connect/autocomplete.rs
@@ -16,14 +16,20 @@ impl App {
.builder
.get_object::<gtk::ListBox>("autocomplete_listbox")
.expect("Can't find autocomplete_listbox in ui file.");
- let window: gtk::Window = self
+ let window: libhandy::ApplicationWindow = self
.ui
.builder
.get_object("main_window")
.expect("Can't find main_window in ui file.");
let op = self.op.clone();
- widgets::Autocomplete::new(op, window, self.ui.sventry.view.clone(), popover, listbox)
- .connect();
+ widgets::Autocomplete::new(
+ op,
+ window.upcast(),
+ self.ui.sventry.view.clone(),
+ popover,
+ listbox,
+ )
+ .connect();
}
}
diff --git a/fractal-gtk/src/app/connect/headerbar.rs b/fractal-gtk/src/app/connect/headerbar.rs
index 961d5615..233f8661 100644
--- a/fractal-gtk/src/app/connect/headerbar.rs
+++ b/fractal-gtk/src/app/connect/headerbar.rs
@@ -6,13 +6,13 @@ use crate::app::App;
impl App {
pub fn connect_headerbars(&self) {
if let Some(set) = gtk::Settings::get_default() {
- let left_header: gtk::HeaderBar = self
+ let left_header: libhandy::HeaderBar = self
.ui
.builder
.get_object("left-header")
.expect("Can't find left-header in ui file.");
- let right_header: gtk::HeaderBar = self
+ let right_header: libhandy::HeaderBar = self
.ui
.builder
.get_object("room_header_bar")
@@ -25,8 +25,8 @@ impl App {
// Check if the close button is to the right; If not,
// change the headerbar controls
if decor_split.len() > 1 && !decor_split[1].contains("close") {
- right_header.set_show_close_button(false);
- left_header.set_show_close_button(true);
+ libhandy::HeaderBarExt::set_show_close_button(&right_header, false);
+ libhandy::HeaderBarExt::set_show_close_button(&left_header, true);
}
};
@@ -41,11 +41,11 @@ impl App {
// Change the headerbar controls depending on position
// of close
if decor_split.len() > 1 && decor_split[1].contains("close") {
- left_header.set_show_close_button(false);
- right_header.set_show_close_button(true);
+ libhandy::HeaderBarExt::set_show_close_button(&left_header, false);
+ libhandy::HeaderBarExt::set_show_close_button(&right_header, true);
} else {
- right_header.set_show_close_button(false);
- left_header.set_show_close_button(true);
+ libhandy::HeaderBarExt::set_show_close_button(&right_header, false);
+ libhandy::HeaderBarExt::set_show_close_button(&left_header, true);
}
};
}));
diff --git a/fractal-gtk/src/app/connect/mod.rs b/fractal-gtk/src/app/connect/mod.rs
index a180abed..2a2514bb 100644
--- a/fractal-gtk/src/app/connect/mod.rs
+++ b/fractal-gtk/src/app/connect/mod.rs
@@ -11,6 +11,7 @@ mod markdown;
mod new_room;
mod roomlist_search;
mod send;
+mod swipeable_widgets;
use crate::app::App;
@@ -34,5 +35,6 @@ impl App {
self.connect_direct_chat();
self.connect_roomlist_search();
+ self.connect_swipeable_widgets();
}
}
diff --git a/fractal-gtk/src/app/connect/swipeable_widgets.rs
b/fractal-gtk/src/app/connect/swipeable_widgets.rs
new file mode 100644
index 00000000..004e493c
--- /dev/null
+++ b/fractal-gtk/src/app/connect/swipeable_widgets.rs
@@ -0,0 +1,57 @@
+use gio::prelude::*;
+use gtk::prelude::*;
+use libhandy::prelude::*;
+
+use crate::app::App;
+
+impl App {
+ // Set up HdyDeck and HdyLeaflet so that swipes trigger the
+ // same behaviour as the back button.
+ pub fn connect_swipeable_widgets(&self) {
+ let deck: libhandy::Deck = self
+ .ui
+ .builder
+ .get_object("main_deck")
+ .expect("Can't find main_deck in UI file");
+ let leaflet: libhandy::Leaflet = self
+ .ui
+ .builder
+ .get_object("chat_page")
+ .expect("Can't find chat_page in UI file");
+
+ let app = gio::Application::get_default()
+ .expect("Could not get default application")
+ .downcast::<gtk::Application>()
+ .unwrap();
+
+ deck.connect_property_transition_running_notify(clone!(@weak app => move |deck| {
+ let child: Option<String> = deck.get_visible_child_name().map(|g| g.to_string());
+ if !deck.get_transition_running() && child == Some("chat".to_string()) {
+ app.activate_action("back", None);
+ }
+ }));
+
+ deck.connect_property_visible_child_notify(clone!(@weak app => move |deck| {
+ let child: Option<String> = deck.get_visible_child_name().map(|g| g.to_string());
+ if !deck.get_transition_running() && child == Some("chat".to_string()) {
+ app.activate_action("back", None);
+ }
+ }));
+
+ leaflet.connect_property_child_transition_running_notify(
+ clone!(@weak app => move |leaflet| {
+ let child: Option<String> = leaflet.get_visible_child_name().map(|g| g.to_string());
+ if !leaflet.get_child_transition_running() && child == Some("sidebar".to_string()) {
+ app.activate_action("back", None);
+ }
+ }),
+ );
+
+ leaflet.connect_property_visible_child_notify(clone!(@weak app => move |leaflet| {
+ let child: Option<String> = deck.get_visible_child_name().map(|g| g.to_string());
+ if !leaflet.get_child_transition_running() && child == Some("sidebar".to_string()) {
+ app.activate_action("back", None);
+ }
+ }));
+ }
+}
diff --git a/fractal-gtk/src/app/mod.rs b/fractal-gtk/src/app/mod.rs
index 68b7a983..54034940 100644
--- a/fractal-gtk/src/app/mod.rs
+++ b/fractal-gtk/src/app/mod.rs
@@ -41,7 +41,7 @@ macro_rules! APPOP {
// Our application struct for containing all the state we have to carry around.
// TODO: subclass gtk::Application once possible
pub struct App {
- main_window: gtk::ApplicationWindow,
+ main_window: libhandy::ApplicationWindow,
/* Add widget directly here in place of uibuilder::UI*/
ui: uibuilder::UI,
@@ -71,7 +71,7 @@ impl App {
);
let ui = uibuilder::UI::new();
- let window: gtk::ApplicationWindow = ui
+ let window: libhandy::ApplicationWindow = ui
.builder
.get_object("main_window")
.expect("Couldn't find main_window in ui file.");
@@ -98,8 +98,8 @@ impl App {
let leaflet = ui
.builder
- .get_object::<libhandy::Leaflet>("chat_state_leaflet")
- .expect("Can't find chat_state_leaflet in ui file.");
+ .get_object::<libhandy::Leaflet>("chat_page")
+ .expect("Can't find chat_page in ui file.");
let container = ui
.builder
.get_object::<gtk::Box>("history_container")
@@ -124,33 +124,28 @@ impl App {
}
}));
- let stack = ui
+ let view_stack = ui
.builder
- .get_object::<gtk::Stack>("main_content_stack")
- .expect("Can't find main_content_stack in ui file.");
- let stack_header = ui
- .builder
- .get_object::<gtk::Stack>("headerbar_stack")
- .expect("Can't find headerbar_stack in ui file.");
+ .get_object::<gtk::Stack>("subview_stack")
+ .expect("Can't find subview_stack in ui file.");
- /* Add account settings view to the main stack */
+ /* Add account settings view to the view stack */
let child = ui
.builder
.get_object::<gtk::Box>("account_settings_box")
.expect("Can't find account_settings_box in ui file.");
- let child_header = ui
- .builder
- .get_object::<gtk::Box>("account_settings_headerbar")
- .expect("Can't find account_settings_headerbar in ui file.");
- stack.add_named(&child, "account-settings");
- stack_header.add_named(&child_header, "account-settings");
+ view_stack.add_named(&child, "account-settings");
let op = Arc::new(Mutex::new(AppOp::new(ui.clone())));
+ let main_stack = ui
+ .builder
+ .get_object::<gtk::Stack>("main_content_stack")
+ .expect("Can't find main_content_stack in ui file.");
+
// Add login view to the main stack
let login = widgets::LoginWidget::new(&op);
- stack.add_named(&login.container, "login");
- stack_header.add_named(&login.headers, "login");
+ main_stack.add_named(&login.container, "login");
gtk_app.set_accels_for_action("login.back", &["Escape"]);
@@ -158,6 +153,12 @@ impl App {
OP = Some(Arc::downgrade(&op));
}
+ // TODO: Urgent: hook up with swipe signals
+ let deck = ui
+ .builder
+ .get_object::<libhandy::Deck>("main_deck")
+ .expect("Can't find main_deck in ui file");
+
actions::Global::new(gtk_app, &op);
let app = AppRef::new(Self {
@@ -186,7 +187,8 @@ impl App {
app.main_window.connect_delete_event(move |window, _| {
let settings: gio::Settings = gio::Settings::new("org.gnome.Fractal");
- let window_state = WindowState::from_window(window);
+ let w = window.upcast_ref();
+ let window_state = WindowState::from_window(w);
if let Err(err) = window_state.save_in_gsettings(&settings) {
error!("Can't save the window settings: {:?}", err);
}
diff --git a/fractal-gtk/src/appop/about.rs b/fractal-gtk/src/appop/about.rs
index 8820c36e..87d1dd42 100644
--- a/fractal-gtk/src/appop/about.rs
+++ b/fractal-gtk/src/appop/about.rs
@@ -7,7 +7,7 @@ use crate::config;
impl AppOp {
pub fn about_dialog(&self) {
- let window: gtk::ApplicationWindow = self
+ let window: libhandy::ApplicationWindow = self
.ui
.builder
.get_object("main_window")
diff --git a/fractal-gtk/src/appop/account.rs b/fractal-gtk/src/appop/account.rs
index 23f5be35..cf092469 100644
--- a/fractal-gtk/src/appop/account.rs
+++ b/fractal-gtk/src/appop/account.rs
@@ -74,7 +74,7 @@ impl AppOp {
let parent = self
.ui
.builder
- .get_object::<gtk::Window>("main_window")
+ .get_object::<libhandy::ApplicationWindow>("main_window")
.expect("Can't find main_window in ui file.");
let entry = gtk::Entry::new();
@@ -141,7 +141,7 @@ impl AppOp {
let parent = self
.ui
.builder
- .get_object::<gtk::Window>("main_window")
+ .get_object::<libhandy::ApplicationWindow>("main_window")
.expect("Can't find main_window in ui file.");
let msg = i18n("In order to add this email address, go to your inbox and follow the link you
received. Once you’ve done that, click Continue.");
@@ -200,7 +200,7 @@ impl AppOp {
let parent = self
.ui
.builder
- .get_object::<gtk::Window>("main_window")
+ .get_object::<libhandy::ApplicationWindow>("main_window")
.expect("Can't find main_window in ui file.");
let msg = error;
@@ -773,7 +773,7 @@ impl AppOp {
let parent = self
.ui
.builder
- .get_object::<gtk::Window>("main_window")
+ .get_object::<libhandy::ApplicationWindow>("main_window")
.expect("Can't find main_window in ui file.");
let msg = i18n("Are you sure you want to delete your account?");
diff --git a/fractal-gtk/src/appop/attach.rs b/fractal-gtk/src/appop/attach.rs
index 44315b98..82147a76 100644
--- a/fractal-gtk/src/appop/attach.rs
+++ b/fractal-gtk/src/appop/attach.rs
@@ -27,7 +27,7 @@ impl AppOp {
};
if let Some(pb) = scaled {
- let window: gtk::ApplicationWindow = self
+ let window: libhandy::ApplicationWindow = self
.ui
.builder
.get_object("main_window")
diff --git a/fractal-gtk/src/appop/media_viewer.rs b/fractal-gtk/src/appop/media_viewer.rs
index 8a76fee1..95a74b1a 100644
--- a/fractal-gtk/src/appop/media_viewer.rs
+++ b/fractal-gtk/src/appop/media_viewer.rs
@@ -1,4 +1,5 @@
use gtk::prelude::*;
+use libhandy::prelude::*;
use log::error;
@@ -18,19 +19,15 @@ impl AppOp {
let stack = self
.ui
.builder
- .get_object::<gtk::Stack>("main_content_stack")
- .expect("Can't find main_content_stack in ui file.");
- let stack_header = self
- .ui
- .builder
- .get_object::<gtk::Stack>("headerbar_stack")
- .expect("Can't find headerbar_stack in ui file.");
+ .get_object::<gtk::Stack>("subview_stack")
+ .expect("Can't find subview_stack in ui file.");
let main_window = self
.ui
.builder
- .get_object::<gtk::Window>("main_window")
- .expect("Can't find main_window in ui file.");
+ .get_object::<libhandy::ApplicationWindow>("main_window")
+ .expect("Can't find main_window in ui file.")
+ .upcast::<gtk::Window>();
{
let room_id = self.active_room.as_ref()?;
@@ -66,12 +63,8 @@ impl AppOp {
if let Some(widget) = stack.get_child_by_name("media-viewer") {
stack.remove(&widget);
}
- if let Some(widget) = stack_header.get_child_by_name("media-viewer") {
- stack_header.remove(&widget);
- }
stack.add_named(&body, "media-viewer");
- stack_header.add_named(&header, "media-viewer");
}
self.set_state(AppState::MediaViewer);
diff --git a/fractal-gtk/src/appop/message.rs b/fractal-gtk/src/appop/message.rs
index d81e4af4..42d7f03f 100644
--- a/fractal-gtk/src/appop/message.rs
+++ b/fractal-gtk/src/appop/message.rs
@@ -143,7 +143,7 @@ impl AppOp {
pub fn mark_last_message_as_read(&mut self, Force(force): Force) -> Option<()> {
let login_data = self.login_data.clone()?;
- let window: gtk::Window = self
+ let window: libhandy::ApplicationWindow = self
.ui
.builder
.get_object("main_window")
diff --git a/fractal-gtk/src/appop/mod.rs b/fractal-gtk/src/appop/mod.rs
index 8b7a4f1b..e5ce84df 100644
--- a/fractal-gtk/src/appop/mod.rs
+++ b/fractal-gtk/src/appop/mod.rs
@@ -116,6 +116,7 @@ pub struct AppOp {
pub directory: Vec<Room>,
pub leaflet: libhandy::Leaflet,
+ pub deck: libhandy::Deck,
pub thread_pool: ThreadPool,
pub user_info_cache: UserInfoCache,
@@ -127,8 +128,12 @@ impl AppOp {
pub fn new(ui: uibuilder::UI) -> AppOp {
let leaflet = ui
.builder
- .get_object::<libhandy::Leaflet>("header_leaflet")
- .expect("Couldn't find header_leaflet in ui file");
+ .get_object::<libhandy::Leaflet>("chat_page")
+ .expect("Couldn't find chat_page in ui file");
+ let deck = ui
+ .builder
+ .get_object::<libhandy::Deck>("main_deck")
+ .expect("Couldn't find main_deck in ui file");
AppOp {
ui,
@@ -159,6 +164,7 @@ impl AppOp {
directory: vec![],
leaflet,
+ deck,
thread_pool: ThreadPool::new(20),
user_info_cache: Arc::new(Mutex::new(
@@ -192,7 +198,7 @@ impl AppOp {
}
}
- fn get_window(&self) -> gtk::Window {
+ fn get_window(&self) -> libhandy::ApplicationWindow {
self.ui
.builder
.get_object("main_window")
diff --git a/fractal-gtk/src/appop/room.rs b/fractal-gtk/src/appop/room.rs
index 8e6bbd82..a6587ddb 100644
--- a/fractal-gtk/src/appop/room.rs
+++ b/fractal-gtk/src/appop/room.rs
@@ -363,7 +363,7 @@ impl AppOp {
}
pub fn kicked_room(&self, room_name: String, reason: String, kicker: String) {
- let parent: gtk::Window = self
+ let parent: libhandy::ApplicationWindow = self
.ui
.builder
.get_object("main_window")
diff --git a/fractal-gtk/src/appop/room_settings.rs b/fractal-gtk/src/appop/room_settings.rs
index 841e109d..d204ad85 100644
--- a/fractal-gtk/src/appop/room_settings.rs
+++ b/fractal-gtk/src/appop/room_settings.rs
@@ -8,21 +8,17 @@ use crate::widgets;
impl AppOp {
pub fn create_room_settings(&mut self) -> Option<()> {
let login_data = self.login_data.clone()?;
- let window = self
+ let window: gtk::Window = self
.ui
.builder
- .get_object::<gtk::Window>("main_window")
- .expect("Can't find main_window in ui file.");
+ .get_object::<libhandy::ApplicationWindow>("main_window")
+ .expect("Can't find main_window in ui file.")
+ .upcast::<gtk::Window>();
let stack = self
.ui
.builder
- .get_object::<gtk::Stack>("main_content_stack")
- .expect("Can't find main_content_stack in ui file.");
- let stack_header = self
- .ui
- .builder
- .get_object::<gtk::Stack>("headerbar_stack")
- .expect("Can't find headerbar_stack in ui file.");
+ .get_object::<gtk::Stack>("subview_stack")
+ .expect("Can't find subview_stack in ui file.");
{
let room = self.rooms.get(&self.active_room.clone()?)?;
@@ -33,18 +29,14 @@ impl AppOp {
login_data.server_url,
login_data.access_token,
);
- let (body, header) = panel.create()?;
+ let page = panel.create()?;
/* remove old panel */
if let Some(widget) = stack.get_child_by_name("room-settings") {
stack.remove(&widget);
}
- if let Some(widget) = stack_header.get_child_by_name("room-settings") {
- stack_header.remove(&widget);
- }
- stack.add_named(&body, "room-settings");
- stack_header.add_named(&header, "room-settings");
+ stack.add_named(&page, "room-settings");
self.room_settings = Some(panel);
}
diff --git a/fractal-gtk/src/appop/state.rs b/fractal-gtk/src/appop/state.rs
index 6a062a9b..17c150e1 100644
--- a/fractal-gtk/src/appop/state.rs
+++ b/fractal-gtk/src/appop/state.rs
@@ -1,5 +1,5 @@
use gtk::prelude::*;
-use libhandy::LeafletExt;
+use libhandy::prelude::*;
use super::RoomSearchPagination;
use crate::actions::AppState;
@@ -8,6 +8,71 @@ use crate::appop::AppOp;
impl AppOp {
pub fn set_state(&mut self, state: AppState) {
self.state = state;
+
+ match self.state {
+ AppState::Login => self.set_stack_state("login"),
+ AppState::NoRoom | AppState::Room => {
+ self.set_stack_state("main_view");
+ self.set_chat_state(state);
+ }
+ AppState::Directory => self.set_deck_state(Some("directory"), state),
+ AppState::Loading => self.set_stack_state("loading"),
+ AppState::AccountSettings => self.set_deck_state(Some("account-settings"), state),
+ AppState::RoomSettings => self.set_deck_state(Some("room-settings"), state),
+ AppState::MediaViewer => self.set_deck_state(Some("media-viewer"), state),
+ };
+
+ //set focus for room directory
+ if let AppState::Directory = self.state {
+ self.ui
+ .builder
+ .get_object::<gtk::Widget>("directory_search_entry")
+ .expect("Can't find widget to set focus in ui file.")
+ .grab_focus();
+ self.directory_pagination = RoomSearchPagination::Initial;
+ self.search_rooms();
+ }
+ }
+
+ fn set_deck_state(&self, view: Option<&str>, state: AppState) {
+ let deck = self
+ .ui
+ .builder
+ .get_object::<libhandy::Deck>("main_deck")
+ .expect("Could not find main_deck in ui file");
+ let stack = self
+ .ui
+ .builder
+ .get_object::<gtk::Stack>("subview_stack")
+ .expect("Could not find subview_stack in ui file");
+ let direction = match state {
+ AppState::Room | AppState::NoRoom => libhandy::NavigationDirection::Back,
+ _ => libhandy::NavigationDirection::Forward,
+ };
+
+ if let Some(v) = view {
+ stack.set_visible_child_name(v);
+ }
+
+ if let Some(_) = deck.get_adjacent_child(direction) {
+ deck.navigate(direction);
+ }
+ }
+
+ fn set_stack_state(&self, state: &str) {
+ self.ui
+ .builder
+ .get_object::<gtk::Stack>("main_content_stack")
+ .expect("Can't find main_content_stack in ui file.")
+ .set_visible_child_name(state);
+ }
+
+ fn set_chat_state(&mut self, state: AppState) {
+ let deck = self
+ .ui
+ .builder
+ .get_object::<libhandy::Deck>("main_deck")
+ .expect("Could not find main_deck in ui file");
let stack = self
.ui
.builder
@@ -16,74 +81,27 @@ impl AppOp {
let headerbar = self
.ui
.builder
- .get_object::<gtk::HeaderBar>("room_header_bar")
+ .get_object::<libhandy::HeaderBar>("room_header_bar")
.expect("Can't find room_header_bar in ui file.");
- let widget_name = match self.state {
- AppState::Login => "login",
+ match state {
AppState::NoRoom => {
self.set_state_no_room(&headerbar);
- self.leaflet.set_visible_child_name("sidebar");
+ self.leaflet.navigate(libhandy::NavigationDirection::Back);
stack.set_visible_child_name("noroom");
- "chat"
}
AppState::Room => {
self.set_state_room(&headerbar);
- self.leaflet.set_visible_child_name("content");
+ self.leaflet
+ .navigate(libhandy::NavigationDirection::Forward);
stack.set_visible_child_name("room_view");
- "chat"
}
- AppState::Directory => "directory",
- AppState::Loading => "loading",
- AppState::AccountSettings => "account-settings",
- AppState::RoomSettings => "room-settings",
- AppState::MediaViewer => "media-viewer",
- };
-
- self.ui
- .builder
- .get_object::<gtk::Stack>("main_content_stack")
- .expect("Can't find main_content_stack in ui file.")
- .set_visible_child_name(widget_name);
-
- //setting headerbar
- let bar_name = match self.state {
- AppState::Login => "login",
- AppState::Directory => "back",
- AppState::Loading => "loading",
- AppState::AccountSettings => "account-settings",
- AppState::RoomSettings => "room-settings",
- AppState::MediaViewer => "media-viewer",
- _ => "normal",
- };
-
- self.ui
- .builder
- .get_object::<gtk::Stack>("headerbar_stack")
- .expect("Can't find headerbar_stack in ui file.")
- .set_visible_child_name(bar_name);
-
- //set focus for views
- let widget_focus = match self.state {
- AppState::Directory => "directory_search_entry",
- _ => "",
- };
-
- if !widget_focus.is_empty() {
- self.ui
- .builder
- .get_object::<gtk::Widget>(widget_focus)
- .expect("Can't find widget to set focus in ui file.")
- .grab_focus();
- }
-
- if let AppState::Directory = self.state {
- self.directory_pagination = RoomSearchPagination::Initial;
- self.search_rooms();
+ _ => (),
}
+ libhandy::DeckExt::set_visible_child_name(&deck, "chat");
}
- fn set_state_room(&self, headerbar: >k::HeaderBar) {
+ fn set_state_room(&self, headerbar: &libhandy::HeaderBar) {
for ch in headerbar.get_children().iter() {
ch.show();
}
@@ -105,7 +123,7 @@ impl AppOp {
}
// WORKAROUND this is needed because NoRoom isn't a real app state
- fn set_state_no_room(&mut self, headerbar: >k::HeaderBar) {
+ fn set_state_no_room(&mut self, headerbar: &libhandy::HeaderBar) {
for ch in headerbar.get_children().iter() {
ch.hide();
diff --git a/fractal-gtk/src/main.rs b/fractal-gtk/src/main.rs
index db5fe211..5a10c159 100644
--- a/fractal-gtk/src/main.rs
+++ b/fractal-gtk/src/main.rs
@@ -1,3 +1,6 @@
+#[macro_use]
+extern crate glib;
+
mod backend;
mod client;
mod config;
@@ -58,6 +61,9 @@ fn main() -> Result<(), Box<dyn Error>> {
static_resources::init().expect("GResource initialization failed.");
+ gtk::init().expect("Failed to initialize GTK");
+ libhandy::init();
+
// Initialize GStreamer. This checks, among other things, what plugins are available
gst::init()?;
diff --git a/fractal-gtk/src/meson.build b/fractal-gtk/src/meson.build
index cf955208..83c2c7c6 100644
--- a/fractal-gtk/src/meson.build
+++ b/fractal-gtk/src/meson.build
@@ -66,6 +66,7 @@ app_sources = files(
'app/connect/new_room.rs',
'app/connect/roomlist_search.rs',
'app/connect/send.rs',
+ 'app/connect/swipeable_widgets.rs',
'app/mod.rs',
'app/windowstate.rs',
'appop/about.rs',
diff --git a/fractal-gtk/src/widgets/kicked_dialog.rs b/fractal-gtk/src/widgets/kicked_dialog.rs
index e89b02cb..5408a3d2 100644
--- a/fractal-gtk/src/widgets/kicked_dialog.rs
+++ b/fractal-gtk/src/widgets/kicked_dialog.rs
@@ -56,7 +56,7 @@ impl KickedDialog {
}
/* This sets the transient_for parent */
- pub fn set_parent_window(&self, parent: >k::Window) {
+ pub fn set_parent_window<P: glib::IsA<gtk::Window>>(&self, parent: &P) {
self.widgets
.msg_kicked_window
.set_transient_for(Some(parent));
diff --git a/fractal-gtk/src/widgets/login.rs b/fractal-gtk/src/widgets/login.rs
index 514ffe36..b139e67c 100644
--- a/fractal-gtk/src/widgets/login.rs
+++ b/fractal-gtk/src/widgets/login.rs
@@ -2,6 +2,7 @@ use fractal_api::url::Url;
use gio::prelude::*;
use glib::clone;
use gtk::prelude::*;
+use libhandy::prelude::*;
use log::info;
use crate::actions;
@@ -18,8 +19,7 @@ use std::sync::{Arc, Mutex};
#[derive(Debug, Clone)]
pub struct LoginWidget {
- pub container: gtk::Stack,
- pub headers: gtk::Stack,
+ pub container: libhandy::Deck,
pub server_entry: gtk::Entry,
pub username_entry: gtk::Entry,
pub password_entry: gtk::Entry,
@@ -157,8 +157,7 @@ impl Default for LoginWidget {
fn default() -> Self {
let builder = gtk::Builder::from_resource("/org/gnome/Fractal/ui/login_flow.ui");
- let container: gtk::Stack = builder.get_object("login_flow_stack").unwrap();
- let headers: gtk::Stack = builder.get_object("login_flow_headers").unwrap();
+ let container: libhandy::Deck = builder.get_object("login_flow_deck").unwrap();
let server_entry = builder.get_object("server_chooser_entry").unwrap();
let username_entry = builder.get_object("username_entry").unwrap();
let password_entry = builder.get_object("password_entry").unwrap();
@@ -166,14 +165,12 @@ impl Default for LoginWidget {
let server_err_label = builder.get_object("server_err_label").unwrap();
let credentials_err_label = builder.get_object("credentials_err_label").unwrap();
- let actions = actions::Login::new(&container, &headers, &server_entry, &server_err_label);
+ let actions = actions::Login::new(&container, &server_entry, &server_err_label);
container.show_all();
- headers.show_all();
LoginWidget {
container,
- headers,
server_entry,
username_entry,
password_entry,
diff --git a/fractal-gtk/src/widgets/room_settings.rs b/fractal-gtk/src/widgets/room_settings.rs
index d0d8ee2e..2594f21b 100644
--- a/fractal-gtk/src/widgets/room_settings.rs
+++ b/fractal-gtk/src/widgets/room_settings.rs
@@ -68,15 +68,11 @@ impl RoomSettings {
/* creates a empty list with members.len() rows, the content will be loaded when the row is
* drawn */
- pub fn create(&mut self) -> Option<(gtk::Box, gtk::Box)> {
- let body = self
+ pub fn create(&mut self) -> Option<gtk::Box> {
+ let page = self
.builder
.get_object::<gtk::Box>("room_settings_box")
.expect("Can't find room_settings_box in ui file.");
- let header = self
- .builder
- .get_object::<gtk::Box>("room_settings_headerbar")
- .expect("Can't find room_settings_headerbar in ui file.");
let stack = self
.builder
.get_object::<gtk::Stack>("room_settings_stack")
@@ -94,7 +90,7 @@ impl RoomSettings {
self.init_room_settings();
self.connect();
- Some((body, header))
+ Some(page)
}
#[allow(dead_code)]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]