Browse Source

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.
fix-filtering
Christopher Davis 6 years ago
parent
commit
1a552c5fbf
  1. 1
      Cargo.lock
  2. 1
      fractal-gtk/Cargo.toml
  3. 68
      fractal-gtk/res/ui/account_settings.ui
  4. 575
      fractal-gtk/res/ui/login_flow.ui
  5. 1207
      fractal-gtk/res/ui/main_window.ui
  6. 154
      fractal-gtk/res/ui/media_viewer.ui
  7. 68
      fractal-gtk/res/ui/room_settings.ui
  8. 13
      fractal-gtk/src/actions/global.rs
  9. 48
      fractal-gtk/src/actions/login.rs
  10. 2
      fractal-gtk/src/actions/message.rs
  11. 5
      fractal-gtk/src/app/connect/headerbar.rs
  12. 2
      fractal-gtk/src/app/connect/mod.rs
  13. 67
      fractal-gtk/src/app/connect/swipeable_widgets.rs
  14. 41
      fractal-gtk/src/app/mod.rs
  15. 13
      fractal-gtk/src/appop/media_viewer.rs
  16. 10
      fractal-gtk/src/appop/mod.rs
  17. 17
      fractal-gtk/src/appop/room_settings.rs
  18. 143
      fractal-gtk/src/appop/state.rs
  19. 2
      fractal-gtk/src/main.rs
  20. 1
      fractal-gtk/src/meson.build
  21. 11
      fractal-gtk/src/widgets/login.rs
  22. 8
      fractal-gtk/src/widgets/media_viewer.rs
  23. 10
      fractal-gtk/src/widgets/room_settings.rs

1
Cargo.lock generated

@ -563,6 +563,7 @@ dependencies = [
"gstreamer-pbutils",
"gstreamer-player",
"gtk",
"gtk-sys",
"html2pango",
"itertools 0.8.2",
"lazy_static",

1
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"

68
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">

575
fractal-gtk/res/ui/login_flow.ui

@ -2,63 +2,79 @@
<!-- 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>
<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,315 +83,308 @@
</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>
</packing>
</child>
</object>
<packing>

1207
fractal-gtk/res/ui/main_window.ui

File diff suppressed because it is too large Load Diff

154
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="HdyHeaderBar" 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>

68
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>

13
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: &gtk::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: &gtk::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);
@ -272,6 +275,13 @@ pub fn new(app: &gtk::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 |_, _| {
@ -344,6 +354,7 @@ pub fn new(app: &gtk::Application, op: &Arc<Mutex<AppOp>>) {
app.set_accels_for_action("app.older-messages", &["Page_Up"]);
app.set_accels_for_action("app.newer-messages", &["Page_Down"]);
app.set_accels_for_action("app.back", &["Escape"]);
app.set_accels_for_action("app.deck-back", &["Escape"]);
app.set_accels_for_action("app.main_menu", &["F10"]);
// connect mouse back button to app.back action

48
fractal-gtk/src/actions/login.rs

@ -1,6 +1,5 @@
use log::{debug, warn};
use std::cell::RefCell;
use std::rc::Rc;
use libhandy::prelude::*;
use log::warn;
use gio::prelude::*;
use gio::SimpleAction;
@ -41,8 +40,7 @@ impl ToString for LoginState {
}
pub fn new(
stack: &gtk::Stack,
headers: &gtk::Stack,
deck: &libhandy::Deck,
server_entry: &gtk::Entry,
err_label: &gtk::Label,
) -> SimpleActionGroup {
@ -60,8 +58,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 +71,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 +106,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
}

2
fractal-gtk/src/actions/message.rs

@ -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"));

5
fractal-gtk/src/app/connect/headerbar.rs

@ -1,18 +1,19 @@
use glib::clone;
use gtk::prelude::*;
use libhandy::HeaderBarExt;
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")

2
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();
}
}

67
fractal-gtk/src/app/connect/swipeable_widgets.rs

@ -0,0 +1,67 @@
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();
let global_back = app
.lookup_action("back")
.expect("Could not get back action");
deck.connect_property_transition_running_notify(
clone!(@weak app, @weak global_back => 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()) {
// Re-enable global back when returning to main view
let _ = global_back.set_property("enabled", &true);
app.activate_action("back", None);
}
}),
);
deck.connect_property_visible_child_notify(
clone!(@weak app, @weak global_back => 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()) {
let _ = global_back.set_property("enabled", &true);
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);
}
}));
}
}

41
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"]);
@ -175,6 +170,9 @@ impl App {
// Create application
let app = App::new(gtk_app);
// Initialize libhandy
libhandy::init();
gtk_app.connect_activate(clone!(@weak app => move |_| {
app.on_activate();
}));
@ -186,7 +184,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);
}

13
fractal-gtk/src/appop/media_viewer.rs

@ -18,13 +18,8 @@ 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
@ -66,12 +61,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);

10
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(

17
fractal-gtk/src/appop/room_settings.rs

@ -16,13 +16,8 @@ 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 room = self.rooms.get(&self.active_room.clone()?)?;
@ -33,18 +28,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);
}

143
fractal-gtk/src/appop/state.rs

@ -1,5 +1,6 @@
use gio::prelude::*;
use gtk::prelude::*;
use libhandy::LeafletExt;
use libhandy::prelude::*;
use super::RoomSearchPagination;
use crate::actions::AppState;
@ -8,6 +9,79 @@ 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 app = gio::Application::get_default().unwrap();
let global_back = app.lookup_action("back");
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 deck.get_adjacent_child(direction).is_some() {
deck.navigate(direction);
if direction == libhandy::NavigationDirection::Forward {
// Disable global back while in a subview
global_back.map(|a| a.set_property("enabled", &false));
}
}
}
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 +90,33 @@ 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();
if deck
.get_adjacent_child(libhandy::NavigationDirection::Back)
.is_some()
{
deck.navigate(libhandy::NavigationDirection::Back);
}
}
fn set_state_room(&self, headerbar: &gtk::HeaderBar) {
fn set_state_room(&self, headerbar: &libhandy::HeaderBar) {
for ch in headerbar.get_children().iter() {
ch.show();
}
@ -105,7 +138,7 @@ impl AppOp {
}
// WORKAROUND this is needed because NoRoom isn't a real app state
fn set_state_no_room(&mut self, headerbar: &gtk::HeaderBar) {
fn set_state_no_room(&mut self, headerbar: &libhandy::HeaderBar) {
for ch in headerbar.get_children().iter() {
ch.hide();

2
fractal-gtk/src/main.rs

@ -1,4 +1,6 @@
#![deny(dead_code, unused_imports, unused_variables)]
#[macro_use]
extern crate glib;
mod backend;
mod client;

1
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',

11
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,

8
fractal-gtk/src/widgets/media_viewer.rs

@ -17,6 +17,7 @@ use glib::signal;
use glib::source::Continue;
use gtk::prelude::*;
use gtk::Overlay;
use libhandy::HeaderBarExt;
use crate::types::Message;
use crate::types::Room;
@ -157,7 +158,7 @@ impl Data {
.expect("Can't find media_viewer_headerbar_box in ui file.");
let media_viewer_headerbar = self
.builder
.get_object::<gtk::HeaderBar>("media_viewer_headerbar")
.get_object::<libhandy::HeaderBar>("media_viewer_headerbar")
.expect("Can't find media_viewer_headerbar in ui file.");
let headerbar_revealer = self
.builder
@ -209,7 +210,7 @@ impl Data {
.expect("Can't find media_viewer_headerbar_box in ui file.");
let media_viewer_headerbar = self
.builder
.get_object::<gtk::HeaderBar>("media_viewer_headerbar")
.get_object::<libhandy::HeaderBar>("media_viewer_headerbar")
.expect("Can't find media_viewer_headerbar in ui file.");
let headerbar_revealer = self
.builder
@ -225,7 +226,6 @@ impl Data {
}
media_viewer_headerbar.pack_start(&media_viewer_back_button);
media_viewer_headerbar.set_child_position(&media_viewer_back_button, 0);
media_viewer_headerbar.set_show_close_button(true);
let full_screen_button_icon = self
@ -991,7 +991,7 @@ impl MediaViewer {
fn set_header_title(ui: &gtk::Builder, title: &str) {
let media_viewer_headerbar = ui
.get_object::<gtk::HeaderBar>("media_viewer_headerbar")
.get_object::<libhandy::HeaderBar>("media_viewer_headerbar")
.expect("Cant find media_viewer_headerbar in ui file.");
media_viewer_headerbar.set_title(Some(title));
}

10
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)
}
pub fn connect(&mut self) {

Loading…
Cancel
Save