Browse Source

Start using Blueprint for UI files

Blueprint files to compile must be added to src/blp-resources.in.

To avoid having to maintain both a list of Blueprint files and the
corresponding list of UI files in the gresource.xml file, we populate
the resource file with meson.
fractal-13
Kévin Commaille 7 months ago
parent
commit
8c64726cca
No known key found for this signature in database
GPG Key ID: F26F4BE20A08255B
  1. 10
      meson.build
  2. 12
      po/POTFILES.in
  3. 56
      src/account_chooser_dialog/account_row.blp
  4. 65
      src/account_chooser_dialog/account_row.ui
  5. 77
      src/account_chooser_dialog/mod.blp
  6. 83
      src/account_chooser_dialog/mod.ui
  7. 23
      src/account_switcher/account_switcher_button.blp
  8. 47
      src/account_switcher/account_switcher_button.ui
  9. 45
      src/account_switcher/account_switcher_popover.blp
  10. 52
      src/account_switcher/account_switcher_popover.ui
  11. 23
      src/account_switcher/avatar_with_selection.blp
  12. 25
      src/account_switcher/avatar_with_selection.ui
  13. 81
      src/account_switcher/session_item.blp
  14. 90
      src/account_switcher/session_item.ui
  15. 5
      src/blp-resources.gresource.xml.in
  16. 10
      src/blp-resources.in
  17. 1
      src/config.rs.in
  18. 205
      src/error_page.blp
  19. 228
      src/error_page.ui
  20. 3
      src/main.rs
  21. 44
      src/meson.build
  22. 8
      src/ui-resources.gresource.xml
  23. 101
      src/window.blp
  24. 117
      src/window.ui

10
meson.build

@ -2,10 +2,11 @@ project('fractal',
'rust',
version: '12',
license: 'GPL-3.0-or-later',
meson_version: '>= 1.1')
meson_version: '>= 1.2')
i18n = import('i18n')
fs = import('fs')
gnome = import('gnome')
i18n = import('i18n')
base_id = 'org.gnome.Fractal'
application_id = base_id
@ -50,12 +51,17 @@ glib_compile_resources = find_program('glib-compile-resources', required: true)
glib_compile_schemas = find_program('glib-compile-schemas', required: true)
desktop_file_validate = find_program('desktop-file-validate', required: false)
appstreamcli = find_program('appstreamcli', required: false)
cargo = find_program('cargo', required: true)
cargo_version = run_command(cargo, '--version', check: true).stdout().strip()
message(cargo_version)
rustc_version = run_command('rustc', '--version', check: true).stdout().strip()
message(rustc_version)
blueprint_compiler = find_program('blueprint-compiler', required: true)
blueprint_compiler_version = run_command('blueprint-compiler', '--version', check: true).stdout().strip()
message('blueprint-compiler ' + blueprint_compiler_version)
prefix = get_option('prefix')
bindir = prefix / get_option('bindir')
localedir = prefix / get_option('localedir')

12
po/POTFILES.in

@ -4,10 +4,10 @@ data/org.gnome.Fractal.desktop.in.in
data/org.gnome.Fractal.gschema.xml.in
data/org.gnome.Fractal.metainfo.xml.in.in
src/account_chooser_dialog/mod.ui
src/account_switcher/account_switcher_button.ui
src/account_switcher/account_switcher_popover.ui
src/account_switcher/session_item.ui
src/account_chooser_dialog/mod.blp
src/account_switcher/account_switcher_button.blp
src/account_switcher/account_switcher_popover.blp
src/account_switcher/session_item.blp
src/application.rs
src/components/action_button.ui
src/components/avatar/editable.rs
@ -37,8 +37,8 @@ src/components/rows/loading_row.ui
src/components/user_page.rs
src/components/user_page.ui
src/contrib/qr_code.rs
src/error_page.blp
src/error_page.rs
src/error_page.ui
src/identity_verification_view/accept_request_page.rs
src/identity_verification_view/accept_request_page.ui
src/identity_verification_view/cancelled_page.rs
@ -205,4 +205,4 @@ src/utils/matrix/media_message.rs
src/utils/matrix/mod.rs
src/utils/media/image/mod.rs
src/utils/media/mod.rs
src/window.ui
src/window.blp

56
src/account_chooser_dialog/account_row.blp

@ -0,0 +1,56 @@
using Gtk 4.0;
using Adw 1;
template $AccountChooserDialogRow: Gtk.ListBoxRow {
selectable: false;
Gtk.Box {
spacing: 10;
$Avatar avatar {
size: "40";
}
Gtk.Box {
spacing: 3;
orientation: vertical;
Gtk.Label display_name {
xalign: 0.0;
hexpand: true;
}
Gtk.Label user_id {
xalign: 0.0;
hexpand: true;
styles [
"dimmed",
"caption",
]
}
}
Gtk.Stack state_stack {
Gtk.StackPage {
name: "loading";
child: Adw.Spinner {
width-request: 24;
};
}
Gtk.StackPage {
name: "error";
child: Gtk.Image error_image {
icon-name: "error-symbolic";
styles [
"error",
]
};
}
}
}
}

65
src/account_chooser_dialog/account_row.ui

@ -1,65 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="AccountChooserDialogRow" parent="GtkListBoxRow">
<property name="selectable">false</property>
<child>
<object class="GtkBox">
<property name="spacing">10</property>
<child>
<object class="Avatar" id="avatar">
<property name="size">40</property>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">3</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="display_name">
<property name="xalign">0.0</property>
<property name="hexpand">True</property>
</object>
</child>
<child>
<object class="GtkLabel" id="user_id">
<property name="xalign">0.0</property>
<property name="hexpand">True</property>
<style>
<class name="dimmed"/>
<class name="caption"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkStack" id="state_stack">
<child>
<object class="GtkStackPage">
<property name="name">loading</property>
<property name="child">
<object class="AdwSpinner">
<property name="width-request">24</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">error</property>
<property name="child">
<object class="GtkImage" id="error_image">
<property name="icon-name">error-symbolic</property>
<style>
<class name="error"/>
</style>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

77
src/account_chooser_dialog/mod.blp

@ -0,0 +1,77 @@
using Gtk 4.0;
using Adw 1;
template $AccountChooserDialog: Adw.Dialog {
title: _("Select an Account");
content-width: 360;
content-height: 360;
styles [
"account-chooser",
]
child: Adw.ToolbarView {
[top]
Adw.HeaderBar {
show-title: false;
}
[top]
Adw.Clamp {
hexpand: true;
child: Gtk.Box {
orientation: vertical;
spacing: 18;
margin-start: 12;
margin-end: 12;
Gtk.Label heading {
wrap: true;
wrap-mode: word_char;
max-width-chars: 20;
justify: center;
xalign: 0.5;
label: _("Select an Account");
styles [
"title-2",
]
}
};
}
content: Gtk.ScrolledWindow {
hscrollbar-policy: never;
propagate-natural-height: true;
child: Adw.Clamp {
margin-top: 24;
margin-bottom: 12;
margin-start: 12;
margin-end: 12;
child: Gtk.Box {
orientation: vertical;
spacing: 24;
Gtk.Label {
wrap: true;
wrap-mode: word_char;
justify: center;
label: _("Select the account you want to open the URI with");
styles [
"body",
]
}
Gtk.ListBox accounts {
activate-on-single-click: true;
row-activated => $select_row() swapped;
}
};
};
};
};
}

83
src/account_chooser_dialog/mod.ui

@ -1,83 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="AccountChooserDialog" parent="AdwDialog">
<property name="title" translatable="yes">Select an Account</property>
<property name="content-width">360</property>
<property name="content-height">360</property>
<style>
<class name="account-chooser"/>
</style>
<property name="child">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar">
<property name="show-title">False</property>
</object>
</child>
<child type="top">
<object class="AdwClamp">
<property name="hexpand">True</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<child>
<object class="GtkLabel" id="heading">
<property name="wrap">True</property>
<property name="wrap-mode">word-char</property>
<property name="max-width-chars">20</property>
<property name="justify">center</property>
<property name="xalign">0.5</property>
<property name="label" translatable="yes">Select an Account</property>
<style>
<class name="title-2"/>
</style>
</object>
</child>
</object>
</property>
</object>
</child>
<property name="content">
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="propagate-natural-height">True</property>
<property name="child">
<object class="AdwClamp">
<property name="margin-top">24</property>
<property name="margin-end">24</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">24</property>
<child>
<object class="GtkLabel">
<property name="wrap">True</property>
<property name="wrap-mode">word-char</property>
<property name="justify">center</property>
<property name="label" translatable="yes">Select the account you want to open the URI with</property>
<style>
<class name="body"/>
</style>
</object>
</child>
<child>
<object class="GtkListBox" id="accounts">
<property name="activate-on-single-click">true</property>
<signal name="row-activated" handler="select_row" swapped="yes"/>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
</property>
</object>
</property>
</template>
</interface>

23
src/account_switcher/account_switcher_button.blp

@ -0,0 +1,23 @@
using Gtk 4.0;
template $AccountSwitcherButton: Gtk.ToggleButton {
visible: bind $invert_boolean(template.root as <$Window>.session-selection as <$FixedSelection>.is-empty) as <bool>;
tooltip-text: bind template.root as <$Window>.session-selection as <$FixedSelection>.selected-item as <$SessionInfo>.user-id-string;
toggled => $toggle_popover() swapped;
accessibility {
description: _("Switch Accounts");
has-popup: true;
}
styles [
"image-button",
"circular",
]
child: $Avatar {
size: "24";
data: bind template.root as <$Window>.session-selection as <$FixedSelection>.selected-item as <$SessionInfo>.avatar-data;
accessible-role: "presentation";
};
}

47
src/account_switcher/account_switcher_button.ui

@ -1,47 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="AccountSwitcherButton" parent="GtkToggleButton">
<signal name="toggled" handler="toggle_popover" swapped="yes"/>
<binding name="visible">
<closure type="gboolean" function="invert_boolean">
<lookup name="is-empty" type="FixedSelection">
<lookup name="session-selection" type="Window">
<lookup name="root">AccountSwitcherButton</lookup>
</lookup>
</lookup>
</closure>
</binding>
<binding name="tooltip-text">
<lookup name="user-id-string" type="SessionInfo">
<lookup name="selected-item" type="FixedSelection">
<lookup name="session-selection" type="Window">
<lookup name="root">AccountSwitcherButton</lookup>
</lookup>
</lookup>
</lookup>
</binding>
<accessibility>
<property name="description" translatable="yes">Switch Accounts</property>
<property name="has-popup">True</property>
</accessibility>
<style>
<class name="image-button"/>
<class name="circular"/>
</style>
<property name="child">
<object class="Avatar">
<property name="size">24</property>
<binding name="data">
<lookup name="avatar-data" type="SessionInfo">
<lookup name="selected-item" type="FixedSelection">
<lookup name="session-selection" type="Window">
<lookup name="root">AccountSwitcherButton</lookup>
</lookup>
</lookup>
</lookup>
</binding>
<property name="accessible-role">presentation</property>
</object>
</property>
</template>
</interface>

45
src/account_switcher/account_switcher_popover.blp

@ -0,0 +1,45 @@
using Gtk 4.0;
template $AccountSwitcherPopover: Gtk.Popover {
styles [
"account-switcher",
]
Gtk.Box {
orientation: vertical;
spacing: 6;
Gtk.ListBox sessions {
activate-on-single-click: true;
row-activated => $select_row() swapped;
}
Gtk.Separator {}
Gtk.Button {
action-name: "win.new-session";
child: Gtk.Box {
spacing: 10;
Gtk.Image {
name: "new-login-icon";
icon-name: "add-symbolic";
pixel-size: 16;
accessible-role: presentation;
}
Gtk.Label {
use-underline: true;
ellipsize: end;
label: _("_Add Account");
}
};
styles [
"account-switcher-row",
"flat",
]
}
}
}

52
src/account_switcher/account_switcher_popover.ui

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="AccountSwitcherPopover" parent="GtkPopover">
<style>
<class name="account-switcher"/>
</style>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkListBox" id="sessions">
<property name="activate_on_single_click">true</property>
<signal name="row-activated" handler="select_row" swapped="yes"/>
</object>
</child>
<child>
<object class="GtkSeparator"/>
</child>
<child>
<object class="GtkButton">
<property name="action-name">win.new-session</property>
<property name="child">
<object class="GtkBox">
<property name="spacing">10</property>
<child>
<object class="GtkImage">
<property name="name">new-login-icon</property>
<property name="icon-name">add-symbolic</property>
<property name="pixel-size">16</property>
<property name="accessible-role">presentation</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="use-underline">true</property>
<property name="ellipsize">end</property>
<property name="label" translatable="yes">_Add Account</property>
</object>
</child>
</object>
</property>
<style>
<class name="account-switcher-row"/>
<class name="flat"/>
</style>
</object>
</child>
</object>
</child>
</template>
</interface>

23
src/account_switcher/avatar_with_selection.blp

@ -0,0 +1,23 @@
using Gtk 4.0;
using Adw 1;
template $AvatarWithSelection: Adw.Bin {
accessible-role: presentation;
child: Gtk.Overlay {
$Avatar child_avatar {}
[overlay]
Gtk.Image checkmark {
visible: false;
halign: end;
valign: end;
icon-name: "checkmark-symbolic";
pixel-size: 11;
styles [
"blue-checkmark",
]
}
};
}

25
src/account_switcher/avatar_with_selection.ui

@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="AvatarWithSelection" parent="AdwBin">
<property name="accessible-role">presentation</property>
<property name="child">
<object class="GtkOverlay">
<child>
<object class="Avatar" id="child_avatar"></object>
</child>
<child type="overlay">
<object class="GtkImage" id="checkmark">
<property name="visible">false</property>
<property name="halign">end</property>
<property name="valign">end</property>
<property name="icon-name">checkmark-symbolic</property>
<property name="pixel-size">11</property>
<style>
<class name="blue-checkmark" />
</style>
</object>
</child>
</object>
</property>
</template>
</interface>

81
src/account_switcher/session_item.blp

@ -0,0 +1,81 @@
using Gtk 4.0;
using Adw 1;
template $SessionItemRow: Gtk.ListBoxRow {
selectable: false;
styles [
"account-switcher-row",
]
Gtk.Box {
spacing: 10;
$AvatarWithSelection avatar {
size: "40";
}
Gtk.Box {
spacing: 3;
orientation: vertical;
Gtk.Label display_name {
xalign: 0.0;
hexpand: true;
ellipsize: end;
}
Gtk.Label user_id {
xalign: 0.0;
hexpand: true;
ellipsize: end;
styles [
"dimmed",
"caption",
]
}
}
Gtk.Stack state_stack {
Gtk.StackPage {
name: "loading";
child: Adw.Spinner {
valign: center;
halign: center;
height-request: 24;
};
}
Gtk.StackPage {
name: "settings";
child: Gtk.Button {
icon-name: "settings-symbolic";
valign: center;
halign: center;
tooltip-text: _("Account Settings");
clicked => $show_account_settings() swapped;
styles [
"circular",
"raised",
]
};
}
Gtk.StackPage {
name: "error";
child: Gtk.Image error_image {
icon-name: "error-symbolic";
styles [
"error",
]
};
}
}
}
}

90
src/account_switcher/session_item.ui

@ -1,90 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="SessionItemRow" parent="GtkListBoxRow">
<property name="selectable">false</property>
<style>
<class name="account-switcher-row"/>
</style>
<child>
<object class="GtkBox">
<property name="spacing">10</property>
<child>
<object class="AvatarWithSelection" id="avatar">
<property name="size">40</property>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">3</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="display_name">
<property name="xalign">0.0</property>
<property name="hexpand">True</property>
<property name="ellipsize">end</property>
</object>
</child>
<child>
<object class="GtkLabel" id="user_id">
<property name="xalign">0.0</property>
<property name="hexpand">True</property>
<property name="ellipsize">end</property>
<style>
<class name="dimmed"/>
<class name="caption"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkStack" id="state_stack">
<child>
<object class="GtkStackPage">
<property name="name">loading</property>
<property name="child">
<object class="AdwSpinner">
<property name="valign">center</property>
<property name="halign">center</property>
<property name="height-request">24</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">settings</property>
<property name="child">
<object class="GtkButton">
<property name="icon-name">settings-symbolic</property>
<property name="valign">center</property>
<property name="halign">center</property>
<property name="tooltip-text" translatable="yes">Account Settings</property>
<signal name="clicked" handler="show_account_settings" swapped="true"/>
<style>
<class name="circular"/>
<class name="raised"/>
</style>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">error</property>
<property name="child">
<object class="GtkImage" id="error_image">
<property name="icon-name">error-symbolic</property>
<style>
<class name="error"/>
</style>
</object>
</property>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

5
src/blp-resources.gresource.xml.in

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/Fractal/ui/">@UI_FILES@
</gresource>
</gresources>

10
src/blp-resources.in

@ -0,0 +1,10 @@
# List of Blueprint files to compile.
# Please keep this file sorted alphabetically.
account_chooser_dialog/account_row.blp
account_chooser_dialog/mod.blp
account_switcher/account_switcher_button.blp
account_switcher/account_switcher_popover.blp
account_switcher/avatar_with_selection.blp
account_switcher/session_item.blp
error_page.blp
window.blp

1
src/config.rs.in

@ -1,6 +1,7 @@
use crate::application::AppProfile;
pub const APP_ID: &str = @APP_ID@;
pub const BLUEPRINT_RESOURCES_FILE: &str = concat!(@PKGDATADIR@, "/blp-resources.gresource");
pub const DISABLE_GLYCIN_SANDBOX: bool = @DISABLE_GLYCIN_SANDBOX@;
pub const GETTEXT_PACKAGE: &str = @GETTEXT_PACKAGE@;
pub const LOCALEDIR: &str = @LOCALEDIR@;

205
src/error_page.blp

@ -0,0 +1,205 @@
using Gtk 4.0;
using Adw 1;
template $ErrorPage: Adw.Bin {
Adw.ToolbarView {
[top]
Adw.HeaderBar {
title-widget: Adw.WindowTitle {
title: _("Error");
};
[start]
$AccountSwitcherButton account_switcher {}
[start]
Gtk.Button {
visible: bind account_switcher.visible inverted;
action-name: "app.about";
tooltip-text: _("About Fractal");
icon-name: "about-symbolic";
accessibility {
label: _("About Fractal");
}
}
[end]
Gtk.Button {
visible: bind account_switcher.visible;
action-name: "app.about";
tooltip-text: _("About Fractal");
icon-name: "about-symbolic";
accessibility {
label: _("About Fractal");
}
}
}
content: Gtk.Stack stack {
Gtk.StackPage {
name: "secret";
child: Adw.StatusPage secret_error_page {
title: _("Secret Portal Error");
icon-name: "key-symbolic";
vexpand: true;
Adw.Clamp linux_secret_instructions {
Gtk.Box {
orientation: vertical;
spacing: 12;
Gtk.Label {
wrap: true;
wrap-mode: word_char;
xalign: 0.0;
label: _("Fractal relies on a Secret Portal to manage your sensitive session information and an error occurred while we were trying to restore your sessions.");
styles [
"body",
]
}
Gtk.Box {
orientation: vertical;
spacing: 12;
Gtk.Label {
wrap: true;
wrap-mode: word_char;
xalign: 0.0;
label: _("Here are a few things that might help you fix issues with the Secret Portal:");
styles [
"body",
]
}
Gtk.Box {
spacing: 6;
Gtk.Label {
valign: start;
label: "•";
}
Gtk.Label {
wrap: true;
wrap-mode: word_char;
xalign: 0.0;
label: _("Make sure you have a Secret Portal Backend Provider installed, like gnome-keyring.");
styles [
"body",
]
}
}
Gtk.Box {
spacing: 6;
Gtk.Label {
valign: start;
label: "•";
}
Gtk.Box {
orientation: vertical;
spacing: 12;
Gtk.Label {
wrap: true;
wrap-mode: word_char;
xalign: 0.0;
label: _("If you prefer to use a Secret Service Provider instead, you need to allow Fractal to interact with it, like this:");
styles [
"body",
]
}
Gtk.Box {
Gtk.ScrolledWindow {
vscrollbar-policy: never;
child: Gtk.Label secret_service_override_command {
xalign: 0.0;
hexpand: true;
selectable: true;
margin-start: 10;
margin-end: 10;
};
}
Gtk.Button {
icon-name: "copy-symbolic";
tooltip-text: _("Copy Command");
valign: center;
halign: end;
margin-start: 3;
clicked => $copy_secret_service_override_command() swapped;
styles [
"flat",
]
}
styles [
"card",
"linked",
"command",
]
}
}
}
Gtk.Box {
spacing: 6;
Gtk.Label {
valign: start;
label: "•";
}
Gtk.Label {
wrap: true;
wrap-mode: word_char;
xalign: 0.0;
label: _("Check that you have a default keyring and that it is unlocked.");
styles [
"body",
]
}
}
}
Gtk.Label {
wrap: true;
wrap-mode: word_char;
xalign: 0.0;
label: _("Check the application logs and your distribution’s documentation for more details.");
styles [
"body",
]
}
}
}
};
}
Gtk.StackPage {
name: "session";
child: Adw.StatusPage session_error_page {
title: _("Could Not Initialize Session");
icon-name: "warning-symbolic";
vexpand: true;
};
}
};
}
}

228
src/error_page.ui

@ -1,228 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="ErrorPage" parent="AdwBin">
<child>
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar">
<property name="title-widget">
<object class="AdwWindowTitle">
<property name="title" translatable="yes">Error</property>
</object>
</property>
<child type="start">
<object class="AccountSwitcherButton" id="account_switcher"/>
</child>
<child type="start">
<object class="GtkButton">
<property name="visible" bind-source="account_switcher" bind-property="visible" bind-flags="sync-create | invert-boolean"/>
<property name="action-name">app.about</property>
<property name="tooltip-text" translatable="yes">About Fractal</property>
<property name="icon-name">about-symbolic</property>
<accessibility>
<property name="label" translatable="yes">About Fractal</property>
</accessibility>
</object>
</child>
<child type="end">
<object class="GtkButton">
<property name="visible" bind-source="account_switcher" bind-property="visible" bind-flags="sync-create"/>
<property name="action-name">app.about</property>
<property name="tooltip-text" translatable="yes">About Fractal</property>
<property name="icon-name">about-symbolic</property>
<accessibility>
<property name="label" translatable="yes">About Fractal</property>
</accessibility>
</object>
</child>
</object>
</child>
<property name="content">
<object class="GtkStack" id="stack">
<child>
<object class="GtkStackPage">
<property name="name">secret</property>
<property name="child">
<object class="AdwStatusPage" id="secret_error_page">
<property name="title" translatable="yes">Secret Portal Error</property>
<property name="icon-name">key-symbolic</property>
<property name="vexpand">true</property>
<child>
<object class="AdwClamp" id="linux_secret_instructions">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="wrap">true</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0.0</property>
<property name="label" translatable="yes">Fractal relies on a Secret Portal to manage your sensitive session information and an error occurred while we were trying to restore your sessions.</property>
<style>
<class name="body"/>
</style>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="wrap">true</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0.0</property>
<property name="label" translatable="yes">Here are a few things that might help you fix issues with the Secret Portal:</property>
<style>
<class name="body"/>
</style>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="valign">start</property>
<property name="label">•</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="wrap">true</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0.0</property>
<property name="label" translatable="yes">Make sure you have a Secret Portal Backend Provider installed, like gnome-keyring.</property>
<style>
<class name="body"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="valign">start</property>
<property name="label">•</property>
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="wrap">true</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0.0</property>
<property name="label" translatable="yes">If you prefer to use a Secret Service Provider instead, you need to allow Fractal to interact with it, like this:</property>
<style>
<class name="body"/>
</style>
</object>
</child>
<child>
<object class="GtkBox">
<child>
<object class="GtkScrolledWindow">
<property name="vscrollbar-policy">never</property>
<property name="child">
<object class="GtkLabel" id="secret_service_override_command">
<property name="xalign">0.0</property>
<property name="hexpand">True</property>
<property name="selectable">True</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkButton">
<property name="icon-name">copy-symbolic</property>
<property name="tooltip-text" translatable="yes">Copy Command</property>
<property name="valign">center</property>
<property name="halign">end</property>
<property name="margin-start">3</property>
<signal name="clicked" handler="copy_secret_service_override_command" swapped="yes"/>
<style>
<class name="flat"/>
</style>
</object>
</child>
<style>
<class name="card" />
<class name="linked" />
<class name="command" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="valign">start</property>
<property name="label">•</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="wrap">true</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0.0</property>
<property name="label" translatable="yes">Check that you have a default keyring and that it is unlocked.</property>
<style>
<class name="body"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="wrap">true</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0.0</property>
<property name="label" translatable="yes">Check the application logs and your distribution’s documentation for more details.</property>
<style>
<class name="body"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">session</property>
<property name="child">
<object class="AdwStatusPage" id="session_error_page">
<property name="title" translatable="yes">Could Not Initialize Session</property>
<property name="icon-name">warning-symbolic</property>
<property name="vexpand">true</property>
</object>
</property>
</object>
</child>
</object>
</property>
</object>
</child>
</template>
</interface>

3
src/main.rs

@ -63,6 +63,9 @@ fn main() {
let res = gio::Resource::load(RESOURCES_FILE).expect("Could not load gresource file");
gio::resources_register(&res);
let blp_res = gio::Resource::load(BLUEPRINT_RESOURCES_FILE)
.expect("Could not load Blueprint gresource file");
gio::resources_register(&blp_res);
let ui_res = gio::Resource::load(UI_RESOURCES_FILE).expect("Could not load UI gresource file");
gio::resources_register(&ui_res);

44
src/meson.build

@ -1,4 +1,40 @@
# UI resources
# Compile Blueprint resources
blp_files = []
foreach line : fs.read('blp-resources.in').splitlines()
if not line.startswith('#') and line.strip() != ''
blp_files += line
endif
endforeach
blueprints = custom_target(
'blueprints',
input: blp_files,
output: '.',
command: [blueprint_compiler, 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'],
)
# Populate the GResource file for the compiled Blueprint files dynamically,
# using the same file list
compiled_ui_files = ''
foreach file : blp_files
compiled_ui_files += '\n <file compressed="true" preprocess="xml-stripblanks">' + file.replace('.blp', '.ui') + '</file>'
endforeach
blp_resources_xml = configure_file(
input: 'blp-resources.gresource.xml.in',
output: 'blp-resources.gresource.xml',
configuration: { 'UI_FILES': compiled_ui_files }
)
blp_resources = gnome.compile_resources(
'blp-resources',
blp_resources_xml,
gresource_bundle: true,
install: true,
install_dir: pkgdatadir,
dependencies: [blueprints, blp_resources_xml],
)
# Compile UI resources
ui_resources = gnome.compile_resources(
'ui-resources',
'ui-resources.gresource.xml',
@ -7,6 +43,7 @@ ui_resources = gnome.compile_resources(
install_dir: pkgdatadir,
)
# Generate config.rs
global_conf = configuration_data()
global_conf.set_quoted('APP_ID', application_id)
global_conf.set('DISABLE_GLYCIN_SANDBOX', get_option('disable-glycin-sandbox').to_string())
@ -20,7 +57,6 @@ config = configure_file(
output: 'config.rs',
configuration: global_conf
)
# Copy the config.rs output to the source directory.
run_command(
'cp',
meson.project_build_root() / 'src' / 'config.rs',
@ -28,6 +64,7 @@ run_command(
check: true
)
# Build binary with cargo
cargo_options = [ '--manifest-path', meson.project_source_root() / 'Cargo.toml' ]
cargo_options += [ '--target-dir', meson.project_build_root() / 'src' ]
@ -45,7 +82,7 @@ cargo_env = [ 'CARGO_HOME=' + meson.project_build_root() / 'cargo-home' ]
if build_env_only
depends = []
else
depends = [resources, ui_resources]
depends = [resources, blp_resources, ui_resources]
endif
custom_target(
@ -67,6 +104,7 @@ custom_target(
]
)
# Build docs with rustdoc
rustdoc_flags = ' '.join([
'-Zunstable-options',
'--enable-index-page',

8
src/ui-resources.gresource.xml

@ -1,12 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/Fractal/ui/">
<file compressed="true" preprocess="xml-stripblanks">account_chooser_dialog/account_row.ui</file>
<file compressed="true" preprocess="xml-stripblanks">account_chooser_dialog/mod.ui</file>
<file compressed="true" preprocess="xml-stripblanks">account_switcher/account_switcher_button.ui</file>
<file compressed="true" preprocess="xml-stripblanks">account_switcher/account_switcher_popover.ui</file>
<file compressed="true" preprocess="xml-stripblanks">account_switcher/avatar_with_selection.ui</file>
<file compressed="true" preprocess="xml-stripblanks">account_switcher/session_item.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components/action_button.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components/avatar/editable.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components/avatar/mod.ui</file>
@ -42,7 +36,6 @@
<file compressed="true" preprocess="xml-stripblanks">components/rows/substring_entry_row.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components/rows/switch_loading_row.ui</file>
<file compressed="true" preprocess="xml-stripblanks">components/user_page.ui</file>
<file compressed="true" preprocess="xml-stripblanks">error_page.ui</file>
<file compressed="true" preprocess="xml-stripblanks">identity_verification_view/accept_request_page.ui</file>
<file compressed="true" preprocess="xml-stripblanks">identity_verification_view/cancelled_page.ui</file>
<file compressed="true" preprocess="xml-stripblanks">identity_verification_view/choose_method_page.ui</file>
@ -147,6 +140,5 @@
<file compressed="true" preprocess="xml-stripblanks">session/view/sidebar/section_row.ui</file>
<file compressed="true" preprocess="xml-stripblanks">session/view/sidebar/verification_row.ui</file>
<file compressed="true" preprocess="xml-stripblanks">shortcuts.ui</file>
<file compressed="true" preprocess="xml-stripblanks">window.ui</file>
</gresource>
</gresources>

101
src/window.blp

@ -0,0 +1,101 @@
using Gtk 4.0;
using Adw 1;
template $Window: Adw.ApplicationWindow {
default-width: 900;
default-height: 850;
width-request: 360;
height-request: 294;
title: _("Fractal");
content: Adw.ToastOverlay toast_overlay {
Gtk.Stack main_stack {
transition-type: crossfade;
Gtk.StackPage {
name: "loading";
title: _("Loading");
child: Gtk.WindowHandle loading {
child: Adw.ToolbarView {
[top]
Adw.HeaderBar {
[start]
$AccountSwitcherButton {}
[end]
Gtk.Button {
action-name: "app.about";
tooltip-text: _("About Fractal");
icon-name: "about-symbolic";
accessibility {
label: _("About Fractal");
}
}
}
content: Gtk.Box {
orientation: vertical;
$OfflineBanner {}
Gtk.Box {
orientation: vertical;
valign: center;
vexpand: true;
spacing: 24;
Adw.Spinner {
height-request: 64;
width-request: 64;
}
Gtk.Label {
halign: center;
justify: center;
wrap: true;
wrap-mode: word_char;
label: _("Fetching Account Data…");
styles [
"title-2",
]
}
}
};
};
};
}
Gtk.StackPage {
name: "login";
title: _("Log In");
child: $Login login {};
}
Gtk.StackPage {
name: "session";
title: _("Session");
child: $SessionView session_view {};
}
Gtk.StackPage {
name: "error";
title: _("Error");
child: $ErrorPage error_page {};
}
}
};
Adw.Breakpoint {
condition ("max-width: 600sp")
setters {
template.compact: "True";
}
}
}

117
src/window.ui

@ -1,117 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="Window" parent="AdwApplicationWindow">
<property name="default-width">900</property>
<property name="default-height">850</property>
<property name="width-request">360</property>
<property name="height-request">294</property>
<property name="title" translatable="yes">Fractal</property>
<property name="content">
<object class="AdwToastOverlay" id="toast_overlay">
<child>
<object class="GtkStack" id="main_stack">
<property name="transition-type">crossfade</property>
<child>
<object class="GtkStackPage">
<property name="name">loading</property>
<property name="title" translatable="yes">Loading</property>
<property name="child">
<object class="GtkWindowHandle" id="loading">
<property name="child">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar">
<child type="start">
<object class="AccountSwitcherButton"/>
</child>
<child type="end">
<object class="GtkButton">
<property name="action-name">app.about</property>
<property name="tooltip-text" translatable="yes">About Fractal</property>
<property name="icon-name">about-symbolic</property>
<accessibility>
<property name="label" translatable="yes">About Fractal</property>
</accessibility>
</object>
</child>
</object>
</child>
<property name="content">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="OfflineBanner"/>
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="valign">center</property>
<property name="vexpand">True</property>
<property name="spacing">24</property>
<child>
<object class="AdwSpinner">
<property name="height-request">64</property>
<property name="width-request">64</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">center</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<property name="wrap-mode">word-char</property>
<property name="label" translatable="yes">Fetching Account Data…</property>
<style>
<class name="title-2"/>
</style>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">login</property>
<property name="title" translatable="yes">Log In</property>
<property name="child">
<object class="Login" id="login"/>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">session</property>
<property name="title" translatable="yes">Session</property>
<property name="child">
<object class="SessionView" id="session_view"/>
</property>
</object>
</child>
<child>
<object class="GtkStackPage">
<property name="name">error</property>
<property name="title" translatable="yes">Error</property>
<property name="child">
<object class="ErrorPage" id="error_page"/>
</property>
</object>
</child>
</object>
</child>
</object>
</property>
<child>
<object class="AdwBreakpoint">
<condition>max-width: 600sp</condition>
<setter object="Window" property="compact">True</setter>
</object>
</child>
</template>
</interface>
Loading…
Cancel
Save