gui: Port to Blueprint

This was mostly done with `blueprint-compiler port`.

Since Blueprint doesn't know about custom templates, I had to manually change some values from strings to literals.

Part-of: <https://gitlab.gnome.org/GNOME/gnome-calendar/-/merge_requests/567>
This commit is contained in:
Jamie Gravendeel
2025-06-08 14:31:01 +02:00
parent 2aceaa816f
commit a509de8b1e
90 changed files with 3278 additions and 3867 deletions
@@ -0,0 +1,42 @@
using Gtk 4.0;
using Adw 1;
Adw.ActionRow row {
use-markup: false;
activatable: true;
[prefix]
Image icon {
pixel-size: 24;
accessible-role: presentation;
styles [
"calendar-color-image",
]
}
[suffix]
Image read_only_icon {
tooltip-text: _("Read-Only Calendar");
icon-name: "changes-prevent-symbolic";
pixel-size: 20;
valign: center;
}
[suffix]
Switch switch {
valign: center;
tooltip-text: _("Display Calendar");
}
[suffix]
Image {
halign: end;
valign: center;
icon-name: "go-next-symbolic";
accessibility {
label: _("Edit calendar");
}
}
}
@@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="AdwActionRow" id="row">
<property name="use-markup">False</property>
<property name="activatable">True</property>
<child type="prefix">
<object class="GtkImage" id="icon">
<property name="pixel-size">24</property>
<property name="accessible-role">presentation</property>
<style>
<class name="calendar-color-image"/>
</style>
</object>
</child>
<!-- Lock icon for read-only calendars -->
<child type="suffix">
<object class="GtkImage" id="read_only_icon">
<property name="tooltip-text" translatable="yes">Read-Only Calendar</property>
<property name="icon-name">changes-prevent-symbolic</property>
<property name="pixel-size">20</property>
<property name="valign">center</property>
</object>
</child>
<child type="suffix">
<object class="GtkSwitch" id="switch">
<property name="valign">center</property>
<property name="tooltip-text" translatable="yes">Display Calendar</property>
</object>
</child>
<child type="suffix">
<object class="GtkImage">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="icon-name">go-next-symbolic</property>
<accessibility>
<property name="label" translatable="yes">Edit calendar</property>
</accessibility>
</object>
</child>
</object>
</interface>
@@ -0,0 +1,13 @@
using Gtk 4.0;
using Adw 1;
template $GcalCalendarManagementDialog: Adw.Dialog {
title: _("Calendar Settings");
width-request: 360;
height-request: 500;
content-width: 500;
Adw.NavigationView navigation_view {
popped => $on_navigation_view_popped_cb(template) not-swapped;
}
}
@@ -1,14 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GcalCalendarManagementDialog" parent="AdwDialog">
<property name="title" translatable="yes">Calendar Settings</property>
<property name="width-request">360</property>
<property name="height-request">500</property>
<property name="content-width">500</property>
<child>
<object class="AdwNavigationView" id="navigation_view">
<signal name="popped" handler="on_navigation_view_popped_cb" object="GcalCalendarManagementDialog" swapped="no" />
</object>
</child>
</template>
</interface>
@@ -0,0 +1,74 @@
using Gtk 4.0;
using Adw 1;
template $GcalCalendarsPage: Adw.NavigationPage {
title: _("Calendars");
tag: "calendars";
child: Adw.ToastOverlay toast_overlay {
Adw.ToolbarView {
[top]
Adw.HeaderBar {}
content: ScrolledWindow {
hexpand: true;
hscrollbar-policy: never;
max-content-height: 900;
propagate-natural-height: true;
child: Adw.Clamp {
child: Box {
orientation: vertical;
spacing: 24;
margin-top: 24;
margin-bottom: 24;
margin-start: 12;
margin-end: 12;
valign: start;
ListBox listbox {
selection-mode: none;
row-activated => $on_listbox_row_activated_cb(template) not-swapped;
styles [
"calendars-list",
"boxed-list",
]
}
};
};
};
[bottom]
Adw.Clamp {
ListBox {
selection-mode: none;
margin-top: 15;
margin-bottom: 15;
margin-start: 12;
margin-end: 12;
Adw.ButtonRow {
title: _("_Add Calendar");
use-underline: true;
end-icon-name: "go-next-symbolic";
activated => $on_new_calendar_row_activated_cb(template) not-swapped;
ShortcutController {
scope: managed;
Shortcut {
trigger: "<Ctrl>n";
action: "activate";
}
}
}
styles [
"boxed-list",
]
}
}
}
};
}
@@ -1,98 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GcalCalendarsPage" parent="AdwNavigationPage">
<property name="title" translatable="yes">Calendars</property>
<property name="tag">calendars</property>
<property name="child">
<object class="AdwToastOverlay" id="toast_overlay">
<child>
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar" />
</child>
<property name="content">
<object class="GtkScrolledWindow">
<property name="hexpand">True</property>
<property name="hscrollbar_policy">never</property>
<property name="max_content_height">900</property>
<property name="propagate_natural_height">True</property>
<property name="child">
<object class="AdwClamp">
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">24</property>
<property name="margin-top">24</property>
<property name="margin-bottom">24</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="valign">start</property>
<child>
<object class="GtkListBox" id="listbox">
<property name="selection-mode">none</property>
<signal name="row-activated" handler="on_listbox_row_activated_cb" object="GcalCalendarsPage" swapped="no" />
<style>
<class name="calendars-list"/>
<class name="boxed-list"/>
</style>
</object>
</child>
</object>
</property>
</object>
</property>
</object>
</property>
<child type="bottom">
<object class="AdwClamp">
<child>
<object class="GtkListBox">
<property name="selection-mode">none</property>
<property name="margin-top">15</property>
<property name="margin-bottom">15</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<child>
<object class="AdwButtonRow">
<property name="title" translatable="yes">_Add Calendar</property>
<property name="use-underline">true</property>
<property name="end-icon-name">go-next-symbolic</property>
<signal name="activated" handler="on_new_calendar_row_activated_cb" object="GcalCalendarsPage" swapped="no" />
<child>
<object class="GtkShortcutController">
<property name="scope">managed</property>
<child>
<object class="GtkShortcut">
<property name="trigger">&lt;Ctrl&gt;n</property>
<property name="action">activate</property>
</object>
</child>
</object>
</child>
</object>
</child>
<style>
<class name="boxed-list"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</property>
</template>
</interface>
@@ -0,0 +1,93 @@
using Gtk 4.0;
using Adw 1;
template $GcalEditCalendarPage: Adw.NavigationPage {
title: _("Edit Calendar");
tag: "edit-calendar";
child: Adw.ToolbarView {
[top]
Adw.HeaderBar {
title-widget: Adw.WindowTitle {
title: bind name_entry.text;
};
}
content: Adw.PreferencesPage {
Adw.PreferencesGroup {
Adw.ActionRow account_row {
title: _("Account");
subtitle-selectable: true;
styles [
"property",
]
Button settings_button {
tooltip-text: _("Open in Settings");
valign: center;
clicked => $on_settings_button_clicked_cb(template) not-swapped;
styles [
"flat",
]
Image {
icon-name: "external-link-symbolic";
accessible-role: presentation;
}
}
}
Adw.ActionRow calendar_url_row {
title: _("Location");
subtitle-lines: 1;
styles [
"property",
]
}
}
Adw.PreferencesGroup {
Adw.EntryRow name_entry {
title: _("Calendar Name");
}
Adw.ActionRow {
title: _("Color");
activatable-widget: calendar_color_button;
ColorDialogButton calendar_color_button {
valign: center;
dialog: ColorDialog {
modal: true;
with-alpha: false;
};
notify::rgba => $on_calendar_color_changed_cb(template) not-swapped;
}
}
Adw.SwitchRow calendar_visible_row {
title: _("_Display Calendar");
use-underline: true;
notify::active => $on_calendar_visibility_changed_cb(template) not-swapped;
}
}
Adw.PreferencesGroup remove_group {
Adw.ButtonRow remove_button_row {
title: _("_Remove Calendar");
use-underline: true;
activated => $on_remove_button_row_activated_cb(template) not-swapped;
styles [
"destructive-action",
]
}
}
};
};
}
@@ -1,144 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GcalEditCalendarPage" parent="AdwNavigationPage">
<property name="title" translatable="yes">Edit Calendar</property>
<property name="tag">edit-calendar</property>
<property name="child">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar">
<property name="title-widget">
<object class="AdwWindowTitle">
<binding name="title">
<lookup type="GtkEditable" name="text">name_entry</lookup>
</binding>
</object>
</property>
</object>
</child>
<property name="content">
<object class="AdwPreferencesPage">
<!-- Location (URL, file path) -->
<child>
<object class="AdwPreferencesGroup">
<!-- Online Accounts -->
<child>
<object class="AdwActionRow" id="account_row">
<property name="title" translatable="yes">Account</property>
<property name="subtitle-selectable">True</property>
<style>
<class name="property"/>
</style>
<child>
<object class="GtkButton" id="settings_button">
<property name="tooltip-text" translatable="yes">Open in Settings</property>
<property name="valign">center</property>
<signal name="clicked" handler="on_settings_button_clicked_cb" object="GcalEditCalendarPage" swapped="no" />
<style>
<class name="flat"/>
</style>
<child>
<object class="GtkImage">
<property name="icon-name">external-link-symbolic</property>
<property name="accessible-role">presentation</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwActionRow" id="calendar_url_row">
<property name="title" translatable="yes">Location</property>
<property name="subtitle-lines">1</property>
<style>
<class name="property"/>
</style>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<!-- Calendar name -->
<child>
<object class="AdwEntryRow" id="name_entry">
<property name="title" translatable="yes">Calendar Name</property>
</object>
</child>
<!-- Color -->
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Color</property>
<property name="activatable-widget">calendar_color_button</property>
<child>
<object class="GtkColorDialogButton" id="calendar_color_button">
<property name="valign">center</property>
<property name="dialog">
<object class="GtkColorDialog">
<property name="modal">True</property>
<property name="with-alpha">False</property>
</object>
</property>
<signal name="notify::rgba" handler="on_calendar_color_changed_cb" object="GcalEditCalendarPage" swapped="no"/>
</object>
</child>
</object>
</child>
<!-- Calendar visibility -->
<child>
<object class="AdwSwitchRow" id="calendar_visible_row">
<property name="title" translatable="yes">_Display Calendar</property>
<property name="use-underline">true</property>
<signal name="notify::active" handler="on_calendar_visibility_changed_cb" object="GcalEditCalendarPage" swapped="no"/>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup" id="remove_group">
<!-- Remove button -->
<child>
<object class="AdwButtonRow" id="remove_button_row">
<property name="title" translatable="yes">_Remove Calendar</property>
<property name="use-underline">true</property>
<signal name="activated" handler="on_remove_button_row_activated_cb" object="GcalEditCalendarPage" swapped="no" />
<style>
<class name="destructive-action" />
</style>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</property>
</template>
</interface>
@@ -0,0 +1,168 @@
using Gtk 4.0;
using Adw 1;
template $GcalNewCalendarPage: Adw.NavigationPage {
title: _("New Calendar");
tag: "new-calendar";
child: Adw.ToolbarView {
[top]
Adw.HeaderBar {
show-end-title-buttons: false;
show-start-title-buttons: false;
}
content: Adw.PreferencesPage {
Adw.PreferencesGroup {
title: _("Create a Local Calendar");
Adw.EntryRow local_calendar_name_row {
title: _("Calendar Name");
notify::text => $on_local_calendar_name_row_text_changed_cb(template) not-swapped;
}
Adw.ActionRow {
title: _("Color");
activatable-widget: local_calendar_color_button;
ColorDialogButton local_calendar_color_button {
valign: center;
dialog: ColorDialog {
modal: true;
with-alpha: false;
};
notify::rgba => $on_local_calendar_color_button_rgba_changed_cb(template) not-swapped;
}
}
}
Adw.PreferencesGroup {
title: _("Connect to an Online Calendar");
Grid {
row-spacing: 12;
column-spacing: 12;
Label {
label: _("HTTPS, CalDAV, or Webcal URLs are supported. Online calendars that can only be updated by the provider will be added as read-only.");
wrap: true;
xalign: 0;
layout {
column: 0;
row: 0;
column-span: 2;
}
}
Entry calendar_address_entry {
hexpand: true;
placeholder-text: "https://example.com/calendar.ics";
input-purpose: url;
notify::text => $on_url_entry_text_changed_cb(template) not-swapped;
activate => $on_calendar_address_activated_cb(template) not-swapped;
layout {
column: 0;
row: 1;
}
}
Revealer web_sources_revealer {
transition-type: slide_down;
transition-duration: 200;
layout {
column: 0;
row: 2;
column-span: 2;
}
Box web_sources_listbox_box {
orientation: vertical;
spacing: 6;
Label web_sources_calendar_label {
label: _("Calendars");
xalign: 0;
styles [
"heading",
]
}
ListBox web_sources_listbox {
activate-on-single-click: false;
selection-mode: none;
styles [
"calendar-list",
]
}
}
}
Label web_description_label {
label: _("If the calendar belongs to one of your online accounts, you can add it through the <a href=\"GOA\">online account settings</a>.");
use-markup: true;
wrap: true;
xalign: 0;
activate-link => $on_web_description_label_link_activated_cb(template) not-swapped;
layout {
column: 0;
row: 3;
column-span: 2;
}
}
}
}
Adw.PreferencesGroup {
Button add_button {
halign: center;
label: C_("button", "Add Calendar");
sensitive: false;
clicked => $on_add_button_clicked_cb(template) not-swapped;
styles [
"pill",
"suggested-action",
]
}
}
};
};
}
Adw.MessageDialog credentials_dialog {
heading: _("Credentials");
hide-on-close: true;
extra-child: Adw.Clamp {
ListBox {
Adw.EntryRow credentials_user_entry {
title: _("User");
}
Adw.PasswordEntryRow credentials_password_entry {
title: _("Password");
}
styles [
"boxed-list",
]
}
};
responses [
cancel: _("_Cancel"),
connect: _("_Connect") suggested,
]
default-response: "connect";
close-response: "cancel";
response => $on_credentials_dialog_response_cb(template) not-swapped;
}
@@ -1,215 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GcalNewCalendarPage" parent="AdwNavigationPage">
<property name="title" translatable="yes">New Calendar</property>
<property name="tag">new-calendar</property>
<property name="child">
<object class="AdwToolbarView">
<child type="top">
<object class="AdwHeaderBar">
<property name="show-end-title-buttons">False</property>
<property name="show-start-title-buttons">False</property>
</object>
</child>
<property name="content">
<object class="AdwPreferencesPage">
<!-- Local calendar -->
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Create a Local Calendar</property>
<!-- Calendar name -->
<child>
<object class="AdwEntryRow" id="local_calendar_name_row">
<property name="title" translatable="yes">Calendar Name</property>
<signal name="notify::text" handler="on_local_calendar_name_row_text_changed_cb" object="GcalNewCalendarPage" swapped="no" />
</object>
</child>
<!-- Color -->
<child>
<object class="AdwActionRow">
<property name="title" translatable="yes">Color</property>
<property name="activatable-widget">local_calendar_color_button</property>
<child>
<object class="GtkColorDialogButton" id="local_calendar_color_button">
<property name="valign">center</property>
<property name="dialog">
<object class="GtkColorDialog">
<property name="modal">True</property>
<property name="with-alpha">False</property>
</object>
</property>
<signal name="notify::rgba" handler="on_local_calendar_color_button_rgba_changed_cb" object="GcalNewCalendarPage" swapped="no" />
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<property name="title" translatable="yes">Connect to an Online Calendar</property>
<child>
<object class="GtkGrid">
<property name="row_spacing">12</property>
<property name="column_spacing">12</property>
<!-- Online Accounts reference label-->
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">HTTPS, CalDAV, or Webcal URLs are supported. Online calendars that can only be updated by the provider will be added as read-only.</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
<!-- URL entry -->
<child>
<object class="GtkEntry" id="calendar_address_entry">
<property name="hexpand">True</property>
<property name="placeholder-text">https://example.com/calendar.ics</property>
<property name="input-purpose">url</property>
<signal name="notify::text" handler="on_url_entry_text_changed_cb" object="GcalNewCalendarPage" swapped="no" />
<signal name="activate" handler="on_calendar_address_activated_cb" object="GcalNewCalendarPage" swapped="no" />
<layout>
<property name="column">0</property>
<property name="row">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkRevealer" id="web_sources_revealer">
<property name="transition_type">slide-down</property>
<property name="transition_duration">200</property>
<layout>
<property name="column">0</property>
<property name="row">2</property>
<property name="column-span">2</property>
</layout>
<child>
<object class="GtkBox" id="web_sources_listbox_box">
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="web_sources_calendar_label">
<property name="label" translatable="yes">Calendars</property>
<property name="xalign">0</property>
<style>
<class name="heading" />
</style>
</object>
</child>
<child>
<object class="GtkListBox" id="web_sources_listbox">
<property name="activate_on_single_click">False</property>
<property name="selection_mode">none</property>
<style>
<class name="calendar-list" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<!-- Online Accounts reference label-->
<child>
<object class="GtkLabel" id="web_description_label">
<property name="label" translatable="yes">If the calendar belongs to one of your online accounts, you can add it through the &lt;a href=&quot;GOA&quot;&gt;online account settings&lt;/a&gt;.</property>
<property name="use_markup">True</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
<signal name="activate-link" handler="on_web_description_label_link_activated_cb" object="GcalNewCalendarPage" swapped="no" />
<layout>
<property name="column">0</property>
<property name="row">3</property>
<property name="column-span">2</property>
</layout>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="AdwPreferencesGroup">
<child>
<object class="GtkButton" id="add_button">
<property name="halign">center</property>
<property name="label" translatable="yes" context="button">Add Calendar</property>
<property name="sensitive">False</property>
<signal name="clicked" handler="on_add_button_clicked_cb" object="GcalNewCalendarPage" swapped="no" />
<style>
<class name="pill"/>
<class name="suggested-action"/>
</style>
</object>
</child>
</object>
</child>
</object>
</property>
</object>
</property>
</template>
<!-- Credentials popover -->
<object class="AdwMessageDialog" id="credentials_dialog">
<property name="heading" translatable="true">Credentials</property>
<property name="hide-on-close">True</property>
<property name="extra-child">
<object class="AdwClamp">
<child>
<object class="GtkListBox">
<child>
<object class="AdwEntryRow" id="credentials_user_entry">
<property name="title" translatable="true">User</property>
</object>
</child>
<child>
<object class="AdwPasswordEntryRow" id="credentials_password_entry">
<property name="title" translatable="true">Password</property>
</object>
</child>
<style>
<class name="boxed-list"/>
</style>
</object>
</child>
</object>
</property>
<responses>
<response id="cancel" translatable="yes">_Cancel</response>
<response id="connect" translatable="yes" appearance="suggested">_Connect</response>
</responses>
<property name="default-response">connect</property>
<property name="close-response">cancel</property>
<signal name="response" handler="on_credentials_dialog_response_cb" object="GcalNewCalendarPage" swapped="no"/>
</object>
</interface>
+20
View File
@@ -1,9 +1,29 @@
calendar_incs += include_directories('.')
blueprints = custom_target(
'blueprints',
input: files(
'calendar-row.blp',
'gcal-calendar-management-dialog.blp',
'gcal-calendars-page.blp',
'gcal-edit-calendar-page.blp',
'gcal-new-calendar-page.blp',
),
output: '.',
command: [
find_program('blueprint-compiler'),
'batch-compile',
'@OUTPUT@',
'@CURRENT_SOURCE_DIR@',
'@INPUT@',
],
)
built_sources += gnome.compile_resources(
'calendar-management-resources',
'calendar-management.gresource.xml',
c_name: 'calendar_management',
dependencies: blueprints,
)
sources += files(