event-popover: Rework UI and code

This builds on top of the existing UI/code, while adding a few improvements and
behavioral changes:

- The popover displays the changes-prevent icon when the even is read-only.
- Each section is properly separated with `GtkSeparator`s, with equal amount of
top and bottom margins.
- Location and Meetings section are mutually exclusive; only one is shown.
- When an event has no event note, the popover will always display that there's no
description.
- `GcalMeetingRow` has been ported to `GtkListBoxRow`.
- The action button adapts its icon and tooltip text depending on the event
permission.
This commit is contained in:
Hari Rana
2024-07-22 16:20:57 -06:00
committed by Georges Basile Stavracas Neto
parent d1c0aa8245
commit 00cf2a735d
7 changed files with 274 additions and 169 deletions
+44 -15
View File
@@ -31,14 +31,17 @@ struct _GcalEventPopover
{
GtkPopover parent;
GtkWidget *action_button;
GtkLabel *date_time_label;
GtkLabel *description_label;
GtkWidget *edit_button;
GtkScrolledWindow *description_scrolled_window;
GtkWidget *location_box;
GtkLabel *location_label;
GtkListBox *meetings_listbox;
GtkBox *meetings_box;
GtkLabel *placeholder_label;
GtkLabel *summary_label;
GtkImage *read_only_icon;
GcalContext *context;
GcalEvent *event;
@@ -348,6 +351,30 @@ format_single_day (GcalEventPopover *self,
g_assert_not_reached ();
}
static void
update_decorations (GcalEventPopover *self,
GcalEvent *event)
{
GcalCalendar *calendar;
gboolean calendar_is_read_only;
calendar = gcal_event_get_calendar (event);
calendar_is_read_only = gcal_calendar_is_read_only (calendar);
gtk_widget_set_visible (GTK_WIDGET (self->read_only_icon), calendar_is_read_only);
if (calendar_is_read_only)
{
gtk_button_set_icon_name (GTK_BUTTON (self->action_button), "info-outline-symbolic");
gtk_widget_set_tooltip_text (self->action_button, _("View Additional Details"));
}
else
{
gtk_button_set_icon_name (GTK_BUTTON (self->action_button), "edit-symbolic");
gtk_widget_set_tooltip_text (self->action_button, _("Edit Additional Details"));
}
}
static void
update_date_time_label (GcalEventPopover *self)
{
@@ -407,11 +434,8 @@ update_date_time_label (GcalEventPopover *self)
static void
update_placeholder_label (GcalEventPopover *self)
{
gboolean placeholder_visible = FALSE;
placeholder_visible |= !gtk_widget_get_visible (GTK_WIDGET (self->location_box)) &&
!gtk_widget_get_visible (GTK_WIDGET (self->description_label));
gtk_widget_set_visible (GTK_WIDGET (self->placeholder_label), placeholder_visible);
gtk_widget_set_visible (GTK_WIDGET (self->placeholder_label),
!gtk_widget_get_visible (GTK_WIDGET (self->description_scrolled_window)));
}
static void
@@ -424,7 +448,7 @@ add_meeting (GcalEventPopover *self,
g_signal_connect (row, "join-meeting", G_CALLBACK (on_join_meeting_cb), self);
gtk_list_box_append (self->meetings_listbox, row);
gtk_widget_set_visible (GTK_WIDGET (self->meetings_listbox), TRUE);
gtk_widget_set_visible (GTK_WIDGET (self->meetings_box), TRUE);
}
static void
@@ -455,7 +479,8 @@ setup_location_label (GcalEventPopover *self)
}
gtk_widget_set_visible (self->location_box,
location && g_utf8_strlen (location, -1) > 0);
location && g_utf8_strlen (location, -1) > 0 &&
!gtk_widget_get_visible (GTK_WIDGET (self->meetings_box)));
gtk_label_set_markup (self->location_label, location);
}
@@ -479,7 +504,7 @@ setup_description_label (GcalEventPopover *self)
g_string_replace (string, " ", " ", 0);
gtk_label_set_markup (self->description_label, string->str);
gtk_widget_set_visible (GTK_WIDGET (self->description_label), string->str && *string->str);
gtk_widget_set_visible (GTK_WIDGET (self->description_scrolled_window), string->str && *string->str);
}
static void
@@ -494,8 +519,9 @@ set_event_internal (GcalEventPopover *self,
setup_location_label (self);
update_placeholder_label (self);
update_date_time_label (self);
update_decorations (self, event);
gtk_widget_grab_focus (self->edit_button);
gtk_widget_grab_focus (self->action_button);
}
@@ -504,8 +530,8 @@ set_event_internal (GcalEventPopover *self,
*/
static void
on_edit_button_clicked_cb (GtkButton *edit_button,
GcalEventPopover *self)
on_action_button_clicked_cb (GtkButton *action_button,
GcalEventPopover *self)
{
g_signal_emit (self, signals[EDIT], 0);
gtk_popover_popdown (GTK_POPOVER (self));
@@ -575,7 +601,7 @@ gcal_event_popover_map (GtkWidget *widget)
if (first_meeting_row)
gtk_widget_grab_focus (GTK_WIDGET (first_meeting_row));
else
gtk_widget_grab_focus (self->edit_button);
gtk_widget_grab_focus (self->action_button);
}
@@ -695,14 +721,17 @@ gcal_event_popover_class_init (GcalEventPopoverClass *klass)
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, date_time_label);
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, description_label);
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, edit_button);
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, description_scrolled_window);
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, action_button);
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, location_box);
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, location_label);
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, meetings_box);
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, meetings_listbox);
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, placeholder_label);
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, summary_label);
gtk_widget_class_bind_template_child (widget_class, GcalEventPopover, read_only_icon);
gtk_widget_class_bind_template_callback (widget_class, on_edit_button_clicked_cb);
gtk_widget_class_bind_template_callback (widget_class, on_action_button_clicked_cb);
}
static void
+165 -134
View File
@@ -1,142 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GcalEventPopover" parent="GtkPopover">
<property name="default-widget">edit_button</property>
<property name="default-widget">action_button</property>
<property name="position">top</property>
<property name="width-request">250</property>
<style>
<class name="event-popover" />
</style>
<child>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<!-- Title -->
<child>
<object class="GtkLabel" id="summary_label">
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="selectable">True</property>
<property name="wrap">true</property>
<property name="wrap-mode">word-char</property>
<property name="width-chars">30</property>
<property name="max-width-chars">40</property>
<style>
<class name="title-3" />
</style>
</object>
</child>
<!-- Date & Time -->
<child>
<object class="GtkLabel" id="date_time_label">
<property name="margin-bottom">12</property>
<property name="ellipsize">end</property>
<style>
<class name="dim-label" />
</style>
</object>
</child>
<property name="spacing">18</property>
<property name="margin-top">18</property>
<property name="margin-bottom">12</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<child>
<object class="GtkSeparator">
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="propagate-natural-width">True</property>
<property name="propagate-natural-height">True</property>
<property name="max-content-height">400</property>
<object class="GtkBox">
<property name="hexpand">True</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<!-- Title -->
<child>
<object class="GtkBox">
<property name="spacing">12</property>
<property name="margin-bottom">12</property>
<property name="orientation">vertical</property>
<object class="GtkLabel" id="summary_label">
<property name="selectable">True</property>
<property name="wrap">True</property>
<property name="wrap-mode">word-char</property>
<property name="xalign">0.0</property>
<property name="max-width-chars">22.5</property>
<property name="lines">6</property>
<property name="ellipsize">end</property>
<style>
<class name="title-4" />
</style>
</object>
</child>
<!-- Placeholder -->
<child>
<object class="GtkLabel" id="placeholder_label">
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="valign">center</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="label" translatable="yes">No event information</property>
<attributes>
<attribute name="style" value="italic" />
</attributes>
<style>
<class name="dim-label" />
</style>
</object>
</child>
<!-- Date & Time -->
<child>
<object class="GtkLabel" id="date_time_label">
<property name="xalign">0.0</property>
<style>
<class name="dim-label" />
</style>
</object>
</child>
<!-- Description -->
<child>
<object class="GtkLabel" id="description_label">
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="use-markup">True</property>
<property name="selectable">True</property>
<property name="max-width-chars">50</property>
<property name="xalign">0.0</property>
<property name="wrap">True</property>
<property name="wrap-mode">word-char</property>
<style>
<class name="dim-label" />
</style>
</object>
</child>
</object>
</child>
<!-- Location -->
<child>
<object class="GtkBox" id="location_box">
<property name="spacing">6</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="spacing">6</property>
<child>
<object class="GtkLabel">
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="xalign">0.0</property>
<property name="label" translatable="yes">Location</property>
<style>
<class name="heading" />
</style>
</object>
</child>
<child>
<object class="GtkSeparator">
</object>
</child>
<child>
<object class="GtkLabel" id="location_label">
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="selectable">True</property>
<property name="xalign">0.0</property>
</object>
</child>
</object>
</child>
<!-- Lock icon for read-only events -->
<child>
<object class="GtkImage" id="read_only_icon">
<property name="tooltip-markup" translatable="yes">&lt;b&gt;This event is part of a read-only calendar&lt;/b&gt;
You cannot delete or change this event.</property>
<property name="icon-name">changes-prevent-symbolic</property>
<property name="pixel-size">18</property>
<property name="valign">start</property>
<property name="halign">end</property>
<property name="margin-top">8</property>
<property name="margin-bottom">8</property>
<style>
<class name="dim-label" />
</style>
</object>
</child>
<!-- Edit/View button -->
<child>
<object class="GtkButton" id="action_button">
<property name="can-focus">True</property>
<property name="valign">start</property>
<property name="halign">end</property>
<style>
<class name="circular" />
</style>
<signal name="clicked" handler="on_action_button_clicked_cb" object="GcalEventPopover" swapped="no" />
</object>
</child>
@@ -146,40 +96,121 @@
</object>
</child>
<!-- Meetings -->
<child>
<object class="GtkSeparator" />
</child>
<!-- Placeholder -->
<child>
<object class="GtkListBox" id="meetings_listbox">
<property name="visible">False</property>
<object class="GtkLabel" id="placeholder_label">
<property name="vexpand">True</property>
<property name="label" translatable="yes">No event notes</property>
<property name="margin-top">12</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="selection-mode">none</property>
<property name="margin-bottom">12</property>
<attributes>
<attribute name="style" value="italic" />
</attributes>
<style>
<class name="calendar-list" />
<class name="dim-label" />
</style>
</object>
</child>
<!-- Edit button -->
<!-- Description -->
<child>
<object class="GtkButton" id="edit_button">
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="margin-start">12</property>
<property name="margin-end">12</property>
<property name="label" translatable="yes">Edit…</property>
<signal name="clicked" handler="on_edit_button_clicked_cb" object="GcalEventPopover" swapped="no" />
<object class="GtkScrolledWindow" id="description_scrolled_window">
<property name="hscrollbar-policy">never</property>
<property name="propagate-natural-height">True</property>
<property name="propagate-natural-width">True</property>
<property name="max-content-height">350</property>
<property name="child">
<object class="GtkLabel" id="description_label">
<property name="use-markup">True</property>
<property name="selectable">True</property>
<property name="halign">fill</property>
<property name="xalign">0.0</property>
<property name="wrap">True</property>
<property name="max-width-chars">35</property>
<property name="wrap-mode">word-char</property>
<property name="margin-top">12</property>
<property name="margin-bottom">18</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
</object>
</property>
</object>
</child>
<!-- Location -->
<child>
<object class="GtkBox" id="location_box">
<property name="orientation">vertical</property>
<child>
<object class="GtkSeparator" />
</child>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="label" translatable="yes">Location</property>
<style>
<class name="heading" />
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="location_label">
<property name="halign">start</property>
<property name="selectable">True</property>
<property name="ellipsize">end</property>
<property name="max-width-chars">35</property>
</object>
</child>
</object>
</child>
</object>
</child>
<!-- Meetings -->
<child>
<object class="GtkBox" id="meetings_box">
<property name="orientation">vertical</property>
<property name="visible">False</property>
<child>
<object class="GtkSeparator" />
</child>
<child>
<object class="GtkListBox" id="meetings_listbox">
<property name="selection-mode">none</property>
<property name="margin-top">12</property>
<property name="margin-bottom">12</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<style>
<class name="calendar-list" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</property>
</template>
</interface>
+10 -6
View File
@@ -27,14 +27,16 @@
struct _GcalMeetingRow
{
AdwActionRow parent_instance;
GtkListBoxRow parent_instance;
GtkWidget *join_button;
GtkLabel *title;
GtkLabel *subtitle;
gchar *url;
};
G_DEFINE_TYPE (GcalMeetingRow, gcal_meeting_row, ADW_TYPE_ACTION_ROW)
G_DEFINE_TYPE (GcalMeetingRow, gcal_meeting_row, GTK_TYPE_LIST_BOX_ROW)
enum
{
@@ -65,12 +67,12 @@ setup_meeting (GcalMeetingRow *self)
const gchar *service_name = gcal_get_service_name_from_url (self->url);
if (service_name)
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self), service_name);
gtk_label_set_label (self->title, service_name);
else
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self), _("Unknown Service"));
gtk_label_set_label (self->title, _("Unknown Service"));
markup_url = g_strdup_printf ("<a href=\"%s\">%s</a>", self->url, self->url);
adw_action_row_set_subtitle (ADW_ACTION_ROW (self), markup_url);
markup_url = g_strdup_printf ("<a title=\"%1$s\" href=\"%1$s\">%1$s</a>", self->url);
gtk_label_set_markup (self->subtitle, markup_url);
}
/*
@@ -181,6 +183,8 @@ gcal_meeting_row_class_init (GcalMeetingRowClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/calendar/ui/gui/gcal-meeting-row.ui");
gtk_widget_class_bind_template_child (widget_class, GcalMeetingRow, join_button);
gtk_widget_class_bind_template_child (widget_class, GcalMeetingRow, title);
gtk_widget_class_bind_template_child (widget_class, GcalMeetingRow, subtitle);
gtk_widget_class_bind_template_callback (widget_class, on_join_button_clicked_cb);
+45 -14
View File
@@ -1,22 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="GcalMeetingRow" parent="AdwActionRow">
<template class="GcalMeetingRow" parent="GtkListBoxRow">
<property name="activatable">False</property>
<property name="focusable">False</property>
<property name="selectable">False</property>
<property name="child">
<object class="GtkBox">
<property name="spacing">6</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="hexpand">True</property>
<child>
<object class="GtkLabel" id="title">
<property name="halign">start</property>
<attributes>
<attribute name="weight" value="bold" />
</attributes>
</object>
</child>
<child>
<object class="GtkLabel" id="subtitle">
<property name="halign">start</property>
<property name="single-line-mode">True</property>
<property name="ellipsize">end</property>
<property name="max-width-chars">25</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="join_button">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="margin-start">12</property>
<property name="use-underline">True</property>
<!-- Translators: "Join" as in "Join meeting" -->
<property name="label" translatable="yes">_Join</property>
<style>
<class name="suggested-action" />
</style>
<signal name="clicked" handler="on_join_button_clicked_cb" object="GcalMeetingRow" swapped="no" />
</object>
</child>
<child>
<object class="GtkButton" id="join_button">
<property name="can-focus">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<!-- Translators: "Join" as in "Join meeting" -->
<property name="label" translatable="yes">Join</property>
<style>
<class name="suggested-action" />
</style>
<signal name="clicked" handler="on_join_button_clicked_cb" object="GcalMeetingRow" swapped="no" />
</object>
</child>
</property>
</template>
</interface>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 12.277344 0.832031 c -0.578125 0.007813 -1.167969 0.230469 -1.691406 0.753907 l -9 9 c -0.375 0.375 -0.585938 0.882812 -0.585938 1.414062 v 3 h 3 c 0.53125 0 1.039062 -0.210938 1.414062 -0.585938 l 9 -9 c 1.789063 -1.789062 0.082032 -4.390624 -1.890624 -4.570312 c -0.082032 -0.011719 -0.164063 -0.011719 -0.246094 -0.011719 z m -1.777344 3.605469 l 1.0625 1.0625 l -7.0625 7.0625 l -1.0625 -1.0625 z m 0 0" fill="#222222"/>
</svg>

After

Width:  |  Height:  |  Size: 573 B

+2
View File
@@ -6,5 +6,7 @@
<file compressed="true">calendar-week-symbolic.svg</file>
<file compressed="true">calendar-today-symbolic.svg</file>
<file compressed="true">external-link-symbolic.svg</file>
<file compressed="true">edit-symbolic.svg</file>
<file compressed="true">info-outline-symbolic.svg</file>
</gresource>
</gresources>
+4
View File
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg">
<path d="m 8 0 c -4.410156 0 -8 3.589844 -8 8 s 3.589844 8 8 8 s 8 -3.589844 8 -8 s -3.589844 -8 -8 -8 z m 0 2 c 3.332031 0 6 2.667969 6 6 s -2.667969 6 -6 6 s -6 -2.667969 -6 -6 s 2.667969 -6 6 -6 z m 0 1.875 c -0.621094 0 -1.125 0.503906 -1.125 1.125 s 0.503906 1.125 1.125 1.125 s 1.125 -0.503906 1.125 -1.125 s -0.503906 -1.125 -1.125 -1.125 z m -1.523438 3.125 c -0.265624 0.011719 -0.476562 0.230469 -0.476562 0.5 c 0 0.277344 0.222656 0.5 0.5 0.5 h 0.5 v 3 h -0.5 c -0.277344 0 -0.5 0.222656 -0.5 0.5 s 0.222656 0.5 0.5 0.5 h 3 c 0.277344 0 0.5 -0.222656 0.5 -0.5 s -0.222656 -0.5 -0.5 -0.5 h -0.5 v -4 h -2.5 c -0.007812 0 -0.015625 0 -0.023438 0 z m 0 0" fill="#222222"/>
</svg>

After

Width:  |  Height:  |  Size: 818 B