[gnome-contacts/nielsdg/gtk4: 8/10] Port to GTK4 and libadwaita
- From: Niels De Graef <nielsdg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-contacts/nielsdg/gtk4: 8/10] Port to GTK4 and libadwaita
- Date: Wed, 5 Jan 2022 01:07:59 +0000 (UTC)
commit c7bbb44e721280462e91591e24dceb3f27a3b3e4
Author: Niels De Graef <nielsdegraef gmail com>
Date: Thu Oct 14 01:19:13 2021 +0200
Port to GTK4 and libadwaita
data/contacts.gresource.xml | 2 +-
data/ui/contacts-accounts-list.ui | 15 +-
data/ui/contacts-avatar-selector.ui | 104 +-
data/ui/contacts-contact-pane.ui | 101 +-
data/ui/contacts-crop-cheese-dialog.ui | 116 --
data/ui/contacts-crop-dialog.ui | 82 ++
data/ui/contacts-in-app-notification.ui | 82 +-
data/ui/contacts-link-suggestion-grid.ui | 42 +-
data/ui/contacts-list-pane.ui | 55 +-
data/ui/contacts-main-window.ui | 634 ++++------
data/ui/contacts-setup-window.ui | 51 +-
data/ui/style.css | 57 +-
docs/meson.build | 4 +-
meson.build | 8 +-
meson_options.txt | 2 +-
po/POTFILES.in | 4 +-
po/POTFILES.skip | 2 +-
src/cc-crop-area.c | 1236 ++++++++++----------
src/contacts-accounts-list.vala | 100 +-
src/contacts-addressbook-dialog.vala | 22 +-
src/contacts-addressbook-list.vala | 45 +-
src/contacts-app.vala | 36 +-
src/contacts-avatar-selector.vala | 204 ++--
src/contacts-avatar.vala | 29 +-
src/contacts-contact-editor.vala | 15 +-
src/contacts-contact-list.vala | 231 ++--
src/contacts-contact-pane.vala | 32 +-
src/contacts-contact-sheet.vala | 254 ++--
...heese-dialog.vala => contacts-crop-dialog.vala} | 58 +-
src/contacts-editor-persona.vala | 70 +-
src/contacts-editor-property.vala | 195 ++-
src/contacts-esd-setup.vala | 86 +-
src/contacts-in-app-notification.vala | 21 +-
src/contacts-link-suggestion-grid.vala | 16 +-
src/contacts-linked-personas-dialog.vala | 7 +-
src/contacts-list-pane.vala | 16 +-
src/contacts-main-window.vala | 257 ++--
src/contacts-setup-window.vala | 4 +-
src/contacts-utils.vala | 8 +-
src/meson.build | 17 +-
src/xdg-portal-camera.vala | 17 +
41 files changed, 1997 insertions(+), 2340 deletions(-)
---
diff --git a/data/contacts.gresource.xml b/data/contacts.gresource.xml
index 370e2ccb..4b3bd25c 100644
--- a/data/contacts.gresource.xml
+++ b/data/contacts.gresource.xml
@@ -6,7 +6,7 @@
<file compressed="true" preprocess="xml-stripblanks">ui/contacts-accounts-list.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/contacts-avatar-selector.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/contacts-contact-pane.ui</file>
- <file compressed="true" preprocess="xml-stripblanks">ui/contacts-crop-cheese-dialog.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks">ui/contacts-crop-dialog.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/contacts-editor-menu.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/contacts-in-app-notification.ui</file>
<file compressed="true" preprocess="xml-stripblanks">ui/contacts-link-suggestion-grid.ui</file>
diff --git a/data/ui/contacts-accounts-list.ui b/data/ui/contacts-accounts-list.ui
index d08d297e..48e3733b 100644
--- a/data/ui/contacts-accounts-list.ui
+++ b/data/ui/contacts-accounts-list.ui
@@ -1,11 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <!-- interface-requires gtk+ 3.22 -->
- <template class="ContactsAccountsList" parent="GtkListBox">
- <property name="visible">True</property>
- <property name="selection_mode">none</property>
+ <template class="ContactsAccountsList" parent="AdwBin">
<style>
- <class name="content"/>
+ <class name="contacts-accounts-list"/>
</style>
+ <child>
+ <object class="GtkListBox" id="listbox">
+ <property name="selection_mode">none</property>
+ <style>
+ <class name="content"/>
+ </style>
+ </object>
+ </child>
</template>
</interface>
diff --git a/data/ui/contacts-avatar-selector.ui b/data/ui/contacts-avatar-selector.ui
index 336b6baf..7947d42f 100644
--- a/data/ui/contacts-avatar-selector.ui
+++ b/data/ui/contacts-avatar-selector.ui
@@ -1,70 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <requires lib="gtk+" version="3.22"/>
- <template class="ContactsAvatarSelector" parent="GtkWindow">
- <property name="can_focus">False</property>
+ <template class="ContactsAvatarSelector" parent="GtkDialog">
<property name="modal">True</property>
<property name="default_width">400</property>
<property name="default_height">400</property>
- <property name="destroy_with_parent">True</property>
- <property name="skip_taskbar_hint">True</property>
- <signal name="delete-event" handler="on_delete_event" swapped="no"/>
- <child type="titlebar">
- <object class="GtkHeaderBar">
+ <property name="title" translatable="yes">Select a new avatar</property>
+
+ <child type="action">
+ <object class="GtkButton" id="cancel_button">
+ <property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="can_focus">False</property>
- <child>
- <object class="GtkButton">
- <property name="label" translatable="yes">Cancel</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <signal name="clicked" handler="on_cancel_clicked" swapped="no"/>
- </object>
- </child>
- <child>
- <object class="GtkButton">
- <property name="label" translatable="yes">Done</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">True</property>
- <signal name="clicked" handler="on_done_clicked" swapped="no"/>
- <style>
- <class name="suggested-action"/>
- </style>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ </child>
+ <child type="action">
+ <object class="GtkButton" id="done_button">
+ <property name="label" translatable="yes">Done</property>
+ <style>
+ <class name="suggested-action"/>
+ </style>
</object>
</child>
- <child>
+ <action-widgets>
+ <action-widget response="cancel">cancel_button</action-widget>
+ <action-widget response="ok" default="true">done_button</action-widget>
+ </action-widgets>
+
+
+ <child internal-child="content_area">
<object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
<property name="hscrollbar_policy">never</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="margin_left">10</property>
- <property name="margin_right">10</property>
- <property name="margin_top">10</property>
- <property name="margin_bottom">10</property>
+ <property name="margin-start">10</property>
+ <property name="margin-end">10</property>
+ <property name="margin-top">10</property>
+ <property name="margin-bottom">10</property>
<property name="orientation">vertical</property>
<property name="spacing">10</property>
<child>
<object class="GtkFlowBox" id="thumbnail_grid">
- <property name="visible">True</property>
<property name="can_focus">False</property>
<property name="column_spacing">5</property>
<property name="row_spacing">5</property>
@@ -72,53 +53,38 @@
<property name="selection_mode">single</property>
<property name="homogeneous">False</property>
</object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
</child>
</object>
</child>
</object>
</child>
<child>
- <object class="GtkSeparator">
- <property name="visible">True</property>
- </object>>
+ <object class="GtkSeparator"/>
</child>
<child>
<object class="GtkBox">
- <property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="margin_left">10</property>
- <property name="margin_right">10</property>
- <property name="margin_top">10</property>
- <property name="margin_bottom">10</property>
+ <property name="margin-start">10</property>
+ <property name="margin-end">10</property>
+ <property name="margin-top">10</property>
+ <property name="margin-bottom">10</property>
<property name="spacing">10</property>
<property name="halign">center</property>
<child>
- <object class="GtkButton" id="cheese_button">
+ <object class="GtkButton" id="camera_button">
<property name="label" translatable="yes">Take a Picture…</property>
- <property name="can_focus">True</property>
- <property name="no_show_all">True</property>
<property name="receives_default">True</property>
- <signal name="clicked" handler="on_cheese_clicked" swapped="no"/>
+ <signal name="clicked" handler="on_camera_button_clicked"/>
</object>
</child>
<child>
<object class="GtkButton">
<property name="label" translatable="yes">Select a File…</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
<property name="receives_default">True</property>
- <signal name="clicked" handler="on_file_clicked" swapped="no"/>
+ <signal name="clicked" handler="on_file_clicked"/>
</object>
</child>
</object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
</child>
</object>
</child>
diff --git a/data/ui/contacts-contact-pane.ui b/data/ui/contacts-contact-pane.ui
index b75c3be1..710f5143 100644
--- a/data/ui/contacts-contact-pane.ui
+++ b/data/ui/contacts-contact-pane.ui
@@ -1,80 +1,81 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <requires lib="gtk+" version="3.20"/>
- <template class="ContactsContactPane" parent="GtkBin">
- <property name="visible">True</property>
+ <template class="ContactsContactPane" parent="AdwBin">
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child>
<object class="GtkStack" id="stack">
- <property name="visible">True</property>
- <property name="visible-child">none_selected_page</property>
<child>
- <object class="HdyStatusPage" id="none_selected_page">
- <property name="visible">True</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="icon_name">avatar-default-symbolic</property>
- <property name="title" translatable="yes">Select a Contact</property>
- </object>
- <packing>
+ <object class="GtkStackPage" id="none_selected_page">
<property name="name">none-selected-page</property>
- </packing>
+ <property name="child">
+ <object class="AdwStatusPage">
+ <property name="visible">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="icon_name">avatar-default-symbolic</property>
+ <property name="title" translatable="yes">Select a Contact</property>
+ </object>
+ </property>
+ </object>
</child>
<child>
- <object class="GtkScrolledWindow" id="contact_sheet_view">
- <property name="visible">True</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="shadow_type">none</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">automatic</property>
- <child>
- <object class="HdyClamp">
+ <object class="GtkStackPage" id="contact_sheet_page">
+ <property name="name">contact-sheet-page</property>
+ <property name="child">
+ <object class="GtkScrolledWindow" id="contact_sheet_view">
<property name="visible">True</property>
- <property name="margin-top">32</property>
- <property name="margin-bottom">32</property>
- <property name="margin-left">24</property>
- <property name="margin-right">24</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
<child>
- <object class="GtkBox" id="contact_sheet_page">
+ <object class="AdwClamp">
<property name="visible">True</property>
+ <property name="margin-top">32</property>
+ <property name="margin-bottom">32</property>
+ <property name="margin-start">24</property>
+ <property name="margin-end">24</property>
+ <child>
+ <object class="GtkBox" id="contact_sheet_box">
+ <property name="visible">True</property>
+ </object>
+ </child>
</object>
</child>
</object>
- </child>
+ </property>
</object>
- <packing>
- <property name="name">contact-sheet-page</property>
- </packing>
</child>
<child>
- <object class="GtkScrolledWindow" id="contact_editor_view">
- <property name="visible">True</property>
- <property name="hexpand">True</property>
- <property name="vexpand">True</property>
- <property name="shadow_type">none</property>
- <property name="hscrollbar_policy">never</property>
- <property name="vscrollbar_policy">automatic</property>
- <child>
- <object class="HdyClamp">
+ <object class="GtkStackPage" id="contact_editor_page">
+ <property name="name">contact-editor-page</property>
+ <property name="child">
+ <object class="GtkScrolledWindow" id="contact_editor_view">
<property name="visible">True</property>
- <property name="margin-top">32</property>
- <property name="margin-bottom">32</property>
- <property name="margin-left">24</property>
- <property name="margin-right">24</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
<child>
- <object class="GtkBox" id="contact_editor_page">
+ <object class="AdwClamp">
<property name="visible">True</property>
+ <property name="margin-top">32</property>
+ <property name="margin-bottom">32</property>
+ <property name="margin-start">24</property>
+ <property name="margin-end">24</property>
+ <child>
+ <object class="GtkBox" id="contact_editor_box">
+ <property name="visible">True</property>
+ </object>
+ </child>
</object>
</child>
</object>
- </child>
+ </property>
</object>
- <packing>
- <property name="name">contact-editor-page</property>
- </packing>
</child>
+ <property name="visible-child-name">none-selected-page</property>
</object>
</child>
</template>
diff --git a/data/ui/contacts-crop-dialog.ui b/data/ui/contacts-crop-dialog.ui
new file mode 100644
index 00000000..1a7a48ad
--- /dev/null
+++ b/data/ui/contacts-crop-dialog.ui
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="ContactsCropDialog" parent="GtkWindow">
+ <property name="modal">True</property>
+ <property name="default_width">400</property>
+ <property name="default_height">400</property>
+ <property name="destroy_with_parent">True</property>
+ <child type="titlebar">
+ <object class="GtkHeaderBar">
+ <property name="show-title-buttons">False</property>
+ <child>
+ <object class="GtkButton">
+ <property name="label" translatable="yes">Cancel</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="on_cancel_clicked" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStack" id="headerbar_stack">
+ <!-- <property name="visible-child-name" bind-source="stack" bind-property="visible-child-name"
/> XXX -->
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">crop</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">5</property>
+ <child>
+ <object class="GtkButton" id="take_another_button">
+ <property name="label" translatable="yes">Take Another…</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="on_take_another_clicked" swapped="no"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton">
+ <property name="label" translatable="yes">Done</property>
+ <property name="receives_default">True</property>
+ <signal name="clicked" handler="on_done_clicked" swapped="no"/>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkStackPage">
+ <property name="name">cheese</property>
+ <property name="child">
+ <object class="GtkButton">
+ <property name="receives_default">True</property>
+ <property name="halign">end</property>
+ <signal name="clicked" handler="on_take_pic_clicked" swapped="no"/>
+ <child>
+ <object class="GtkImage">
+ <property name="icon_name">camera-photo-symbolic</property>
+ </object>
+ </child>
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ </object>
+ </property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkStack" id="stack">
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/ui/contacts-in-app-notification.ui b/data/ui/contacts-in-app-notification.ui
index 2df36bf8..75a73261 100644
--- a/data/ui/contacts-in-app-notification.ui
+++ b/data/ui/contacts-in-app-notification.ui
@@ -1,52 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <requires lib="gtk+" version="3.14"/>
- <template class="ContactsInAppNotification" parent="GtkRevealer">
- <property name="visible">True</property>
- <property name="halign">center</property>
- <property name="valign">start</property>
+ <template class="ContactsInAppNotification" parent="AdwBin">
<child>
- <object class="GtkGrid" id="grid">
- <property name="visible">True</property>
- <property name="column_spacing">12</property>
- <property name="width_request">300</property>
- <style>
- <class name="app-notification"/>
- </style>
+ <object class="GtkRevealer" id="revealer">
+ <property name="halign">center</property>
+ <property name="valign">start</property>
<child>
- <object class="GtkLabel" id="label">
- <property name="visible">True</property>
- <property name="hexpand">True</property>
- <property name="halign">start</property>
- <property name="wrap">True</property>
- <property name="max_width_chars">50</property>
- <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
- </object>
- <packing>
- <property name="top_attach">0</property>
- <property name="left_attach">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="close_button">
- <property name="visible">True</property>
- <property name="valign">center</property>
- <property name="focus_on_click">False</property>
- <property name="relief">none</property>
- <signal name="clicked" handler="on_close_button_clicked" swapped="no"/>
+ <object class="GtkGrid" id="grid">
+ <property name="column_spacing">12</property>
+ <property name="width_request">300</property>
+ <style>
+ <class name="app-notification"/>
+ </style>
+ <child>
+ <object class="GtkLabel" id="label">
+ <property name="hexpand">True</property>
+ <property name="halign">start</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">50</property>
+ <property name="wrap_mode">PANGO_WRAP_WORD_CHAR</property>
+ <layout>
+ <property name="row">0</property>
+ <property name="column">0</property>
+ </layout>
+ </object>
+ </child>
<child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="pixel_size">16</property>
- <property name="icon_name">window-close-symbolic</property>
+ <object class="GtkButton" id="close_button">
+ <property name="valign">center</property>
+ <property name="focus_on_click">False</property>
+ <signal name="clicked" handler="on_close_button_clicked" swapped="no"/>
+ <style>
+ <class name="flat"/>
+ </style>
+ <child>
+ <object class="GtkImage">
+ <property name="can_focus">False</property>
+ <property name="pixel_size">16</property>
+ <property name="icon_name">window-close-symbolic</property>
+ </object>
+ </child>
+ <layout>
+ <property name="row">0</property>
+ <property name="column">2</property>
+ </layout>
</object>
</child>
</object>
- <packing>
- <property name="top_attach">0</property>
- <property name="left_attach">2</property>
- </packing>
</child>
</object>
</child>
diff --git a/data/ui/contacts-link-suggestion-grid.ui b/data/ui/contacts-link-suggestion-grid.ui
index 30511c78..8b5e34e8 100644
--- a/data/ui/contacts-link-suggestion-grid.ui
+++ b/data/ui/contacts-link-suggestion-grid.ui
@@ -1,26 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <!-- interface-requires gtk+ 3.22 -->
<template class="ContactsLinkSuggestionGrid" parent="GtkGrid">
<property name="orientation">horizontal</property>
- <property name="visible">True</property>
- <property name="valign">end</property>
<property name="column_spacing">6</property>
+ <style>
+ <class name="contacts-link-suggestion"/>
+ </style>
<child>
<object class="GtkLabel" id="description_label">
- <property name="visible">True</property>
<property name="valign">end</property>
<property name="halign">start</property>
<property name="hexpand">True</property>
- <property name="margin_top">12</property>
+ <property name="margin-top">12</property>
<property name="wrap">True</property>
<property name="wrap_mode">word-char</property>
+ <layout>
+ <property name="row">0</property>
+ <property name="column">1</property>
+ </layout>
</object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">0</property>
- <property name="height">1</property>
- </packing>
</child>
<child>
<object class="GtkLabel" id="extra_info_label">
@@ -32,16 +30,14 @@
<style>
<class name="dim-label"/>
</style>
+ <layout>
+ <property name="row">1</property>
+ <property name="column">1</property>
+ </layout>
</object>
- <packing>
- <property name="left_attach">1</property>
- <property name="top_attach">1</property>
- <property name="height">1</property>
- </packing>
</child>
<child>
<object class="GtkBox">
- <property name="visible">True</property>
<property name="valign">center</property>
<property name="orientation">horizontal</property>
<property name="spacing">6</property>
@@ -51,7 +47,6 @@
<property name="margin_end">6</property>
<child>
<object class="GtkButton" id="accept_button">
- <property name="visible">True</property>
<property name="valign">center</property>
<property name="label" translatable="yes">Link Contacts</property>
<property name="margin_end">6</property>
@@ -59,31 +54,28 @@
</child>
<child>
<object class="GtkSeparator">
- <property name="visible">True</property>
<property name="orientation">vertical</property>
</object>
</child>
<child>
<object class="GtkButton" id="reject_button">
- <property name="visible">True</property>
<property name="valign">center</property>
<style>
<class name="flat"/>
</style>
<child>
<object class="GtkImage">
- <property name="visible">True</property>
<property name="icon_name">window-close-symbolic</property>
</object>
</child>
</object>
</child>
+ <layout>
+ <property name="row">0</property>
+ <property name="column">2</property>
+ <property name="row-span">2</property>
+ </layout>
</object>
- <packing>
- <property name="left_attach">2</property>
- <property name="top_attach">0</property>
- <property name="height">2</property>
- </packing>
</child>
</template>
</interface>
diff --git a/data/ui/contacts-list-pane.ui b/data/ui/contacts-list-pane.ui
index 00ec107b..a497c716 100644
--- a/data/ui/contacts-list-pane.ui
+++ b/data/ui/contacts-list-pane.ui
@@ -1,89 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.15.2 on Thu Aug 15 15:33:02 2013 -->
<interface>
- <!-- interface-requires gtk+ 3.10 -->
- <template class="ContactsListPane" parent="GtkFrame">
- <property name="can_focus">False</property>
- <property name="hexpand">False</property>
- <property name="hexpand_set">True</property>
- <property name="shadow_type">none</property>
+ <template class="ContactsListPane" parent="AdwBin">
<child>
- <object class="GtkGrid">
+ <object class="GtkBox">
<property name="orientation">vertical</property>
- <property name="visible">True</property>
<child>
<object class="GtkSearchEntry" id="filter_entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="primary_icon_name">edit-find-symbolic</property>
- <property name="primary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">False</property>
- <property name="margin">6</property>
<property name="placeholder_text" translatable="yes">Type to search</property>
- <signal name="search_changed" handler="filter_entry_changed" object="ContactsListPane"
after="no" swapped="no"/>
+ <signal name="search_changed" handler="filter_entry_changed"/>
+ <style>
+ <class name="contacts-filter-entry"/>
+ </style>
</object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">0</property>
- </packing>
</child>
<child>
<object class="GtkScrolledWindow" id="contacts_list_container">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="hscrollbar_policy">never</property>
- <property name="no_show_all">True</property>
</object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">1</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
</child>
<child>
<object class="GtkActionBar" id="actions_bar">
<property name="visible">False</property>
<child>
<object class="GtkButton" id="link_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
<property name="focus_on_click">False</property>
<property name="label" translatable="yes" comments="Link refers to the verb, from linking
contacts together">Link</property>
- <property name="width_request">70</property>
<property name="sensitive">False</property>
<signal name="clicked" handler="on_link_button_clicked"/>
</object>
- <packing>
- <property name="pack_type">start</property>
- </packing>
</child>
- <child>
+ <child type="end">
<object class="GtkButton" id="delete_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
<property name="focus_on_click">False</property>
<property name="label" translatable="yes">Remove</property>
- <property name="width_request">70</property>
<property name="sensitive">False</property>
<signal name="clicked" handler="on_delete_button_clicked"/>
<style>
<class name="destructive-action"/>
</style>
</object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
</child>
</object>
- <packing>
- <property name="left_attach">0</property>
- <property name="top_attach">2</property>
- <property name="width">1</property>
- <property name="height">1</property>
- </packing>
</child>
</object>
</child>
diff --git a/data/ui/contacts-main-window.ui b/data/ui/contacts-main-window.ui
index ee0cfd1f..4d2981cb 100644
--- a/data/ui/contacts-main-window.ui
+++ b/data/ui/contacts-main-window.ui
@@ -1,458 +1,294 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <!-- interface-requires gtk+ 3.22 -->
- <object class="GtkPopoverMenu" id="hamburger_menu_popover">
- <child>
- <object class="GtkBox" id="hamburger_menu_box">
- <property name="visible">True</property>
- <property name="margin">12</property>
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkLabel">
- <property name="visible">True</property>
- <property name="margin">5</property>
- <property name="halign">start</property>
- <property name="label" translatable="yes">List Contacts By:</property>
- <attributes>
- <attribute name="weight" value="bold"/>
- <attribute name="scale" value="0.8"/>
- </attributes>
- <style>
- <class name="dim-label"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkModelButton" id="sort_on_firstname_button">
- <property name="visible">True</property>
- <property name="text" translatable="yes">First Name</property>
- <property name="role">radio</property>
- </object>
- </child>
- <child>
- <object class="GtkModelButton" id="sort_on_surname_button">
- <property name="visible">True</property>
- <property name="text" translatable="yes">Surname</property>
- <property name="role">radio</property>
- </object>
- </child>
- <child>
- <object class="GtkSeparator">
- <property name="margin-top">6</property>
- <property name="margin-bottom">6</property>
- <property name="visible">True</property>
- </object>
- </child>
- <child>
- <object class="GtkModelButton">
- <property name="can_focus">True</property>
- <property name="text" translatable="yes">Change Address Book…</property>
- <property name="action-name">app.change-book</property>
- <property name="visible">True</property>
- </object>
- </child>
- <child>
- <object class="GtkModelButton">
- <property name="can_focus">True</property>
- <property name="text" translatable="yes">Online Accounts <sup>↗</sup></property>
- <property name="action-name">app.online-accounts</property>
- <property name="use-markup">True</property>
- <property name="visible">True</property>
- </object>
- </child>
- <child>
- <object class="GtkSeparator">
- <property name="margin-top">6</property>
- <property name="margin-bottom">6</property>
- <property name="visible">True</property>
- </object>
- </child>
- <child>
- <object class="GtkModelButton">
- <property name="can_focus">True</property>
- <property name="text" translatable="yes">Keyboard Shortcuts</property>
- <property name="action-name">win.show-help-overlay</property>
- <property name="visible">True</property>
- </object>
- </child>
- <child>
- <object class="GtkModelButton">
- <property name="can_focus">True</property>
- <property name="text" translatable="yes">Help</property>
- <property name="action-name">app.help</property>
- <property name="visible">True</property>
- </object>
- </child>
- <child>
- <object class="GtkModelButton">
- <property name="can_focus">True</property>
- <property name="text" translatable="yes">About Contacts</property>
- <property name="action-name">app.about</property>
- <property name="visible">True</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- <object class="GtkPopoverMenu" id="contact_sheet_menu">
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="orientation">vertical</property>
- <property name="margin">10</property>
- <child>
- <object class="GtkModelButton">
- <property name="visible">False</property>
- <property name="action-name">window.share-contact</property>
- <property name="text" translatable="yes">Share</property>
- </object>
- </child>
- <child>
- <object class="GtkModelButton">
- <property name="visible">True</property>
- <property name="action-name">window.edit-contact</property>
- <property name="text" translatable="yes">Edit</property>
- </object>
- </child>
- <child>
- <object class="GtkModelButton" id="unlink_button">
- <property name="visible">True</property>
- <property name="action-name">window.unlink-contact</property>
- <property name="text" translatable="yes">Unlink</property>
- </object>
- </child>
- <child>
- <object class="GtkSeparator">
- <property name="visible">True</property>
- </object>
- </child>
- <child>
- <object class="GtkModelButton">
- <property name="visible">True</property>
- <property name="action-name">window.delete-contact</property>
- <property name="text" translatable="yes">Delete</property>
- </object>
- </child>
- </object>
- </child>
- </object>
- <template class="ContactsMainWindow" parent="HdyApplicationWindow">
- <property name="can_focus">False</property>
+ <menu id="hamburger_menu_popover">
+ <section>
+ <attribute name="label" translatable="yes">List Contacts By:</attribute>
+ <item>
+ <attribute name="label" translatable="yes">First Name</attribute>
+ <attribute name="action">window.sort-on</attribute>
+ <attribute name="target">'firstname'</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Surname</attribute>
+ <attribute name="action">window.sort-on</attribute>
+ <attribute name="target">'surname'</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">Change Address Book…</attribute>
+ <attribute name="action">app.change-book</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Online Accounts ↗</attribute>
+ <attribute name="action">app.online-accounts</attribute>
+ </item>
+ </section>
+ <section>
+ <item>
+ <attribute name="label" translatable="yes">Keyboard Shortcuts</attribute>
+ <attribute name="action">win.show-help-overlay</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">Help</attribute>
+ <attribute name="action">app.help</attribute>
+ </item>
+ <item>
+ <attribute name="label" translatable="yes">About Contacts</attribute>
+ <attribute name="action">app.about</attribute>
+ </item>
+ </section>
+ </menu>
+
+ <menu id="contact_sheet_menu">
+ <section>
+ <!-- XXX -->
+ <item>
+ <attribute name="action">window.unlink-contact</attribute>
+ <attribute name="label" translatable="yes">Unlink</attribute>
+ <attribute name="hidden-when">action-disabled</attribute>
+ </item>
+ </section>
+ </menu>
+
+ <template class="ContactsMainWindow" parent="AdwApplicationWindow">
<property name="default_width">800</property>
<property name="default_height">600</property>
<property name="icon_name">gnome-contacts</property>
<property name="title" translatable="yes">Contacts</property>
- <signal name="key-press-event" handler="key_press_event_cb" object="ContactsMainWindow" after="yes"
swapped="no"/>
- <signal name="delete-event" handler="delete_event_cb" object="ContactsMainWindow" after="no"
swapped="no"/>
+ <child>
+ <object class="GtkEventControllerKey">
+ <signal name="key-pressed" handler="on_key_pressed"/>
+ </object>
+ </child>
<child>
<object class="GtkBox">
- <property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
- <object class="HdyLeaflet" id="header">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
+ <object class="AdwLeaflet" id="header">
+ <property name="visible-child-name" bind-source="content_box" bind-property="visible-child-name"
bind-flags="bidirectional|sync-create"/>
<property name="mode-transition-duration" bind-source="content_box"
bind-property="mode-transition-duration" bind-flags="bidirectional|sync-create"/>
<property name="child-transition-duration" bind-source="content_box"
bind-property="child-transition-duration" bind-flags="bidirectional|sync-create"/>
<property name="transition-type" bind-source="content_box" bind-property="transition-type"
bind-flags="bidirectional|sync-create"/>
<child>
- <object class="HdyHeaderBar" id="left_header">
- <property name="visible">True</property>
- <property name="hexpand">False</property>
- <property name="can_focus">False</property>
- <property name="title" translatable="yes">Contacts</property>
- <property name="show_close_button">True</property>
- <child>
- <object class="GtkButton" id="add_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="tooltip_text" translatable="yes">Create new contact</property>
- <signal name="clicked" handler="new_contact" object="ContactsMainWindow" after="no"
swapped="no"/>
- <child internal-child="accessible">
- <object class="AtkObject" id="add_button_atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">Add contact</property>
+ <object class="AdwLeafletPage">
+ <property name="name">list-pane</property>
+ <property name="child">
+ <object class="AdwHeaderBar" id="left_header">
+ <property name="hexpand">False</property>
+ <property name="show-end-title-buttons" bind-source="content_box" bind-property="folded"
bind-flags="sync-create"/>
+
+ <child type="start">
+ <object class="GtkButton" id="add_button">
+ <property name="tooltip-text" translatable="yes">Create new contact</property>
+ <property name="icon-name">list-add-symbolic</property>
+ <signal name="clicked" handler="new_contact"/>
+ <style>
+ <class name="flat"/>
+ </style>
</object>
</child>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">list-add-symbolic</property>
- <property name="icon_size">1</property>
+
+ <property name="title-widget">
+ <object class="AdwWindowTitle">
+ <property name="title" translatable="yes">Contacts</property>
</object>
- </child>
- </object>
- <packing>
- <property name="pack_type">start</property>
- </packing>
- </child>
+ </property>
- <child>
- <object class="GtkButton" id="selection_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="halign">center</property>
- <property name="valign">center</property>
- <property name="tooltip_text" translatable="yes">Select Items</property>
- <signal name="clicked" handler="on_selection_button_clicked"/>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">object-select-symbolic</property>
- <property name="icon_size">1</property>
+ <child type="end">
+ <object class="GtkMenuButton" id="hamburger_menu_button">
+ <property name="menu-model">hamburger_menu_popover</property>
+ <property name="primary">True</property>
+ <property name="tooltip_text" translatable="yes">Menu</property>
+ <property name="icon-name">open-menu-symbolic</property>
</object>
</child>
- </object>
- <packing>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
-
- <child>
- <object class="GtkMenuButton" id="hamburger_menu_button">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="focus_on_click">False</property>
- <property name="popover">hamburger_menu_popover</property>
- <accelerator key="F10" signal="clicked"/>
- <property name="tooltip_text" translatable="yes">Menu</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">open-menu-symbolic</property>
+ <child type="end">
+ <object class="GtkButton" id="selection_button">
+ <property name="tooltip-text" translatable="yes">Select Items</property>
+ <signal name="clicked" handler="on_selection_button_clicked"/>
+ <child>
+ <object class="GtkImage">
+ <property name="icon_name">object-select-symbolic</property>
+ <property name="icon_size">1</property>
+ </object>
+ </child>
+ <style>
+ <class name="flat"/>
+ </style>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkButton" id="select_cancel_button">
+ <property name="visible">False</property>
+ <property name="label" translatable="yes">Cancel</property>
+ <property name="tooltip_text" translatable="yes">Cancel selection</property>
</object>
</child>
</object>
- <packing>
- <property name="pack_type">end</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="select_cancel_button">
- <property name="visible">False</property>
- <property name="can_focus">True</property>
- <property name="focus_on_click">False</property>
- <property name="label" translatable="yes">Cancel</property>
- <property name="tooltip_text" translatable="yes">Cancel selection</property>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
+ </property>
</object>
- <packing>
- <property name="name">list-pane</property>
- </packing>
</child>
<child>
- <object class="GtkSeparator" id="header_separator">
- <property name="visible">True</property>
- <style>
- <class name="sidebar"/>
- </style>
- </object>
- <packing>
+ <object class="AdwLeafletPage">
<property name="navigatable">False</property>
- </packing>
+ <property name="child">
+ <object class="GtkSeparator" id="header_separator">
+ </object>
+ </property>
+ </object>
</child>
<child>
- <object class="HdyHeaderBar" id="right_header">
- <property name="visible">True</property>
- <property name="hexpand">True</property>
- <property name="show_close_button">True</property>
- <child>
- <object class="GtkRevealer" id="back_revealer">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="transition-type">slide-right</property>
- <property name="transition-duration" bind-source="content_box"
bind-property="mode-transition-duration" bind-flags="bidirectional|sync-create"/>
+ <object class="AdwLeafletPage">
+ <property name="name">contact-pane</property>
+ <property name="child">
+ <object class="AdwHeaderBar" id="right_header">
+ <property name="hexpand">True</property>
+ <property name="show-end-title-buttons" bind-source="content_box" bind-property="folded"
bind-flags="invert-boolean | sync-create"/>
<child>
- <object class="GtkButton" id="back">
- <property name="visible">True</property>
- <property name="valign">center</property>
- <property name="use-underline">True</property>
- <signal name="clicked" handler="on_back_clicked"/>
+ <object class="GtkRevealer" id="back_revealer">
+ <property name="transition-type">slide-right</property>
+ <property name="transition-duration" bind-source="content_box"
bind-property="mode-transition-duration" bind-flags="bidirectional|sync-create"/>
+ <child>
+ <object class="GtkButton" id="back">
+ <property name="valign">center</property>
+ <property name="use-underline">True</property>
+ <property name="tooltip_text">Back</property>
+ <signal name="clicked" handler="on_back_clicked"/>
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child>
+ <object class="GtkImage" id="back_image">
+ <property name="icon-name">go-previous-symbolic</property>
+ <property name="icon-size">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <property name="title-widget">
+ <object class="AdwWindowTitle">
+ <property name="title"></property>
+ </object>
+ </property>
+ <child>
+ <object class="GtkButton" id="cancel_button">
+ <property name="visible">False</property>
+ <property name="label" translatable="yes">_Cancel</property>
+ <property name="use_underline">True</property>
+ <signal name="notify::visible" handler="on_cancel_visible"
object="ContactsMainWindow" after="yes" swapped="no"/>
<style>
- <class name="image-button"/>
+ <class name="text-button"/>
</style>
- <child internal-child="accessible">
- <object class="AtkObject" id="a11y-back">
- <property name="accessible-name" translatable="yes">Back</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkBox" id="contact_sheet_buttons">
+ <property name="visible">False</property>
+ <property name="orientation">horizontal</property>
+ <property name="spacing">3</property>
+ <property name="margin-end">6</property>
+ <!-- <property name="menu-model">contact_sheet_menu</property> -->
+ <child>
+ <object class="GtkToggleButton" id="favorite_button">
+ <property name="icon-name">starred-symbolic</property>
+ <signal name="toggled" handler="on_favorite_button_toggled"/>
</object>
</child>
<child>
- <object class="GtkImage" id="back_image">
- <property name="visible">True</property>
- <property name="icon-name">go-previous-symbolic</property>
- <property name="icon-size">1</property>
+ <object class="GtkButton" id="edit_contact_button">
+ <property name="icon-name">document-edit-symbolic</property>
+ <property name="action-name">window.edit-contact</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="delete_contact_button">
+ <property name="icon-name">user-trash-symbolic</property>
+ <property name="action-name">window.delete-contact</property>
</object>
</child>
</object>
</child>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="cancel_button">
- <property name="visible">False</property>
- <property name="can_focus">True</property>
- <property name="focus_on_click">False</property>
- <property name="label" translatable="yes">_Cancel</property>
- <property name="use_underline">True</property>
- <property name="width_request">70</property>
- <property name="valign">center</property>
- <signal name="notify::visible" handler="on_cancel_visible" object="ContactsMainWindow"
after="yes" swapped="no"/>
- <style>
- <class name="text-button"/>
- </style>
- </object>
- <packing>
- <property name="pack_type">start</property>
- </packing>
- </child>
- <child>
- <object class="GtkToggleButton" id="favorite_button">
- <property name="visible">False</property>
- <property name="can_focus">True</property>
- <property name="focus_on_click">False</property>
- <property name="valign">center</property>
- <signal name="toggled" handler="on_favorite_button_toggled"/>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">starred-symbolic</property>
- <property name="icon_size">1</property>
- </object>
- </child>
- </object>
- <packing>
- <property name="pack_type">end</property>
- <property name="position">2</property>
- </packing>
- </child>
- <child>
- <object class="GtkMenuButton" id="contact_menu_button">
- <property name="visible">False</property>
- <property name="can_focus">True</property>
- <property name="focus_on_click">False</property>
- <property name="popover">contact_sheet_menu</property>
- <property name="tooltip_text" translatable="yes">Main Menu</property>
- <child>
- <object class="GtkImage">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="icon_name">view-more-symbolic</property>
+ <child type="end">
+ <object class="GtkButton" id="done_button">
+ <property name="visible">False</property>
+ <property name="label" translatable="yes">Done</property>
+ <property name="valign">center</property>
+ <style>
+ <class name="text-button"/>
+ </style>
</object>
</child>
</object>
- <packing>
- <property name="pack_type">end</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkButton" id="done_button">
- <property name="visible">False</property>
- <property name="can_focus">True</property>
- <property name="focus_on_click">False</property>
- <property name="label" translatable="yes">Done</property>
- <property name="width_request">70</property>
- <property name="valign">center</property>
- <style>
- <class name="text-button"/>
- </style>
- </object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
- </child>
+ </property>
</object>
- <packing>
- <property name="name">contact-pane</property>
- </packing>
</child>
</object>
</child>
- <child>
+ <child>!
<object class="GtkOverlay" id="notification_overlay">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
<child>
- <object class="HdyLeaflet" id="content_box">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
+ <object class="AdwLeaflet" id="content_box">
<property name="can-swipe-back">True</property>
<signal name="notify::folded" handler="on_folded" object="ContactsMainWindow" after="yes"
swapped="no"/>
<signal name="notify::child-transition-running" handler="on_child_transition_running"
object="ContactsMainWindow" after="yes" swapped="no"/>
<child>
- <object class="GtkStack" id="list_pane_stack">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">False</property>
- <child>
- <object class="GtkBox">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="width_request">300</property>
- <property name="homogeneous">True</property>
- <child>
- <object class="GtkSpinner">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="active">True</property>
- <property name="valign">end</property>
- <property name="halign">center</property>
- <style>
- <class name="contacts-watermark"/>
- </style>
- </object>
- </child>
+ <object class="AdwLeafletPage">
+ <property name="name">list-pane</property>
+ <property name="child">
+ <object class="GtkStack" id="list_pane_stack">
+ <property name="hexpand">False</property>
<child>
- <object class="GtkLabel" id="label1">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="valign">start</property>
- <property name="halign">center</property>
- <property name="label" translatable="yes">Loading</property>
- <style>
- <class name="contacts-watermark"/>
- </style>
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <property name="width_request">300</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkSpinner">
+ <property name="spinning">True</property>
+ <property name="valign">end</property>
+ <property name="halign">center</property>
+ <style>
+ <class name="contacts-watermark"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="valign">start</property>
+ <property name="halign">center</property>
+ <property name="label" translatable="yes">Loading</property>
+ <style>
+ <class name="contacts-watermark"/>
+ </style>
+ </object>
+ </child>
</object>
</child>
</object>
- </child>
+ </property>
</object>
- <packing>
- <property name="name">list-pane</property>
- </packing>
</child>
<child>
- <object class="GtkSeparator">
- <property name="visible">True</property>
- <style>
- <class name="sidebar"/>
- </style>
- </object>
- <packing>
+ <object class="AdwLeafletPage">
<property name="navigatable">False</property>
- </packing>
+ <property name="child">
+ <object class="GtkSeparator">
+ </object>
+ </property>
+ </object>
</child>
<child>
- <object class="GtkOverlay" id="contact_pane_container">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">True</property>
- </object>
- <packing>
+ <object class="AdwLeafletPage">
<property name="name">contact-pane</property>
- </packing>
+ <property name="child">
+ <object class="GtkOverlay" id="contact_pane_container">
+ <property name="hexpand">True</property>
+ </object>
+ </property>
+ </object>
</child>
</object>
</child>
@@ -475,18 +311,4 @@
<widget name="contact_pane_container"/>
</widgets>
</object>
- <object class="HdyHeaderGroup">
- <property name="decorate-all" bind-source="content_box" bind-property="folded" bind-flags="sync-create"/>
- <headerbars>
- <headerbar name="left_header"/>
- <headerbar name="right_header"/>
- </headerbars>
- </object>
- <object class="HdySwipeGroup" id="swipe_group">
- <swipeables>
- <swipeable name="header"/>
- <swipeable name="content_box"/>
- </swipeables>
- </object>
</interface>
-
diff --git a/data/ui/contacts-setup-window.ui b/data/ui/contacts-setup-window.ui
index 845c7a0f..ccbd7ce3 100644
--- a/data/ui/contacts-setup-window.ui
+++ b/data/ui/contacts-setup-window.ui
@@ -1,86 +1,62 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <!-- interface-requires gtk+ 3.22 -->
- <template class="ContactsSetupWindow" parent="HdyApplicationWindow">
+ <template class="ContactsSetupWindow" parent="AdwApplicationWindow">
<property name="default_width">800</property>
<property name="default_height">600</property>
<child>
<object class="GtkBox">
- <property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="width_request">360</property>
<child>
- <object class="HdyHeaderBar">
- <property name="visible">True</property>
+ <object class="AdwHeaderBar">
<property name="can_focus">False</property>
- <property name="title" translatable="yes">Contacts Setup</property>
- <property name="show_close_button">False</property>
- <style>
- <class name="titlebar"/>
- </style>
+ <property name="show-start-title-buttons">False</property>
+ <property name="show-end-title-buttons">False</property>
+ <property name="title-widget">
+ <object class="AdwWindowTitle">
+ <property name="title" translatable="yes">Contacts Setup</property>
+ </object>
+ </property>
<child>
<object class="GtkButton" id="setup_quit_button">
- <property name="visible">True</property>
<property name="can_focus">True</property>
<property name="label" translatable="yes">_Quit</property>
<property name="use-underline">True</property>
+ <property name="tooltip-text">Cancel setup and quit</property>
<property name="action_name">app.quit</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="setup_quit_button_atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">Cancel setup and
quit</property>
- </object>
- </child>
</object>
- <packing>
- <property name="pack_type">start</property>
- </packing>
</child>
- <child>
+ <child type="end">
<object class="GtkButton" id="setup_done_button">
- <property name="visible">True</property>
<property name="sensitive">False</property>
- <property name="can_focus">True</property>
- <property name="focus_on_click">False</property>
<property name="label" translatable="yes">_Done</property>
+ <property name="tooltip-text" translatable="yes">Complete setup</property>
<property name="use-underline">True</property>
- <child internal-child="accessible">
- <object class="AtkObject" id="setup_done_button_atkobject">
- <property name="AtkObject::accessible-name" translatable="yes">Setup complete</property>
- </object>
- </child>
<style>
- <class name="text-button"/>
<class name="suggested-action"/>
</style>
</object>
- <packing>
- <property name="pack_type">end</property>
- </packing>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
- <property name="visible">True</property>
<property name="hscrollbar_policy">never</property>
<property name="propagate_natural_height">True</property>
<child>
- <object class="HdyClamp">
- <property name="visible">True</property>
+ <object class="AdwClamp">
<property name="margin_top">24</property>
<property name="margin_bottom">24</property>
<property name="margin_start">12</property>
<property name="margin_end">12</property>
<child>
<object class="GtkBox" id="content">
- <property name="visible">True</property>
<property name="valign">center</property>
<property name="halign">center</property>
<property name="spacing">24</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel">
- <property name="visible">True</property>
<property name="halign">center</property>
<property name="ellipsize">end</property>
<property name="label" translatable="yes">Welcome</property>
@@ -91,7 +67,6 @@
</child>
<child>
<object class="GtkLabel">
- <property name="visible">True</property>
<property name="halign">start</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
diff --git a/data/ui/style.css b/data/ui/style.css
index 67bd2ad3..33ebf132 100644
--- a/data/ui/style.css
+++ b/data/ui/style.css
@@ -7,31 +7,27 @@
background-color: transparent;
}
-.contacts-suggestion {
+/* The search entry to filter the list of contacts */
+.contacts-filter-entry {
+ margin: 6px;
+}
+
+/* The link suggestion widget */
+.contacts-link-suggestion {
border-top: 1px solid @borders;
background-color: shade(@theme_bg_color, 0.9);
}
+ .contacts-link-suggestion avatar {
+ margin: 12px;
+ }
+
/* Give the avatar in the ContactSheet some margin,
* so it doesn't jump when switching to the editor. */
.contacts-contact-sheet .contacts-avatar {
margin: 4px 8px;
}
-.contacts-postal-entry {
- border-radius: 0 0 0 0;
- border-width: 1px 1px 0 1px;
-}
-
-.contacts-postal-entry:nth-child(first) {
- border-radius: 4px 4px 0 0;
-}
-
-.contacts-postal-entry:nth-child(last) {
- border-radius: 0 0 4px 4px;
- border-width: 1px;
-}
-
/* The style for the background "watermark" image and text.
* (copied from dim-label) */
.contacts-watermark {
@@ -42,10 +38,10 @@
.contacts-avatar-popover .contact-display-name {
font-size: 20px;
}
+
flowboxchild.circular {
padding: 4px;
border-radius: 9999px;
- -gtk-outline-radius: 9999px;
}
.avatar-button {
@@ -62,14 +58,29 @@ flowboxchild.circular {
border: 1px solid rgba(205, 199, 194, 0.5);
}
-/* remove padding from ListBoxRow so that the revealer doesn't jump */
-row.editor-property-row {
- padding: 0px;
+/* Contact Editor-related CSS classes */
+
+/* Common class all widgets editing a property */
+.contacts-editor-property-row {
+ padding: 12px;
}
-popover list {
- background-color: @theme_bg_color;
+/* Class for editing postal address */
+.contacts-editor-address entry {
+ border-radius: 0;
+ border-width: 1px 1px 0 1px;
}
-popover list row:hover {
- background-color: @theme_selected_fg_color
+
+ .contacts-editor-address entry:first-child {
+ border-radius: 4px 4px 0 0;
+ }
+
+ .contacts-editor-address entry:last-child {
+ border-radius: 0 0 4px 4px;
+ border-width: 1px;
+ }
+
+/* Widget to edit a birthday */
+.contacts-editor-birthday {
+ margin: 12px;
}
diff --git a/docs/meson.build b/docs/meson.build
index 8ec997d9..8640f4d2 100644
--- a/docs/meson.build
+++ b/docs/meson.build
@@ -13,14 +13,14 @@ custom_target('docs',
'--pkg=glib-2.0',
'--pkg=gio-2.0',
'--pkg=gio-unix-2.0',
- '--pkg=gtk+-3.0',
+ '--pkg=gtk4',
'--pkg=gnome-desktop-3.0',
'--pkg=gee-0.8',
'--pkg=goa-1.0',
'--pkg=folks',
'--pkg=folks-eds',
'--pkg=libedataserverui-1.2',
- '--pkg=libhandy-1',
+ '--pkg=libadwaita-1',
'--pkg=custom',
'--pkg=config',
'--directory=@OUTDIR@',
diff --git a/meson.build b/meson.build
index c9b09be3..d433b483 100644
--- a/meson.build
+++ b/meson.build
@@ -47,14 +47,14 @@ gee = dependency('gee-0.8')
gio_unix = dependency('gio-unix-2.0', version: '>=' + min_glib_version)
glib = dependency('glib-2.0', version: '>=' + min_glib_version)
gmodule_export = dependency('gmodule-export-2.0', version: '>=' + min_glib_version)
-gnome_desktop = dependency('gnome-desktop-3.0')
+# gnome_desktop = dependency('gnome-desktop-3.0')
goa = dependency('goa-1.0')
-gtk = dependency('gtk+-3.0', version: '>= 3.23.1')
-libhandy = dependency('libhandy-1', version: '>= 1.1.0')
+gtk4_dep = dependency('gtk4', version: '>= 4.4')
+libadwaita_dep = dependency('libadwaita-1')
# E-D-S
libebook = dependency('libebook-1.2', version: '>=' + min_eds_version)
libedataserver = dependency('libedataserver-1.2', version: '>=' + min_eds_version)
-libedataserverui = dependency('libedataserverui-1.2', version: '>=' + min_eds_version)
+# libedataserverui = dependency('libedataserverui-1.2', version: '>=' + min_eds_version)
# Cheese
cheese_dep = dependency('cheese', required: get_option('cheese'))
cheese_gtk_dep = dependency('cheese-gtk', version: '>= 3.3.91', required: get_option('cheese'))
diff --git a/meson_options.txt b/meson_options.txt
index 101161cc..c672bba5 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,5 +1,5 @@
option('profile', type: 'combo', choices: [ 'default', 'development' ], value: 'default', description:
'Indicate whether this is a nightly build (used for CI purposes)')
-option('cheese', type: 'feature', value: 'auto', description: 'If enabled, allows creaing an avatar with the
webcam')
+option('camera', type: 'boolean', value: true, description: 'Support creaing an avatar with the webcam using
the XDG camera portal')
option('telepathy', type: 'boolean', value: false, description: 'Enable Telepathy call/chat support.')
option('manpage', type: 'boolean', value: true, description: 'Enable building man pages.')
option('docs', type: 'boolean', value: false, description: 'Whether to build the valadoc docs.')
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 2f3c9fae..b23cc38e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,7 +6,7 @@ data/gtk/help-overlay.ui
data/ui/contacts-accounts-list.ui
data/ui/contacts-avatar-selector.ui
data/ui/contacts-contact-pane.ui
-data/ui/contacts-crop-cheese-dialog.ui
+data/ui/contacts-crop-dialog.ui
data/ui/contacts-editor-menu.ui
data/ui/contacts-linked-personas-dialog.ui
data/ui/contacts-link-suggestion-grid.ui
@@ -23,7 +23,7 @@ src/contacts-contact-editor.vala
src/contacts-contact-list.vala
src/contacts-contact-pane.vala
src/contacts-contact-sheet.vala
-src/contacts-crop-cheese-dialog.vala
+src/contacts-crop-dialog.vala
src/contacts-editor-property.vala
src/contacts-esd-setup.vala
src/contacts-im-service.vala
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 7348e0eb..26d3f803 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -8,11 +8,11 @@ src/contacts-addressbook-list.c
src/contacts-app.c
src/contacts-avatar.c
src/contacts-avatar-selector.c
+src/contacts-camera-dialog.c
src/contacts-contact-editor.c
src/contacts-contact-list.c
src/contacts-contact-pane.c
src/contacts-contact-sheet.c
-src/contacts-crop-cheese-dialog.c
src/contacts-editor-property.c
src/contacts-esd-setup.c
src/contacts-im-service.c
diff --git a/src/cc-crop-area.c b/src/cc-crop-area.c
index 799d55c1..0c341b3c 100644
--- a/src/cc-crop-area.c
+++ b/src/cc-crop-area.c
@@ -19,8 +19,6 @@
#include "config.h"
-#include <stdlib.h>
-
#include <glib.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
@@ -28,21 +26,21 @@
#include "cc-crop-area.h"
struct _CcCropArea {
- GtkDrawingArea parent_instance;
-
- GdkPixbuf *browse_pixbuf;
- GdkPixbuf *pixbuf;
- GdkPixbuf *color_shifted;
- gdouble scale;
- GdkRectangle image;
- GdkCursorType current_cursor;
- GdkRectangle crop;
- gint active_region;
- gint last_press_x;
- gint last_press_y;
- gint base_width;
- gint base_height;
- gdouble aspect;
+ GtkDrawingArea parent_instance;
+
+ GdkPixbuf *browse_pixbuf;
+ GdkPixbuf *pixbuf;
+ GdkPixbuf *color_shifted;
+ double scale;
+ GdkRectangle image;
+ const char *current_cursor;
+ GdkRectangle crop;
+ int active_region;
+ int last_press_x;
+ int last_press_y;
+ int base_width;
+ int base_height;
+ double aspect;
};
G_DEFINE_TYPE (CcCropArea, cc_crop_area, GTK_TYPE_DRAWING_AREA);
@@ -51,757 +49,763 @@ static inline guchar
shift_color_byte (guchar b,
int shift)
{
- return CLAMP(b + shift, 0, 255);
+ return CLAMP(b + shift, 0, 255);
}
static void
shift_colors (GdkPixbuf *pixbuf,
- gint red,
- gint green,
- gint blue,
- gint alpha)
+ int red,
+ int green,
+ int blue,
+ int alpha)
{
- gint x, y, offset, y_offset, rowstride, width, height;
- guchar *pixels;
- gint channels;
-
- width = gdk_pixbuf_get_width (pixbuf);
- height = gdk_pixbuf_get_height (pixbuf);
- rowstride = gdk_pixbuf_get_rowstride (pixbuf);
- pixels = gdk_pixbuf_get_pixels (pixbuf);
- channels = gdk_pixbuf_get_n_channels (pixbuf);
-
- for (y = 0; y < height; y++) {
- y_offset = y * rowstride;
- for (x = 0; x < width; x++) {
- offset = y_offset + x * channels;
- if (red != 0)
- pixels[offset] = shift_color_byte (pixels[offset], red);
- if (green != 0)
- pixels[offset + 1] = shift_color_byte (pixels[offset + 1], green);
- if (blue != 0)
- pixels[offset + 2] = shift_color_byte (pixels[offset + 2], blue);
- if (alpha != 0 && channels >= 4)
- pixels[offset + 3] = shift_color_byte (pixels[offset + 3], blue);
- }
+ int offset, y_offset, rowstride, width, height;
+ guchar *pixels;
+ int channels;
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ channels = gdk_pixbuf_get_n_channels (pixbuf);
+
+ for (int y = 0; y < height; y++) {
+ y_offset = y * rowstride;
+ for (int x = 0; x < width; x++) {
+ offset = y_offset + x * channels;
+ if (red != 0)
+ pixels[offset] = shift_color_byte (pixels[offset], red);
+ if (green != 0)
+ pixels[offset + 1] = shift_color_byte (pixels[offset + 1], green);
+ if (blue != 0)
+ pixels[offset + 2] = shift_color_byte (pixels[offset + 2], blue);
+ if (alpha != 0 && channels >= 4)
+ pixels[offset + 3] = shift_color_byte (pixels[offset + 3], blue);
}
+ }
}
static void
update_pixbufs (CcCropArea *area)
{
- gint width;
- gint height;
- GtkAllocation allocation;
- gdouble scale;
- gint dest_width, dest_height;
- GtkWidget *widget;
-
- widget = GTK_WIDGET (area);
- gtk_widget_get_allocation (widget, &allocation);
-
- width = gdk_pixbuf_get_width (area->browse_pixbuf);
- height = gdk_pixbuf_get_height (area->browse_pixbuf);
-
- scale = allocation.height / (gdouble)height;
- if (scale * width > allocation.width)
- scale = allocation.width / (gdouble)width;
-
- dest_width = width * scale;
- dest_height = height * scale;
-
- if (area->pixbuf == NULL ||
- gdk_pixbuf_get_width (area->pixbuf) != allocation.width ||
- gdk_pixbuf_get_height (area->pixbuf) != allocation.height) {
- g_clear_object (&area->pixbuf);
- area->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
- gdk_pixbuf_get_has_alpha (area->browse_pixbuf),
- 8,
- dest_width, dest_height);
- gdk_pixbuf_fill (area->pixbuf, 0x0);
-
- gdk_pixbuf_scale (area->browse_pixbuf,
- area->pixbuf,
- 0, 0,
- dest_width, dest_height,
- 0, 0,
- scale, scale,
- GDK_INTERP_BILINEAR);
-
- g_clear_object (&area->color_shifted);
- area->color_shifted = gdk_pixbuf_copy (area->pixbuf);
- shift_colors (area->color_shifted, -100, -100, -100, 0);
-
- if (area->scale == 0.0) {
- gdouble scale_to_80, scale_to_image, crop_scale;
-
- /* Scale the crop rectangle to 80% of the area, or less to fit the image */
- scale_to_80 = MIN ((gdouble)gdk_pixbuf_get_width (area->pixbuf) * 0.8 /
area->base_width,
- (gdouble)gdk_pixbuf_get_height (area->pixbuf) * 0.8 /
area->base_height);
- scale_to_image = MIN ((gdouble)dest_width / area->base_width,
- (gdouble)dest_height / area->base_height);
- crop_scale = MIN (scale_to_80, scale_to_image);
-
- area->crop.width = crop_scale * area->base_width / scale;
- area->crop.height = crop_scale * area->base_height / scale;
- area->crop.x = (gdk_pixbuf_get_width (area->browse_pixbuf) - area->crop.width) / 2;
- area->crop.y = (gdk_pixbuf_get_height (area->browse_pixbuf) - area->crop.height) / 2;
- }
-
- area->scale = scale;
- area->image.x = (allocation.width - dest_width) / 2;
- area->image.y = (allocation.height - dest_height) / 2;
- area->image.width = dest_width;
- area->image.height = dest_height;
+ GtkWidget *widget = GTK_WIDGET (area);
+ int width;
+ int height;
+ GtkAllocation allocation;
+ double scale;
+ int dest_width, dest_height;
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ width = gdk_pixbuf_get_width (area->browse_pixbuf);
+ height = gdk_pixbuf_get_height (area->browse_pixbuf);
+
+ scale = allocation.height / (double) height;
+ if (scale * width > allocation.width)
+ scale = allocation.width / (double) width;
+
+ dest_width = width * scale;
+ dest_height = height * scale;
+
+ if (area->pixbuf == NULL ||
+ gdk_pixbuf_get_width (area->pixbuf) != allocation.width ||
+ gdk_pixbuf_get_height (area->pixbuf) != allocation.height) {
+ g_clear_object (&area->pixbuf);
+ area->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+ gdk_pixbuf_get_has_alpha (area->browse_pixbuf),
+ 8,
+ dest_width, dest_height);
+ gdk_pixbuf_fill (area->pixbuf, 0x0);
+
+ gdk_pixbuf_scale (area->browse_pixbuf,
+ area->pixbuf,
+ 0, 0,
+ dest_width, dest_height,
+ 0, 0,
+ scale, scale,
+ GDK_INTERP_BILINEAR);
+
+ g_clear_object (&area->color_shifted);
+ area->color_shifted = gdk_pixbuf_copy (area->pixbuf);
+ shift_colors (area->color_shifted, -100, -100, -100, 0);
+
+ if (area->scale == 0.0) {
+ double scale_to_80, scale_to_image, crop_scale;
+
+ /* Scale the crop rectangle to 80% of the area, or less to fit the image */
+ scale_to_80 = MIN ((double) gdk_pixbuf_get_width (area->pixbuf) * 0.8 / area->base_width,
+ (double) gdk_pixbuf_get_height (area->pixbuf) * 0.8 / area->base_height);
+ scale_to_image = MIN ((double) dest_width / area->base_width,
+ (double) dest_height / area->base_height);
+ crop_scale = MIN (scale_to_80, scale_to_image);
+
+ area->crop.width = crop_scale * area->base_width / scale;
+ area->crop.height = crop_scale * area->base_height / scale;
+ area->crop.x = (gdk_pixbuf_get_width (area->browse_pixbuf) - area->crop.width) / 2;
+ area->crop.y = (gdk_pixbuf_get_height (area->browse_pixbuf) - area->crop.height) / 2;
}
+
+ area->scale = scale;
+ area->image.x = (allocation.width - dest_width) / 2;
+ area->image.y = (allocation.height - dest_height) / 2;
+ area->image.width = dest_width;
+ area->image.height = dest_height;
+ }
}
static void
crop_to_widget (CcCropArea *area,
GdkRectangle *crop)
{
- crop->x = area->image.x + area->crop.x * area->scale;
- crop->y = area->image.y + area->crop.y * area->scale;
- crop->width = area->crop.width * area->scale;
- crop->height = area->crop.height * area->scale;
+ crop->x = area->image.x + area->crop.x * area->scale;
+ crop->y = area->image.y + area->crop.y * area->scale;
+ crop->width = area->crop.width * area->scale;
+ crop->height = area->crop.height * area->scale;
}
typedef enum {
- OUTSIDE,
- INSIDE,
- TOP,
- TOP_LEFT,
- TOP_RIGHT,
- BOTTOM,
- BOTTOM_LEFT,
- BOTTOM_RIGHT,
- LEFT,
- RIGHT
+ OUTSIDE,
+ INSIDE,
+ TOP,
+ TOP_LEFT,
+ TOP_RIGHT,
+ BOTTOM,
+ BOTTOM_LEFT,
+ BOTTOM_RIGHT,
+ LEFT,
+ RIGHT
} Location;
-static gboolean
-cc_crop_area_draw (GtkWidget *widget,
- cairo_t *cr)
+static void
+draw (GtkDrawingArea *draw_area,
+ cairo_t *cr,
+ int _width, // XXX
+ int _height, // XXX
+ gpointer user_data)
{
- GdkRectangle crop;
- gint width, height, ix, iy;
- CcCropArea *uarea = CC_CROP_AREA (widget);
-
- if (uarea->browse_pixbuf == NULL)
- return FALSE;
+ CcCropArea *uarea = CC_CROP_AREA (draw_area);
+ GdkRectangle crop;
+ int width, height, ix, iy;
- update_pixbufs (uarea);
+ if (uarea->browse_pixbuf == NULL)
+ return;
- width = gdk_pixbuf_get_width (uarea->pixbuf);
- height = gdk_pixbuf_get_height (uarea->pixbuf);
- crop_to_widget (uarea, &crop);
+ update_pixbufs (uarea);
- ix = uarea->image.x;
- iy = uarea->image.y;
+ width = gdk_pixbuf_get_width (uarea->pixbuf);
+ height = gdk_pixbuf_get_height (uarea->pixbuf);
+ crop_to_widget (uarea, &crop);
- gdk_cairo_set_source_pixbuf (cr, uarea->color_shifted, ix, iy);
- cairo_rectangle (cr, ix, iy, width, height);
- cairo_fill (cr);
+ ix = uarea->image.x;
+ iy = uarea->image.y;
- gdk_cairo_set_source_pixbuf (cr, uarea->pixbuf, ix, iy);
- cairo_arc (cr, crop.x + crop.width / 2, crop.y + crop.width / 2, crop.width / 2, 0, 2 * G_PI);
- cairo_fill (cr);
+ gdk_cairo_set_source_pixbuf (cr, uarea->color_shifted, ix, iy);
+ cairo_rectangle (cr, ix, iy, width, height);
+ cairo_fill (cr);
- // draw the four corners
- cairo_set_source_rgb (cr, 1, 1, 1);
- cairo_set_line_width (cr, 4.0);
+ gdk_cairo_set_source_pixbuf (cr, uarea->pixbuf, ix, iy);
+ cairo_arc (cr, crop.x + crop.width / 2, crop.y + crop.width / 2, crop.width / 2, 0, 2 * G_PI);
+ cairo_fill (cr);
- // top left corner
- cairo_move_to (cr, crop.x + 15, crop.y);
- cairo_line_to (cr, crop.x, crop.y);
- cairo_line_to (cr, crop.x, crop.y + 15);
+ // draw the four corners
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_set_line_width (cr, 4.0);
- // top right corner
- cairo_move_to (cr, crop.x + crop.width - 15, crop.y);
- cairo_line_to (cr, crop.x + crop.width, crop.y);
- cairo_line_to (cr, crop.x + crop.width, crop.y + 15);
+ // top left corner
+ cairo_move_to (cr, crop.x + 15, crop.y);
+ cairo_line_to (cr, crop.x, crop.y);
+ cairo_line_to (cr, crop.x, crop.y + 15);
- // bottom right corner
- cairo_move_to (cr, crop.x + crop.width - 15, crop.y + crop.height);
- cairo_line_to (cr, crop.x + crop.width, crop.y + crop.height);
- cairo_line_to (cr, crop.x + crop.width, crop.y + crop.height - 15);
+ // top right corner
+ cairo_move_to (cr, crop.x + crop.width - 15, crop.y);
+ cairo_line_to (cr, crop.x + crop.width, crop.y);
+ cairo_line_to (cr, crop.x + crop.width, crop.y + 15);
- // bottom left corner
- cairo_move_to (cr, crop.x + 15, crop.y + crop.height);
- cairo_line_to (cr, crop.x, crop.y + crop.height);
- cairo_line_to (cr, crop.x, crop.y + crop.height - 15);
+ // bottom right corner
+ cairo_move_to (cr, crop.x + crop.width - 15, crop.y + crop.height);
+ cairo_line_to (cr, crop.x + crop.width, crop.y + crop.height);
+ cairo_line_to (cr, crop.x + crop.width, crop.y + crop.height - 15);
- cairo_stroke (cr);
+ // bottom left corner
+ cairo_move_to (cr, crop.x + 15, crop.y + crop.height);
+ cairo_line_to (cr, crop.x, crop.y + crop.height);
+ cairo_line_to (cr, crop.x, crop.y + crop.height - 15);
- return FALSE;
+ cairo_stroke (cr);
}
typedef enum {
- BELOW,
- LOWER,
- BETWEEN,
- UPPER,
- ABOVE
+ BELOW,
+ LOWER,
+ BETWEEN,
+ UPPER,
+ ABOVE
} Range;
static Range
-find_range (gint x,
- gint min,
- gint max)
+find_range (int x,
+ int min,
+ int max)
{
- gint tolerance = 12;
-
- if (x < min - tolerance)
- return BELOW;
- if (x <= min + tolerance)
- return LOWER;
- if (x < max - tolerance)
- return BETWEEN;
- if (x <= max + tolerance)
- return UPPER;
- return ABOVE;
+ int tolerance = 12;
+
+ if (x < min - tolerance)
+ return BELOW;
+ if (x <= min + tolerance)
+ return LOWER;
+ if (x < max - tolerance)
+ return BETWEEN;
+ if (x <= max + tolerance)
+ return UPPER;
+ return ABOVE;
}
static Location
find_location (GdkRectangle *rect,
- gint x,
- gint y)
+ int x,
+ int y)
{
- Range x_range, y_range;
- Location location[5][5] = {
- { OUTSIDE, OUTSIDE, OUTSIDE, OUTSIDE, OUTSIDE },
- { OUTSIDE, TOP_LEFT, TOP, TOP_RIGHT, OUTSIDE },
- { OUTSIDE, LEFT, INSIDE, RIGHT, OUTSIDE },
- { OUTSIDE, BOTTOM_LEFT, BOTTOM, BOTTOM_RIGHT, OUTSIDE },
- { OUTSIDE, OUTSIDE, OUTSIDE, OUTSIDE, OUTSIDE }
- };
-
- x_range = find_range (x, rect->x, rect->x + rect->width);
- y_range = find_range (y, rect->y, rect->y + rect->height);
-
- return location[y_range][x_range];
+ Range x_range, y_range;
+ Location location[5][5] = {
+ { OUTSIDE, OUTSIDE, OUTSIDE, OUTSIDE, OUTSIDE },
+ { OUTSIDE, TOP_LEFT, TOP, TOP_RIGHT, OUTSIDE },
+ { OUTSIDE, LEFT, INSIDE, RIGHT, OUTSIDE },
+ { OUTSIDE, BOTTOM_LEFT, BOTTOM, BOTTOM_RIGHT, OUTSIDE },
+ { OUTSIDE, OUTSIDE, OUTSIDE, OUTSIDE, OUTSIDE }
+ };
+
+ x_range = find_range (x, rect->x, rect->x + rect->width);
+ y_range = find_range (y, rect->y, rect->y + rect->height);
+
+ return location[y_range][x_range];
}
static void
update_cursor (CcCropArea *area,
- gint x,
- gint y)
+ int x,
+ int y)
{
- gint cursor_type;
- GdkRectangle crop;
- gint region;
-
- region = area->active_region;
- if (region == OUTSIDE) {
- crop_to_widget (area, &crop);
- region = find_location (&crop, x, y);
- }
+ const char *cursor_type;
+ GdkRectangle crop;
+ int region;
- switch (region) {
- case OUTSIDE:
- cursor_type = GDK_LEFT_PTR;
- break;
- case TOP_LEFT:
- cursor_type = GDK_TOP_LEFT_CORNER;
- break;
- case TOP:
- cursor_type = GDK_TOP_SIDE;
- break;
- case TOP_RIGHT:
- cursor_type = GDK_TOP_RIGHT_CORNER;
- break;
- case LEFT:
- cursor_type = GDK_LEFT_SIDE;
- break;
- case INSIDE:
- cursor_type = GDK_FLEUR;
- break;
- case RIGHT:
- cursor_type = GDK_RIGHT_SIDE;
- break;
- case BOTTOM_LEFT:
- cursor_type = GDK_BOTTOM_LEFT_CORNER;
- break;
- case BOTTOM:
- cursor_type = GDK_BOTTOM_SIDE;
- break;
- case BOTTOM_RIGHT:
- cursor_type = GDK_BOTTOM_RIGHT_CORNER;
- break;
- default:
- g_assert_not_reached ();
- }
-
- if (cursor_type != area->current_cursor) {
- GdkCursor *cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (area)),
- cursor_type);
- gdk_window_set_cursor (gtk_widget_get_window (GTK_WIDGET (area)), cursor);
- g_object_unref (cursor);
- area->current_cursor = cursor_type;
+ region = area->active_region;
+ if (region == OUTSIDE) {
+ crop_to_widget (area, &crop);
+ region = find_location (&crop, x, y);
+ }
+
+ switch (region) {
+ case OUTSIDE:
+ cursor_type = "default";
+ break;
+ case TOP_LEFT:
+ cursor_type = "nw-resize";
+ break;
+ case TOP:
+ cursor_type = "n-resize";
+ break;
+ case TOP_RIGHT:
+ cursor_type = "ne-resize";
+ break;
+ case LEFT:
+ cursor_type = "w-resize";
+ break;
+ case INSIDE:
+ cursor_type = "move";
+ break;
+ case RIGHT:
+ cursor_type = "e-resize";
+ break;
+ case BOTTOM_LEFT:
+ cursor_type = "sw-resize";
+ break;
+ case BOTTOM:
+ cursor_type = "s-resize";
+ break;
+ case BOTTOM_RIGHT:
+ cursor_type = "se-resize";
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (cursor_type != area->current_cursor) {
+ GtkNative *native;
+ GdkCursor *cursor;
+
+ native = gtk_widget_get_native (GTK_WIDGET (area));
+ if (!native) {
+ g_warning ("Can't adjust cursor: no GtkNative found");
+ return;
}
+ cursor = gdk_cursor_new_from_name (cursor_type, NULL);
+ gdk_surface_set_cursor (gtk_native_get_surface (native), cursor);
+ g_object_unref (cursor);
+ area->current_cursor = cursor_type;
+ }
}
static int
-eval_radial_line (gdouble center_x, gdouble center_y,
- gdouble bounds_x, gdouble bounds_y,
- gdouble user_x)
+eval_radial_line (double center_x, double center_y,
+ double bounds_x, double bounds_y,
+ double user_x)
{
- gdouble decision_slope;
- gdouble decision_intercept;
+ double decision_slope;
+ double decision_intercept;
- decision_slope = (bounds_y - center_y) / (bounds_x - center_x);
- decision_intercept = -(decision_slope * bounds_x);
+ decision_slope = (bounds_y - center_y) / (bounds_x - center_x);
+ decision_intercept = -(decision_slope * bounds_x);
- return (int) (decision_slope * user_x + decision_intercept);
+ return (int) (decision_slope * user_x + decision_intercept);
}
static gboolean
-cc_crop_area_motion_notify_event (GtkWidget *widget,
- GdkEventMotion *event)
+on_motion (GtkEventControllerMotion *controller,
+ double event_x,
+ double event_y,
+ gpointer user_data)
{
- CcCropArea *area = CC_CROP_AREA (widget);
- gint x, y;
- gint delta_x, delta_y;
- gint width, height;
- gint adj_width, adj_height;
- gint pb_width, pb_height;
- GdkRectangle damage;
- gint left, right, top, bottom;
- gdouble new_width, new_height;
- gdouble center_x, center_y;
- gint min_width, min_height;
-
- if (area->browse_pixbuf == NULL)
- return FALSE;
-
- update_cursor (area, event->x, event->y);
-
- crop_to_widget (area, &damage);
- gtk_widget_queue_draw_area (widget,
- damage.x - 4, damage.y - 4,
- damage.width + 6, damage.height + 6);
-
- pb_width = gdk_pixbuf_get_width (area->browse_pixbuf);
- pb_height = gdk_pixbuf_get_height (area->browse_pixbuf);
-
- x = (event->x - area->image.x) / area->scale;
- y = (event->y - area->image.y) / area->scale;
-
- delta_x = x - area->last_press_x;
- delta_y = y - area->last_press_y;
- area->last_press_x = x;
- area->last_press_y = y;
-
- left = area->crop.x;
- right = area->crop.x + area->crop.width - 1;
- top = area->crop.y;
- bottom = area->crop.y + area->crop.height - 1;
-
- center_x = (left + right) / 2.0;
- center_y = (top + bottom) / 2.0;
+ CcCropArea *area = CC_CROP_AREA (user_data);
+ int x, y;
+ int delta_x, delta_y;
+ int width, height;
+ int adj_width, adj_height;
+ int pb_width, pb_height;
+ GdkRectangle damage;
+ int left, right, top, bottom;
+ double new_width, new_height;
+ double center_x, center_y;
+ int min_width, min_height;
+
+ if (area->browse_pixbuf == NULL)
+ return FALSE;
- switch (area->active_region) {
- case INSIDE:
- width = right - left + 1;
- height = bottom - top + 1;
-
- left += delta_x;
- right += delta_x;
- top += delta_y;
- bottom += delta_y;
-
- if (left < 0)
- left = 0;
- if (top < 0)
- top = 0;
- if (right > pb_width)
- right = pb_width;
- if (bottom > pb_height)
- bottom = pb_height;
-
- adj_width = right - left + 1;
- adj_height = bottom - top + 1;
- if (adj_width != width) {
- if (delta_x < 0)
- right = left + width - 1;
- else
- left = right - width + 1;
- }
- if (adj_height != height) {
- if (delta_y < 0)
- bottom = top + height - 1;
- else
- top = bottom - height + 1;
- }
-
- break;
+ update_cursor (area, event_x, event_y);
- case TOP_LEFT:
- if (area->aspect < 0) {
- top = y;
- left = x;
- }
- else if (y < eval_radial_line (center_x, center_y, left, top, x)) {
- top = y;
- new_width = (bottom - top) * area->aspect;
- left = right - new_width;
- }
- else {
- left = x;
- new_height = (right - left) / area->aspect;
- top = bottom - new_height;
- }
- break;
+ crop_to_widget (area, &damage);
+ // XXX
+ /* gtk_widget_queue_draw_area (GTK_WIDGET (area), */
+ /* damage.x - 4, damage.y - 4, */
+ /* damage.width + 6, damage.height + 6); */
- case TOP:
- top = y;
- if (area->aspect > 0) {
- new_width = (bottom - top) * area->aspect;
- right = left + new_width;
- }
- break;
+ pb_width = gdk_pixbuf_get_width (area->browse_pixbuf);
+ pb_height = gdk_pixbuf_get_height (area->browse_pixbuf);
- case TOP_RIGHT:
- if (area->aspect < 0) {
- top = y;
- right = x;
- }
- else if (y < eval_radial_line (center_x, center_y, right, top, x)) {
- top = y;
- new_width = (bottom - top) * area->aspect;
- right = left + new_width;
- }
- else {
- right = x;
- new_height = (right - left) / area->aspect;
- top = bottom - new_height;
- }
- break;
+ x = (event_x - area->image.x) / area->scale;
+ y = (event_y - area->image.y) / area->scale;
- case LEFT:
- left = x;
- if (area->aspect > 0) {
- new_height = (right - left) / area->aspect;
- bottom = top + new_height;
- }
- break;
+ delta_x = x - area->last_press_x;
+ delta_y = y - area->last_press_y;
+ area->last_press_x = x;
+ area->last_press_y = y;
- case BOTTOM_LEFT:
- if (area->aspect < 0) {
- bottom = y;
- left = x;
- }
- else if (y < eval_radial_line (center_x, center_y, left, bottom, x)) {
- left = x;
- new_height = (right - left) / area->aspect;
- bottom = top + new_height;
- }
- else {
- bottom = y;
- new_width = (bottom - top) * area->aspect;
- left = right - new_width;
- }
- break;
+ left = area->crop.x;
+ right = area->crop.x + area->crop.width - 1;
+ top = area->crop.y;
+ bottom = area->crop.y + area->crop.height - 1;
- case RIGHT:
- right = x;
- if (area->aspect > 0) {
- new_height = (right - left) / area->aspect;
- bottom = top + new_height;
- }
- break;
+ center_x = (left + right) / 2.0;
+ center_y = (top + bottom) / 2.0;
- case BOTTOM_RIGHT:
- if (area->aspect < 0) {
- bottom = y;
- right = x;
- }
- else if (y < eval_radial_line (center_x, center_y, right, bottom, x)) {
- right = x;
- new_height = (right - left) / area->aspect;
- bottom = top + new_height;
- }
- else {
- bottom = y;
- new_width = (bottom - top) * area->aspect;
- right = left + new_width;
- }
- break;
+ switch (area->active_region) {
+ case INSIDE:
+ width = right - left + 1;
+ height = bottom - top + 1;
- case BOTTOM:
- bottom = y;
- if (area->aspect > 0) {
- new_width = (bottom - top) * area->aspect;
- right= left + new_width;
- }
- break;
-
- default:
- return FALSE;
+ left += delta_x;
+ right += delta_x;
+ top += delta_y;
+ bottom += delta_y;
+
+ if (left < 0)
+ left = 0;
+ if (top < 0)
+ top = 0;
+ if (right > pb_width)
+ right = pb_width;
+ if (bottom > pb_height)
+ bottom = pb_height;
+
+ adj_width = right - left + 1;
+ adj_height = bottom - top + 1;
+ if (adj_width != width) {
+ if (delta_x < 0)
+ right = left + width - 1;
+ else
+ left = right - width + 1;
+ }
+ if (adj_height != height) {
+ if (delta_y < 0)
+ bottom = top + height - 1;
+ else
+ top = bottom - height + 1;
}
- min_width = area->base_width / area->scale;
- min_height = area->base_height / area->scale;
+ break;
- width = right - left + 1;
- height = bottom - top + 1;
+ case TOP_LEFT:
if (area->aspect < 0) {
- if (left < 0)
- left = 0;
- if (top < 0)
- top = 0;
- if (right > pb_width)
- right = pb_width;
- if (bottom > pb_height)
- bottom = pb_height;
-
- width = right - left + 1;
- height = bottom - top + 1;
-
- switch (area->active_region) {
- case LEFT:
- case TOP_LEFT:
- case BOTTOM_LEFT:
- if (width < min_width)
- left = right - min_width;
- break;
- case RIGHT:
- case TOP_RIGHT:
- case BOTTOM_RIGHT:
- if (width < min_width)
- right = left + min_width;
- break;
-
- default: ;
- }
-
- switch (area->active_region) {
- case TOP:
- case TOP_LEFT:
- case TOP_RIGHT:
- if (height < min_height)
- top = bottom - min_height;
- break;
- case BOTTOM:
- case BOTTOM_LEFT:
- case BOTTOM_RIGHT:
- if (height < min_height)
- bottom = top + min_height;
- break;
-
- default: ;
- }
+ top = y;
+ left = x;
+ }
+ else if (y < eval_radial_line (center_x, center_y, left, top, x)) {
+ top = y;
+ new_width = (bottom - top) * area->aspect;
+ left = right - new_width;
}
else {
- if (left < 0 || top < 0 ||
- right > pb_width || bottom > pb_height ||
- width < min_width || height < min_height) {
- left = area->crop.x;
- right = area->crop.x + area->crop.width - 1;
- top = area->crop.y;
- bottom = area->crop.y + area->crop.height - 1;
- }
+ left = x;
+ new_height = (right - left) / area->aspect;
+ top = bottom - new_height;
+ }
+ break;
+
+ case TOP:
+ top = y;
+ if (area->aspect > 0) {
+ new_width = (bottom - top) * area->aspect;
+ right = left + new_width;
+ }
+ break;
+
+ case TOP_RIGHT:
+ if (area->aspect < 0) {
+ top = y;
+ right = x;
+ }
+ else if (y < eval_radial_line (center_x, center_y, right, top, x)) {
+ top = y;
+ new_width = (bottom - top) * area->aspect;
+ right = left + new_width;
+ }
+ else {
+ right = x;
+ new_height = (right - left) / area->aspect;
+ top = bottom - new_height;
+ }
+ break;
+
+ case LEFT:
+ left = x;
+ if (area->aspect > 0) {
+ new_height = (right - left) / area->aspect;
+ bottom = top + new_height;
+ }
+ break;
+
+ case BOTTOM_LEFT:
+ if (area->aspect < 0) {
+ bottom = y;
+ left = x;
+ }
+ else if (y < eval_radial_line (center_x, center_y, left, bottom, x)) {
+ left = x;
+ new_height = (right - left) / area->aspect;
+ bottom = top + new_height;
+ }
+ else {
+ bottom = y;
+ new_width = (bottom - top) * area->aspect;
+ left = right - new_width;
+ }
+ break;
+
+ case RIGHT:
+ right = x;
+ if (area->aspect > 0) {
+ new_height = (right - left) / area->aspect;
+ bottom = top + new_height;
}
+ break;
- area->crop.x = left;
- area->crop.y = top;
- area->crop.width = right - left + 1;
- area->crop.height = bottom - top + 1;
+ case BOTTOM_RIGHT:
+ if (area->aspect < 0) {
+ bottom = y;
+ right = x;
+ }
+ else if (y < eval_radial_line (center_x, center_y, right, bottom, x)) {
+ right = x;
+ new_height = (right - left) / area->aspect;
+ bottom = top + new_height;
+ }
+ else {
+ bottom = y;
+ new_width = (bottom - top) * area->aspect;
+ right = left + new_width;
+ }
+ break;
- crop_to_widget (area, &damage);
- gtk_widget_queue_draw_area (widget,
- damage.x - 4, damage.y - 4,
- damage.width + 6, damage.height + 6);
+ case BOTTOM:
+ bottom = y;
+ if (area->aspect > 0) {
+ new_width = (bottom - top) * area->aspect;
+ right= left + new_width;
+ }
+ break;
+ default:
return FALSE;
-}
+ }
+
+ min_width = area->base_width / area->scale;
+ min_height = area->base_height / area->scale;
+
+ width = right - left + 1;
+ height = bottom - top + 1;
+ if (area->aspect < 0) {
+ if (left < 0)
+ left = 0;
+ if (top < 0)
+ top = 0;
+ if (right > pb_width)
+ right = pb_width;
+ if (bottom > pb_height)
+ bottom = pb_height;
-static gboolean
-cc_crop_area_button_press_event (GtkWidget *widget,
- GdkEventButton *event)
-{
- CcCropArea *area = CC_CROP_AREA (widget);
- GdkRectangle crop;
+ width = right - left + 1;
+ height = bottom - top + 1;
- if (area->browse_pixbuf == NULL)
- return FALSE;
+ switch (area->active_region) {
+ case LEFT:
+ case TOP_LEFT:
+ case BOTTOM_LEFT:
+ if (width < min_width)
+ left = right - min_width;
+ break;
+ case RIGHT:
+ case TOP_RIGHT:
+ case BOTTOM_RIGHT:
+ if (width < min_width)
+ right = left + min_width;
+ break;
- crop_to_widget (area, &crop);
+ default: ;
+ }
+
+ switch (area->active_region) {
+ case TOP:
+ case TOP_LEFT:
+ case TOP_RIGHT:
+ if (height < min_height)
+ top = bottom - min_height;
+ break;
+ case BOTTOM:
+ case BOTTOM_LEFT:
+ case BOTTOM_RIGHT:
+ if (height < min_height)
+ bottom = top + min_height;
+ break;
- area->last_press_x = (event->x - area->image.x) / area->scale;
- area->last_press_y = (event->y - area->image.y) / area->scale;
- area->active_region = find_location (&crop, event->x, event->y);
+ default: ;
+ }
+ }
+ else {
+ if (left < 0 || top < 0 ||
+ right > pb_width || bottom > pb_height ||
+ width < min_width || height < min_height) {
+ left = area->crop.x;
+ right = area->crop.x + area->crop.width - 1;
+ top = area->crop.y;
+ bottom = area->crop.y + area->crop.height - 1;
+ }
+ }
- gtk_widget_queue_draw_area (widget,
- crop.x - 4, crop.y - 4,
- crop.width + 6, crop.height + 6);
+ area->crop.x = left;
+ area->crop.y = top;
+ area->crop.width = right - left + 1;
+ area->crop.height = bottom - top + 1;
- return FALSE;
+ crop_to_widget (area, &damage);
+ // XXX
+ /* gtk_widget_queue_draw_area (GTK_WIDGET (area), */
+ /* damage.x - 4, damage.y - 4, */
+ /* damage.width + 6, damage.height + 6); */
+
+ return FALSE;
}
static gboolean
-cc_crop_area_button_release_event (GtkWidget *widget,
- GdkEventButton *event)
+on_button_pressed (GtkGestureClick *gesture,
+ int n_press,
+ double x,
+ double y,
+ gpointer user_data)
{
- CcCropArea *area = CC_CROP_AREA (widget);
- GdkRectangle crop;
+ CcCropArea *area = CC_CROP_AREA (user_data);
+ GdkRectangle crop;
- if (area->browse_pixbuf == NULL)
- return FALSE;
+ if (area->browse_pixbuf == NULL)
+ return FALSE;
- crop_to_widget (area, &crop);
+ crop_to_widget (area, &crop);
- area->last_press_x = -1;
- area->last_press_y = -1;
- area->active_region = OUTSIDE;
+ area->last_press_x = (x - area->image.x) / area->scale;
+ area->last_press_y = (y - area->image.y) / area->scale;
+ area->active_region = find_location (&crop, x, y);
- gtk_widget_queue_draw_area (widget,
- crop.x - 4, crop.y - 4,
- crop.width + 6, crop.height + 6);
+ // XXX
+ /* gtk_widget_queue_draw_area (GTK_WIDGET (area), */
+ /* crop.x - 4, crop.y - 4, */
+ /* crop.width + 6, crop.height + 6); */
- return FALSE;
+ return GDK_EVENT_PROPAGATE;
}
-static void
-cc_crop_area_set_size_request (CcCropArea *area)
+static gboolean
+on_button_released (GtkGestureClick *gesture,
+ int n_press,
+ double x,
+ double y,
+ gpointer user_data)
{
- gtk_widget_set_size_request (GTK_WIDGET (area),
- area->base_width,
- area->base_height);
+ CcCropArea *area = CC_CROP_AREA (user_data);
+ GdkRectangle crop;
+
+ if (area->browse_pixbuf == NULL)
+ return FALSE;
+
+ crop_to_widget (area, &crop);
+
+ area->last_press_x = -1;
+ area->last_press_y = -1;
+ area->active_region = OUTSIDE;
+
+ // XXX
+ /* gtk_widget_queue_draw_area (GTK_WIDGET (area), */
+ /* crop.x - 4, crop.y - 4, */
+ /* crop.width + 6, crop.height + 6); */
+
+ return GDK_EVENT_PROPAGATE;
}
static void
cc_crop_area_finalize (GObject *object)
{
- CcCropArea *area = CC_CROP_AREA (object);
+ CcCropArea *area = CC_CROP_AREA (object);
- if (area->browse_pixbuf) {
- g_object_unref (area->browse_pixbuf);
- area->browse_pixbuf = NULL;
- }
- if (area->pixbuf) {
- g_object_unref (area->pixbuf);
- area->pixbuf = NULL;
- }
- if (area->color_shifted) {
- g_object_unref (area->color_shifted);
- area->color_shifted = NULL;
- }
+ g_clear_object (&area->browse_pixbuf);
+ g_clear_object (&area->pixbuf);
+ g_clear_object (&area->color_shifted);
}
static void
cc_crop_area_class_init (CcCropAreaClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
-
- object_class->finalize = cc_crop_area_finalize;
- widget_class->draw = cc_crop_area_draw;
- widget_class->button_press_event = cc_crop_area_button_press_event;
- widget_class->button_release_event = cc_crop_area_button_release_event;
- widget_class->motion_notify_event = cc_crop_area_motion_notify_event;
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = cc_crop_area_finalize;
}
static void
cc_crop_area_init (CcCropArea *area)
{
- gtk_widget_add_events (GTK_WIDGET (area), GDK_POINTER_MOTION_MASK |
- GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK);
-
- area->scale = 0.0;
- area->image.x = 0;
- area->image.y = 0;
- area->image.width = 0;
- area->image.height = 0;
- area->active_region = OUTSIDE;
- area->base_width = 48;
- area->base_height = 48;
- area->aspect = 1;
-
- cc_crop_area_set_size_request (area);
+ GtkGesture *gesture;
+ GtkEventController *controller;
+
+ /* Draw function */
+ gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw, NULL, NULL);
+
+ /* Add handlers for clicks */
+ gesture = gtk_gesture_click_new ();
+ g_signal_connect (gesture, "pressed", G_CALLBACK (on_button_pressed), area);
+ g_signal_connect (gesture, "released", G_CALLBACK (on_button_released), area);
+ gtk_widget_add_controller (GTK_WIDGET (area), GTK_EVENT_CONTROLLER (gesture));
+
+ /* Add handlers for motion events */
+ controller = gtk_event_controller_motion_new ();
+ g_signal_connect (controller, "motion", G_CALLBACK (on_motion), area);
+ gtk_widget_add_controller (GTK_WIDGET (area), GTK_EVENT_CONTROLLER (controller));
+
+ area->scale = 0.0;
+ area->image.x = 0;
+ area->image.y = 0;
+ area->image.width = 0;
+ area->image.height = 0;
+ area->active_region = OUTSIDE;
+ area->base_width = 48;
+ area->base_height = 48;
+ area->aspect = 1;
+
+ gtk_widget_set_size_request (GTK_WIDGET (area),
+ area->base_width,
+ area->base_height);
}
GtkWidget *
cc_crop_area_new (void)
{
- return g_object_new (CC_TYPE_CROP_AREA, NULL);
+ return g_object_new (CC_TYPE_CROP_AREA, NULL);
}
GdkPixbuf *
cc_crop_area_get_picture (CcCropArea *area)
{
- gint width, height;
+ int width, height;
- width = gdk_pixbuf_get_width (area->browse_pixbuf);
- height = gdk_pixbuf_get_height (area->browse_pixbuf);
- width = MIN (area->crop.width, width - area->crop.x);
- height = MIN (area->crop.height, height - area->crop.y);
+ width = gdk_pixbuf_get_width (area->browse_pixbuf);
+ height = gdk_pixbuf_get_height (area->browse_pixbuf);
+ width = MIN (area->crop.width, width - area->crop.x);
+ height = MIN (area->crop.height, height - area->crop.y);
- return gdk_pixbuf_new_subpixbuf (area->browse_pixbuf,
- area->crop.x,
- area->crop.y,
- width, height);
+ return gdk_pixbuf_new_subpixbuf (area->browse_pixbuf,
+ area->crop.x,
+ area->crop.y,
+ width, height);
}
void
cc_crop_area_set_picture (CcCropArea *area,
GdkPixbuf *pixbuf)
{
- int width;
- int height;
+ int width = 0;
+ int height = 0;
- if (area->browse_pixbuf) {
- g_object_unref (area->browse_pixbuf);
- area->browse_pixbuf = NULL;
- }
- if (pixbuf) {
- area->browse_pixbuf = g_object_ref (pixbuf);
- width = gdk_pixbuf_get_width (pixbuf);
- height = gdk_pixbuf_get_height (pixbuf);
- } else {
- width = 0;
- height = 0;
- }
+ g_clear_object (&area->browse_pixbuf);
+ if (pixbuf) {
+ area->browse_pixbuf = g_object_ref (pixbuf);
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ }
- area->crop.width = 2 * area->base_width;
- area->crop.height = 2 * area->base_height;
- area->crop.x = (width - area->crop.width) / 2;
- area->crop.y = (height - area->crop.height) / 2;
+ area->crop.width = 2 * area->base_width;
+ area->crop.height = 2 * area->base_height;
+ area->crop.x = (width - area->crop.width) / 2;
+ area->crop.y = (height - area->crop.height) / 2;
- area->scale = 0.0;
- area->image.x = 0;
- area->image.y = 0;
- area->image.width = 0;
- area->image.height = 0;
+ area->scale = 0.0;
+ area->image.x = 0;
+ area->image.y = 0;
+ area->image.width = 0;
+ area->image.height = 0;
- gtk_widget_queue_draw (GTK_WIDGET (area));
+ // XXX
+ /* gtk_widget_queue_draw (GTK_WIDGET (area)); */
}
void
cc_crop_area_set_min_size (CcCropArea *area,
- gint width,
- gint height)
+ int width,
+ int height)
{
- area->base_width = width;
- area->base_height = height;
+ area->base_width = width;
+ area->base_height = height;
- cc_crop_area_set_size_request (area);
+ gtk_widget_set_size_request (GTK_WIDGET (area),
+ area->base_width,
+ area->base_height);
- if (area->aspect > 0) {
- area->aspect = area->base_width / (gdouble)area->base_height;
- }
+ if (area->aspect > 0)
+ area->aspect = area->base_width / (double) area->base_height;
}
void
cc_crop_area_set_constrain_aspect (CcCropArea *area,
gboolean constrain)
{
- if (constrain) {
- area->aspect = area->base_width / (gdouble)area->base_height;
- }
- else {
- area->aspect = -1;
- }
+ if (constrain) {
+ area->aspect = area->base_width / (double) area->base_height;
+ } else {
+ area->aspect = -1;
+ }
}
-
diff --git a/src/contacts-accounts-list.vala b/src/contacts-accounts-list.vala
index 9690e917..265c04cd 100644
--- a/src/contacts-accounts-list.vala
+++ b/src/contacts-accounts-list.vala
@@ -18,26 +18,31 @@
using Folks;
[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-accounts-list.ui")]
-public class Contacts.AccountsList : Gtk.ListBox {
- private Gtk.ListBoxRow last_selected_row;
+public class Contacts.AccountsList : Adw.Bin {
- private Store contacts_store;
+ [GtkChild]
+ private unowned Gtk.ListBox listbox;
+ private unowned Gtk.ListBoxRow? last_selected_row = null;
- public PersonaStore? selected_store;
+ private Store contacts_store;
+ public PersonaStore? selected_store = null;
public signal void account_selected ();
+ construct {
+ this.listbox.row_activated.connect (on_row_activated);
+ }
+
public AccountsList (Store contacts_store) {
this.contacts_store = contacts_store;
- this.selected_store = null;
}
- public override void row_activated (Gtk.ListBoxRow row) {
+ private void on_row_activated (Gtk.ListBox listbox, Gtk.ListBoxRow? row) {
if (row == null)
return;
- if (last_selected_row != null &&
- last_selected_row == row) {
+ if (this.last_selected_row != null &&
+ this.last_selected_row == row) {
return;
}
@@ -45,29 +50,33 @@ public class Contacts.AccountsList : Gtk.ListBox {
checkmark.show ();
if (last_selected_row != null) {
- checkmark = last_selected_row.get_data<Gtk.Image> ("checkmark");
+ checkmark = this.last_selected_row.get_data<Gtk.Image> ("checkmark");
if (checkmark != null)
checkmark.hide ();
}
- last_selected_row = row;
-
- selected_store = row.get_data<PersonaStore> ("store");
+ // Update the fields
+ this.last_selected_row = row;
+ this.selected_store = row.get_data<PersonaStore> ("store");
account_selected ();
}
public void update_contents (bool select_active) {
- foreach (var child in get_children ()) {
- child.destroy ();
+ // Remove all entries
+ var child = this.listbox.get_first_child ();
+ while (child != null) {
+ var next = child.get_next_sibling ();
+ this.listbox.remove (child);
+ child = next;
}
// Fill the list with address book
PersonaStore[] eds_stores = Utils.get_eds_address_books (this.contacts_store);
debug ("Found %d EDS stores", eds_stores.length);
- PersonaStore? local_store = null;
- foreach (var persona_store in eds_stores) {
+ unowned PersonaStore? local_store = null;
+ foreach (unowned var persona_store in eds_stores) {
if (persona_store.id == "system-address-book") {
local_store = persona_store;
continue;
@@ -85,63 +94,60 @@ public class Contacts.AccountsList : Gtk.ListBox {
source_account_id = goa_source_ext.account_id;
}
- var row = new Hdy.ActionRow ();
+ var row = new Adw.ActionRow ();
row.set_data ("store", persona_store);
Gtk.Image provider_image;
if (source_account_id != "")
provider_image = Contacts.get_icon_for_goa_account (source_account_id);
else
- provider_image = new Gtk.Image.from_icon_name (Config.APP_ID,
- Gtk.IconSize.DIALOG);
+ provider_image = new Gtk.Image.from_icon_name (Config.APP_ID);
+ provider_image.icon_size = Gtk.IconSize.LARGE;
row.add_prefix (provider_image);
row.title = provider_name;
row.subtitle = parent_source.display_name;
- row.show_all ();
- row.no_show_all = true;
- var checkmark = new Gtk.Image.from_icon_name ("object-select-symbolic",
- Gtk.IconSize.MENU);
- checkmark.set ("margin-end", 6,
- "valign", Gtk.Align.CENTER,
- "halign", Gtk.Align.END,
- "vexpand", true,
- "hexpand", true);
- row.add (checkmark);
+
+ var checkmark = new Gtk.Image.from_icon_name ("object-select-symbolic");
+ checkmark.margin_end = 6;
+ checkmark.valign = Gtk.Align.CENTER;
+ checkmark.halign = Gtk.Align.END;
+ checkmark.hexpand = true;
+ checkmark.vexpand = true;
+ checkmark.visible = (persona_store == this.contacts_store.aggregator.primary_store);
+ row.add_suffix (checkmark);
row.set_activatable_widget (checkmark);
row.set_data ("checkmark", checkmark);
- add (row);
+
+ this.listbox.append (row);
if (select_active &&
persona_store == this.contacts_store.aggregator.primary_store) {
- row_activated (row);
+ this.listbox.row_activated (row);
}
}
if (local_store != null) {
- var local_row = new Hdy.ActionRow ();
- var provider_image = new Gtk.Image.from_icon_name (Config.APP_ID,
- Gtk.IconSize.DIALOG);
+ var local_row = new Adw.ActionRow ();
+ var provider_image = new Gtk.Image.from_icon_name (Config.APP_ID);
+ provider_image.icon_size = Gtk.IconSize.LARGE;
local_row.add_prefix (provider_image);
local_row.title = _("Local Address Book");
- local_row.show_all ();
- local_row.no_show_all = true;
- var checkmark = new Gtk.Image.from_icon_name ("object-select-symbolic", Gtk.IconSize.MENU);
- checkmark.set ("margin-end", 6,
- "valign", Gtk.Align.CENTER,
- "halign", Gtk.Align.END,
- "vexpand", true,
- "hexpand", true);
- local_row.add (checkmark);
+ var checkmark = new Gtk.Image.from_icon_name ("object-select-symbolic");
+ checkmark.margin_end = 6;
+ checkmark.valign = Gtk.Align.CENTER;
+ checkmark.halign = Gtk.Align.END;
+ checkmark.hexpand = true;
+ checkmark.vexpand = true;
+ checkmark.visible = (local_store == this.contacts_store.aggregator.primary_store);
+ local_row.add_suffix (checkmark);
local_row.set_activatable_widget (checkmark);
local_row.set_data ("checkmark", checkmark);
local_row.set_data ("store", local_store);
- add (local_row);
+ this.listbox.append (local_row);
if (select_active &&
local_store == this.contacts_store.aggregator.primary_store) {
- row_activated (local_row);
+ this.listbox.row_activated (local_row);
}
}
-
- show_all ();
}
}
diff --git a/src/contacts-addressbook-dialog.vala b/src/contacts-addressbook-dialog.vala
index f9cc8275..4898dc7e 100644
--- a/src/contacts-addressbook-dialog.vala
+++ b/src/contacts-addressbook-dialog.vala
@@ -31,36 +31,34 @@ public class Contacts.AddressbookDialog : Gtk.Dialog {
add_buttons (_("Change"), Gtk.ResponseType.OK,
_("Cancel"), Gtk.ResponseType.CANCEL);
- var content_area = get_content_area () as Gtk.Box;
- content_area.border_width = 0;
-
var ok_button = get_widget_for_response (Gtk.ResponseType.OK);
ok_button.sensitive = false;
ok_button.get_style_context ().add_class ("suggested-action");
- var scrolled_window = new Gtk.ScrolledWindow (null, null);
- scrolled_window.expand = true;
+ var scrolled_window = new Gtk.ScrolledWindow ();
+ scrolled_window.hexpand = true;
+ scrolled_window.vexpand = true;
scrolled_window.height_request = 300;
scrolled_window.hscrollbar_policy = Gtk.PolicyType.NEVER;
scrolled_window.propagate_natural_height = true;
- content_area.add (scrolled_window);
+ ((Gtk.Box) this.get_content_area ()).append (scrolled_window);
- var clamp = new Hdy.Clamp ();
+ var clamp = new Adw.Clamp ();
clamp.margin_top = 32;
clamp.margin_bottom = 32;
clamp.margin_start = 12;
clamp.margin_end = 12;
clamp.maximum_size = 400;
- scrolled_window.add (clamp);
+ scrolled_window.set_child (clamp);
var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 12);
box.valign = Gtk.Align.START;
- clamp.add (box);
+ clamp.set_child (box);
var explanation_label = new Gtk.Label (_("New contacts will be added to the selected address book.\nYou
are able to view and edit contacts from other address books."));
explanation_label.xalign = 0;
explanation_label.wrap = true;
- box.add (explanation_label);
+ box.append (explanation_label);
this.accounts_list = new AccountsList (contacts_store);
this.accounts_list.update_contents (true);
@@ -75,9 +73,7 @@ public class Contacts.AddressbookDialog : Gtk.Dialog {
this.accounts_list.update_contents (true);
});
- box.add (this.accounts_list);
-
- show_all ();
+ box.append (this.accounts_list);
}
public override void response (int response) {
diff --git a/src/contacts-addressbook-list.vala b/src/contacts-addressbook-list.vala
index a7b26167..8b8a1c66 100644
--- a/src/contacts-addressbook-list.vala
+++ b/src/contacts-addressbook-list.vala
@@ -19,18 +19,28 @@
using Folks;
-public class Contacts.AddressbookList : Gtk.ListBox {
+public class Contacts.AddressbookList : Adw.Bin {
+
private BackendStore store;
- private AddressbookRow? marked_row;
private bool show_icon;
+ private unowned Gtk.ListBox listbox;
+ private AddressbookRow? marked_row = null;
+
public signal void addressbook_selected ();
+ construct {
+ var list_box = new Gtk.ListBox ();
+ list_box.row_activated.connect (on_row_activated);
+ list_box.set_header_func (list_box_update_header_func);
+ this.listbox = list_box;
+ this.child = this.listbox;
+ }
+
public AddressbookList (BackendStore store, bool icon = true) {
this.store = store;
this.show_icon = icon;
- this.set_header_func (list_box_update_header_func);
this.update ();
}
@@ -44,7 +54,7 @@ public class Contacts.AddressbookList : Gtk.ListBox {
}
}
- public override void row_activated (Gtk.ListBoxRow row) {
+ private void on_row_activated (Gtk.ListBox listbox, Gtk.ListBoxRow row) {
var addressbook = row as AddressbookRow;
if (addressbook == null)
return;
@@ -62,8 +72,12 @@ public class Contacts.AddressbookList : Gtk.ListBox {
}
public void update () {
- foreach (var child in get_children ()) {
- child.destroy ();
+ // Remove all entries
+ var child = this.listbox.get_first_child ();
+ while (child != null) {
+ var next = child.get_next_sibling ();
+ this.listbox.remove (child);
+ child = next;
}
// Fill the list with address book
@@ -93,25 +107,24 @@ public class Contacts.AddressbookList : Gtk.ListBox {
if (source_account_id != "")
provider_image = Contacts.get_icon_for_goa_account (source_account_id);
else
- provider_image = new Gtk.Image.from_icon_name (Config.APP_ID, Gtk.IconSize.DIALOG);
+ provider_image = new Gtk.Image.from_icon_name (Config.APP_ID);
}
var row = new AddressbookRow (provider_name, parent_source.display_name, provider_image);
- add (row);
+ this.listbox.append (row);
}
if (local_store != null) {
- var provider_image = this.show_icon? new Gtk.Image.from_icon_name (Config.APP_ID, Gtk.IconSize.DIALOG)
: null;
+ var provider_image = this.show_icon? new Gtk.Image.from_icon_name (Config.APP_ID) : null;
var local_row = new AddressbookRow (_("Local Address Book"), null, provider_image);
- add (local_row);
+ this.listbox.append (local_row);
}
-
- show_all ();
}
}
-public class Contacts.AddressbookRow : Hdy.ActionRow {
+public class Contacts.AddressbookRow : Adw.ActionRow {
Gtk.Widget checkmark;
+
public AddressbookRow (string title, string? subtitle, Gtk.Widget? image = null) {
this.set_selectable (false);
if (image != null) {
@@ -121,15 +134,13 @@ public class Contacts.AddressbookRow : Hdy.ActionRow {
if (subtitle != null) {
this.subtitle = subtitle;
}
- this.show_all ();
- this.no_show_all = true;
- this.checkmark = new Gtk.Image.from_icon_name ("object-select-symbolic", Gtk.IconSize.MENU);
+ this.checkmark = new Gtk.Image.from_icon_name ("object-select-symbolic");
this.checkmark.set ("margin-end", 6,
"valign", Gtk.Align.CENTER,
"halign", Gtk.Align.END,
"vexpand", true,
"hexpand", true);
- this.add (this.checkmark);
+ this.set_child (this.checkmark);
}
public void unselect () {
diff --git a/src/contacts-app.vala b/src/contacts-app.vala
index b1adaf40..dc7b94ac 100644
--- a/src/contacts-app.vala
+++ b/src/contacts-app.vala
@@ -22,7 +22,7 @@ public class Contacts.App : Gtk.Application {
private Store contacts_store;
- private MainWindow window;
+ private unowned MainWindow window;
private const GLib.ActionEntry[] action_entries = {
{ "quit", quit },
@@ -84,7 +84,7 @@ public class Contacts.App : Gtk.Application {
}
public void show_contact (Individual? individual) {
- window.set_shown_contact (individual);
+ this.window.set_shown_contact (individual);
}
public async void show_individual (string id) {
@@ -111,15 +111,15 @@ public class Contacts.App : Gtk.Application {
Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE,
_("No contact with id %s found"), id);
dialog.set_title (_("Contact not found"));
- dialog.run ();
- dialog.destroy ();
+ dialog.response.connect ((_) => { dialog.close (); });
+ dialog.show ();
}
}
public void change_address_book () {
var dialog = new AddressbookDialog (this.contacts_store, this.window);
- dialog.run ();
- dialog.destroy ();
+ dialog.response.connect ((_) => dialog.close ());
+ dialog.show ();
}
public void online_accounts () {
@@ -150,7 +150,7 @@ public class Contacts.App : Gtk.Application {
public void show_help () {
try {
- Gtk.show_uri_on_window (window, "help:gnome-help/contacts", Gtk.get_current_event_time ());
+ Gtk.show_uri (this.window, "help:gnome-help/contacts", Gdk.CURRENT_TIME);
} catch (GLib.Error e1) {
warning ("Error showing help: %s", e1.message);
}
@@ -166,7 +166,7 @@ public class Contacts.App : Gtk.Application {
string[] artists = {
"Allan Day <allanpday gmail com>"
};
- Gtk.show_about_dialog (window,
+ Gtk.show_about_dialog (this.window,
"artists", artists,
"authors", authors,
"translator-credits", _("translator-credits"),
@@ -191,23 +191,25 @@ public class Contacts.App : Gtk.Application {
Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE,
_("No contact with email address %s found"), email_address);
dialog.set_title (_("Contact not found"));
- dialog.run ();
- dialog.destroy ();
+ dialog.response.connect ((_) => dialog.close ());
+ dialog.show ();
}
}
public void show_search (string query) {
if (contacts_store.is_quiescent) {
- window.show_search (query);
+ this.window.show_search (query);
} else {
contacts_store.quiescent.connect_after (() => {
- window.show_search (query);
+ this.window.show_search (query);
});
}
}
private void create_window () {
- this.window = new MainWindow (this.settings, this, this.contacts_store);
+ var win = new MainWindow (this.settings, this, this.contacts_store);
+ win.show ();
+ this.window = win;
show_contact_list ();
}
@@ -244,7 +246,7 @@ public class Contacts.App : Gtk.Application {
this.contacts_store = new Store ();
base.startup ();
- Hdy.init ();
+ Adw.init ();
load_styling ();
create_actions ();
@@ -261,9 +263,9 @@ public class Contacts.App : Gtk.Application {
public void load_styling () {
var provider = new Gtk.CssProvider ();
provider.load_from_resource ("/org/gnome/Contacts/ui/style.css");
- Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default(),
- provider,
- Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
+ Gtk.StyleContext.add_provider_for_display (Gdk.Display.get_default(),
+ provider,
+ Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
}
public override void activate () {
diff --git a/src/contacts-avatar-selector.vala b/src/contacts-avatar-selector.vala
index 21790696..9d62a325 100644
--- a/src/contacts-avatar-selector.vala
+++ b/src/contacts-avatar-selector.vala
@@ -21,18 +21,24 @@ const int MAIN_SIZE = 128;
const int ICONS_SIZE = 64;
private class Contacts.Thumbnail : Gtk.FlowBoxChild {
+
public Gdk.Pixbuf? source_pixbuf { get; construct set; }
+
private Thumbnail (Gdk.Pixbuf? source_pixbuf = null) {
- Object (visible: true, halign : Gtk.Align.CENTER, source_pixbuf: source_pixbuf);
- this.get_style_context ().add_class ("circular");
+ Object (visible: true,
+ halign: Gtk.Align.CENTER,
+ source_pixbuf: source_pixbuf);
+
+ this.add_css_class ("circular");
+
var avatar = new Avatar (ICONS_SIZE);
avatar.set_pixbuf (source_pixbuf);
- add (avatar);
+ this.set_child (avatar);
}
public Thumbnail.for_persona (Persona persona) {
Gdk.Pixbuf? pixbuf = null;
- var details = persona as AvatarDetails;
+ unowned var details = persona as AvatarDetails;
if (details != null && details.avatar != null) {
try {
var stream = details.avatar.load (MAIN_SIZE, null);
@@ -58,72 +64,51 @@ private class Contacts.Thumbnail : Gtk.FlowBoxChild {
/**
* The AvatarSelector can be used to choose the avatar for a contact.
* This can be done by either choosing a stock thumbnail, an image file
- * provided by the user, or -if cheese is enabled- by using a webcam.
+ * provided by the user, or by using a webcam.
*
* After a user has initially chosen an avatar, we provide a cropping tool.
*/
[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-avatar-selector.ui")]
-public class Contacts.AvatarSelector : Gtk.Window {
+public class Contacts.AvatarSelector : Gtk.Dialog {
+
const string AVATAR_BUTTON_CSS_NAME = "avatar-button";
- // This will provide the default thumbnails
- private Gnome.DesktopThumbnailFactory thumbnail_factory;
- private Individual individual;
+ private unowned Individual individual;
[GtkChild]
private unowned Gtk.FlowBox thumbnail_grid;
-#if HAVE_CHEESE
[GtkChild]
- private unowned Gtk.Button cheese_button;
- private int num_cameras;
- private Cheese.CameraDeviceMonitor camera_monitor;
-#endif
+ private unowned Gtk.Button camera_button;
+
+ private Xdg.Portal.Camera? camera_portal = null;
public AvatarSelector (Individual? individual, Gtk.Window? window = null) {
- Object (transient_for: window);
- this.thumbnail_factory = new Gnome.DesktopThumbnailFactory (Gnome.ThumbnailSize.NORMAL);
+ Object (transient_for: window, use_header_bar: 1);
this.individual = individual;
- unowned Gtk.BindingSet binding_set = Gtk.BindingSet.by_class (get_class ());
- Gtk.BindingEntry.add_signal (binding_set,
- Gdk.Key.Escape,
- 0,
- "close",
- 0);
-
update_thumbnail_grid ();
-#if HAVE_CHEESE
- this.cheese_button.visible = true;
- this.cheese_button.sensitive = false;
-
- // Look for camera devices.
- this.camera_monitor = new Cheese.CameraDeviceMonitor ();
- this.camera_monitor.added.connect ( () => {
- this.num_cameras++;
- this.cheese_button.sensitive = (this.num_cameras > 0);
- });
- this.camera_monitor.removed.connect ( () => {
- this.num_cameras--;
- this.cheese_button.sensitive = (this.num_cameras > 0);
- });
- // Do this in a separate thread, or it blocks the whole UI
- new Thread<void*> ("camera-loader", () => {
- this.camera_monitor.coldplug ();
- return null;
- });
-#endif
+ this.setup_camera_portal.begin ();
}
- [Signal (action = true)]
- public new virtual signal void close () {
- base.close ();
- }
+ private async void setup_camera_portal () {
+ this.camera_button.sensitive = false;
+ try {
+ this.camera_portal = yield Bus.get_proxy (BusType.SESSION,
+ "org.freedesktop.portal.Desktop",
+ "/org/freedesktop/portal/desktop");
+
+ if (camera_portal.is_camera_present) {
+ this.camera_button.sensitive = true;
+ } else {
+ this.camera_button.tooltip_text = _("No camera detected");
+ }
- [GtkCallback]
- public bool on_delete_event () {
- return hide_on_delete ();
+ } catch (Error e) {
+ warning ("Couldn't retrieve camera portal: %s", e.message);
+ this.camera_button.tooltip_text = _("Error fetching camera");
+ }
}
private Gdk.Pixbuf scale_pixbuf_for_avatar_use (Gdk.Pixbuf pixbuf) {
@@ -150,19 +135,19 @@ public class Contacts.AvatarSelector : Gtk.Window {
pixbuf.save_to_buffer (out buffer, "png", null);
var icon = new BytesIcon (new Bytes (buffer));
// Set the new avatar
- this.individual.change_avatar.begin(icon as LoadableIcon, (obj, res) => {
+ this.individual.change_avatar.begin (icon as LoadableIcon, (obj, res) => {
try {
- this.individual.change_avatar.end(res);
+ this.individual.change_avatar.end (res);
} catch (Error e) {
warning ("Failed to set avatar: %s", e.message);
Utils.show_error_dialog (_("Failed to set avatar."),
- get_toplevel() as Gtk.Window);
+ get_root() as Gtk.Window);
}
});
} catch (GLib.Error e) {
warning ("Failed to set avatar: %s", e.message);
Utils.show_error_dialog (_("Failed to set avatar."),
- get_toplevel() as Gtk.Window);
+ get_root() as Gtk.Window);
}
}
private void update_thumbnail_grid () {
@@ -170,7 +155,7 @@ public class Contacts.AvatarSelector : Gtk.Window {
foreach (var p in individual.personas) {
var widget = new Thumbnail.for_persona (p);
if (widget.source_pixbuf != null)
- this.thumbnail_grid.add (widget);
+ this.thumbnail_grid.insert (widget, -1);
}
}
@@ -178,33 +163,25 @@ public class Contacts.AvatarSelector : Gtk.Window {
foreach (var file_name in stock_files) {
var widget = new Thumbnail.for_filename (file_name);
if (widget.source_pixbuf != null)
- this.thumbnail_grid.add (widget);
+ this.thumbnail_grid.insert (widget, -1);
}
- this.thumbnail_grid.show_all ();
}
[GtkCallback]
- private void on_cheese_clicked (Gtk.Button button) {
- var dialog = new CropCheeseDialog.for_cheese (get_toplevel() as Gtk.Window);
- dialog.show_all ();
- dialog.picture_selected.connect ( (pix) => {
- selected_pixbuf (scale_pixbuf_for_avatar_use (pix));
- this.close ();
- });
+ private void on_camera_button_clicked (Gtk.Button button) {
+ var dialog = new CropDialog.for_camera_portal (this.camera_portal,
+ this.get_root () as Gtk.Window);
+ dialog.show ();
}
- [GtkCallback]
- private void on_cancel_clicked (Gtk.Button button) {
- this.close ();
- }
-
- [GtkCallback]
- private void on_done_clicked (Gtk.Button button) {
- var selected_children = thumbnail_grid.get_selected_children ();
- if (selected_children != null) {
- var thumbnail = (selected_children.data as Thumbnail);
- if (thumbnail != null)
- selected_pixbuf (scale_pixbuf_for_avatar_use (thumbnail.source_pixbuf));
+ public override void response (int response) {
+ if (response == Gtk.ResponseType.OK) {
+ var selected_children = thumbnail_grid.get_selected_children ();
+ if (selected_children != null) {
+ unowned var thumbnail = (selected_children.data as Thumbnail);
+ if (thumbnail != null)
+ selected_pixbuf (scale_pixbuf_for_avatar_use (thumbnail.source_pixbuf));
+ }
}
this.close ();
@@ -213,88 +190,45 @@ public class Contacts.AvatarSelector : Gtk.Window {
[GtkCallback]
private void on_file_clicked (Gtk.Button button) {
var chooser = new Gtk.FileChooserNative (_("Browse for more pictures"),
- get_toplevel () as Gtk.Window,
+ this.get_root () as Gtk.Window,
Gtk.FileChooserAction.OPEN,
_("_Open"), _("_Cancel"));
chooser.set_modal (true);
- chooser.set_local_only (false);
- var preview = new Gtk.Image ();
- preview.set_size_request (MAIN_SIZE, -1);
- chooser.set_preview_widget (preview);
- chooser.set_use_preview_label (false);
- preview.show ();
-
- chooser.update_preview.connect (update_preview);
- var folder = Environment.get_user_special_dir (UserDirectory.PICTURES);
- if (folder != null)
- chooser.set_current_folder (folder);
+ try {
+ unowned var pictures_folder = Environment.get_user_special_dir (UserDirectory.PICTURES);
+ if (pictures_folder != null)
+ chooser.set_current_folder (File.new_for_path (pictures_folder));
+ } catch (Error e) {
+ warning ("Couldn't set avatar selector to Pictures folder: %s", e.message);
+ }
- chooser.response.connect ( (response) => {
+ chooser.response.connect ((response) => {
if (response != Gtk.ResponseType.ACCEPT) {
- chooser.destroy ();
return;
}
+
try {
- var file = File.new_for_uri (chooser.get_uri ());
+ var file = chooser.get_file ();
var in_stream = file.read ();
var pixbuf = new Gdk.Pixbuf.from_stream (in_stream, null);
in_stream.close ();
if (pixbuf.get_width () > MAIN_SIZE || pixbuf.get_height () > MAIN_SIZE) {
- var dialog = new CropCheeseDialog.for_crop (get_toplevel () as Gtk.Window,
- pixbuf);
+ var dialog = new CropDialog.for_pixbuf (pixbuf,
+ get_root () as Gtk.Window);
dialog.picture_selected.connect ( (pix) => {
selected_pixbuf (scale_pixbuf_for_avatar_use (pix));
});
- dialog.show_all();
+ dialog.show();
} else {
selected_pixbuf (scale_pixbuf_for_avatar_use (pixbuf));
}
} catch (GLib.Error e) {
warning ("Failed to set avatar: %s", e.message);
Utils.show_error_dialog (_("Failed to set avatar."),
- this.get_toplevel() as Gtk.Window);
+ this.get_root() as Gtk.Window);
}
-
- chooser.destroy ();
});
-
- chooser.run ();
- this.close ();
+ chooser.show ();
}
-
- private void update_preview (Gtk.FileChooser chooser) {
- var uri = chooser.get_preview_uri ();
- if (uri != null) {
- Gdk.Pixbuf? pixbuf = null;
-
- var preview = chooser.get_preview_widget () as Gtk.Image;
-
- var file = File.new_for_uri (uri);
- try {
- var file_info = file.query_info (FileAttribute.STANDARD_CONTENT_TYPE,
- FileQueryInfoFlags.NONE, null);
- if (file_info != null) {
- var mime_type = file_info.get_content_type ();
-
- if (mime_type != null)
- pixbuf = this.thumbnail_factory.generate_thumbnail (uri, mime_type);
- }
- } catch (Error e) {
- debug ("Couldn't generate thumbnail for file '%s': %s", uri, e.message);
- }
-
- if (chooser is Gtk.Dialog)
- ((Gtk.Dialog) chooser).set_response_sensitive (Gtk.ResponseType.ACCEPT,
- (pixbuf != null));
-
- if (pixbuf != null)
- preview.set_from_pixbuf (pixbuf);
- else
- preview.set_from_icon_name ("dialog-question", Gtk.IconSize.DIALOG);
- }
-
- chooser.set_preview_widget_active (true);
- }
-
}
diff --git a/src/contacts-avatar.vala b/src/contacts-avatar.vala
index 33653065..7ba6a7ac 100644
--- a/src/contacts-avatar.vala
+++ b/src/contacts-avatar.vala
@@ -21,8 +21,7 @@ using Folks;
* The Avatar of a Contact is responsible for showing an {@link Folks.Individual}'s
* avatar, or a fallback if it's not available.
*/
-public class Contacts.Avatar : Gtk.Bin {
- private Hdy.Avatar widget;
+public class Contacts.Avatar : Adw.Bin {
private unowned Individual? individual = null;
@@ -42,10 +41,7 @@ public class Contacts.Avatar : Gtk.Bin {
}
}
- this.widget = new Hdy.Avatar (size, name, show_initials);
- this.widget.set_image_load_func (size => load_avatar (size));
- this.widget.show ();
- add(this.widget);
+ this.child = new Adw.Avatar (size, name, show_initials);
show ();
}
@@ -54,23 +50,10 @@ public class Contacts.Avatar : Gtk.Bin {
* Manually set the avatar to the given pixbuf, even if the contact has an avatar.
*/
public void set_pixbuf (Gdk.Pixbuf? a_pixbuf) {
- this.widget.set_image_load_func (size => load_avatar (size, a_pixbuf));
- }
-
- private Gdk.Pixbuf? load_avatar (int size, Gdk.Pixbuf? pixbuf = null) {
- if (pixbuf != null) {
- return pixbuf.scale_simple (size, size, Gdk.InterpType.HYPER);
- } else {
- if (this.individual != null && this.individual.avatar != null) {
- try {
- var stream = this.individual.avatar.load (size, null);
- return new Gdk.Pixbuf.from_stream_at_scale (stream, size, size, true);
- } catch (Error e) {
- debug ("Couldn't load avatar of contact %s. Reason: %s", this.individual.display_name, e.message);
- }
- }
- }
- return null;
+ if (a_pixbuf != null)
+ ((Adw.Avatar) this.child).set_custom_image (Gdk.Texture.for_pixbuf (a_pixbuf));
+ else
+ ((Adw.Avatar) this.child).set_icon_name ("avatar-default-symbolic");
}
/* Find a nice name to generate the label and color for the fallback avatar
diff --git a/src/contacts-contact-editor.vala b/src/contacts-contact-editor.vala
index 85c34f74..7e90841d 100644
--- a/src/contacts-contact-editor.vala
+++ b/src/contacts-contact-editor.vala
@@ -32,14 +32,13 @@ public class Contacts.ContactEditor : Gtk.Box {
this.individual = individual;
Gtk.Box header = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6);
- header.add (create_avatar_button ());
- header.add (create_name_entry ());
- add (header);
+ header.append (create_avatar_button ());
+ header.append (create_name_entry ());
+ append (header);
foreach (var p in individual.personas) {
- add (new EditorPersona (p, aggregator));
+ append (new EditorPersona (p, aggregator));
}
- show_all ();
}
// Creates the contact's current avatar in a big button on top of the Editor
@@ -47,8 +46,8 @@ public class Contacts.ContactEditor : Gtk.Box {
this.avatar = new Avatar (PROFILE_SIZE, this.individual);
var button = new Gtk.Button ();
- button.get_accessible ().set_name (_("Change avatar"));
- button.image = this.avatar;
+ button.tooltip_text = _("Change avatar");
+ button.set_child (this.avatar);
button.clicked.connect (on_avatar_button_clicked);
return button;
@@ -57,7 +56,7 @@ public class Contacts.ContactEditor : Gtk.Box {
// Show the avatar popover when the avatar is clicked
private void on_avatar_button_clicked (Gtk.Button avatar_button) {
if (this.avatar_selector == null)
- this.avatar_selector = new AvatarSelector (this.individual, (Gtk.Window) this.get_toplevel());
+ this.avatar_selector = new AvatarSelector (this.individual, get_root() as Gtk.Window);
this.avatar_selector.show();
}
diff --git a/src/contacts-contact-list.vala b/src/contacts-contact-list.vala
index 266545d8..770d1e1e 100644
--- a/src/contacts-contact-list.vala
+++ b/src/contacts-contact-list.vala
@@ -22,112 +22,77 @@ using Folks;
* the left. It is contained by the {@link ListPane}, which also provides other
* functionality, such as an action bar.
*/
-public class Contacts.ContactList : Gtk.ListBox {
- private class ContactDataRow : Gtk.ListBoxRow {
- private const int LIST_AVATAR_SIZE = 48;
+public class Contacts.ContactList : Adw.Bin {
- public unowned Individual individual;
- private Gtk.Label label;
- private Avatar avatar;
- public Gtk.CheckButton selector_button;
+ int nr_contacts_marked = 0;
- public ContactDataRow(Individual i) {
- this.individual = i;
- this.individual.notify.connect (on_contact_changed);
+ private Query filter_query;
- get_style_context (). add_class ("contact-data-row");
+ private Store store;
- Gtk.Grid grid = new Gtk.Grid ();
- grid.margin = 3;
- grid.margin_start = 9;
- grid.set_column_spacing (10);
- this.avatar = new Avatar (LIST_AVATAR_SIZE, this.individual);
+ private bool sort_on_surname = false; // keep in sync with the setting
- this.label = new Gtk.Label (individual.display_name);
- this.label.ellipsize = Pango.EllipsizeMode.END;
- this.label.valign = Gtk.Align.CENTER;
- this.label.halign = Gtk.Align.START;
- // Make sure it doesn't "twitch" when the checkbox becomes visible
- this.label.xalign = 0;
+ private bool got_long_press = false;
- this.selector_button = new Gtk.CheckButton ();
- this.selector_button.visible = false;
- this.selector_button.valign = Gtk.Align.CENTER;
- this.selector_button.halign = Gtk.Align.END;
- this.selector_button.hexpand = true;
- // Make sure it doesn't overlap with the scrollbar
- this.selector_button.margin_end = 12;
+ public UiState state { get; set; }
- grid.attach (this.avatar, 0, 0);
- grid.attach (this.label, 1, 0);
- grid.attach (this.selector_button, 2, 0);
- this.add (grid);
- this.show_all ();
- }
-
- private void on_contact_changed (Object obj, ParamSpec pspec) {
- //TODO: Update also the Avatar
- this.label.set_text (this.individual.display_name);
- changed ();
- }
- }
+ private unowned Gtk.ListBox listbox;
public signal void selection_changed (Individual? individual);
public signal void contacts_marked (int contacts_marked);
- int nr_contacts_marked = 0;
+ construct {
+ var list_box = new Gtk.ListBox ();
+ this.listbox = list_box;
+ this.child = list_box;
- private Query filter_query;
+ this.listbox.selection_mode = Gtk.SelectionMode.BROWSE;
+ this.listbox.set_sort_func (compare_rows);
+ this.listbox.set_filter_func (filter_row);
+ this.listbox.set_header_func (update_header);
- private Store store;
+ this.add_css_class ("contacts-contact-list");
- private bool sort_on_surname = false; // keep in sync with the setting
+ // Row selection/activation
+ this.listbox.row_activated.connect (on_row_activated);
+ this.listbox.row_selected.connect (on_row_selected);
- private Gtk.GestureLongPress long_press;
- private bool got_long_press = false;
+ // Connect events right-click and long-press
+ var secondary_click_gesture = new Gtk.GestureClick ();
+ secondary_click_gesture.button = Gdk.BUTTON_SECONDARY;
+ secondary_click_gesture.pressed.connect (on_right_click);
+ this.listbox.add_controller (secondary_click_gesture);
- public UiState state { get; set; }
+ var long_press_gesture = new Gtk.GestureLongPress ();
+ long_press_gesture.pressed.connect (on_long_press);
+ this.listbox.add_controller (long_press_gesture);
+ }
public ContactList (Settings settings, Store store, Query query) {
- this.selection_mode = Gtk.SelectionMode.BROWSE;
this.store = store;
this.filter_query = query;
- this.filter_query.notify.connect (() => { invalidate_filter (); });
- this.visible = true;
+ this.filter_query.notify.connect (() => { this.listbox.invalidate_filter (); });
this.notify["state"].connect (on_ui_state_changed);
- // Connect long press gesture
- this.long_press = new Gtk.GestureLongPress (this);
- this.long_press.pressed.connect ((g, x, y) => {
- this.got_long_press = true;
- var row = (ContactDataRow) get_row_at_y ((int) Math.round (y));
- if (row != null) {
- row.selector_button.active = this.state != UiState.SELECTING || !row.selector_button.active;
- }
- });
-
this.sort_on_surname = settings.sort_on_surname;
settings.changed["sort-on-surname"].connect(() => {
this.sort_on_surname = settings.sort_on_surname;
- invalidate_sort();
+ this.listbox.invalidate_sort();
});
this.store.added.connect (contact_added_cb);
this.store.removed.connect (contact_removed_cb);
foreach (var i in this.store.get_contacts ())
contact_added_cb (this.store, i);
-
- get_style_context ().add_class ("contacts-contact-list");
-
- set_sort_func (compare_rows);
- set_filter_func (filter_row);
- set_header_func (update_header);
}
private void on_ui_state_changed (Object obj, ParamSpec pspec) {
- foreach (var widget in get_children ()) {
- var row = widget as ContactDataRow;
+ for (int i = 0; true; i++) {
+ unowned var row = (ContactDataRow) this.listbox.get_row_at_index (i);
+ if (row == null)
+ break;
+
row.selector_button.visible = (this.state == UiState.SELECTING);
if (this.state != UiState.SELECTING)
@@ -136,9 +101,9 @@ public class Contacts.ContactList : Gtk.ListBox {
// Disalbe highlighted (blue) selection since we use the checkbox to show selection
if (this.state == UiState.SELECTING) {
- this.selection_mode = Gtk.SelectionMode.NONE;
+ this.listbox.selection_mode = Gtk.SelectionMode.NONE;
} else {
- this.selection_mode = Gtk.SelectionMode.BROWSE;
+ this.listbox.selection_mode = Gtk.SelectionMode.BROWSE;
this.nr_contacts_marked = 0;
}
}
@@ -188,9 +153,10 @@ public class Contacts.ContactList : Gtk.ListBox {
private Gtk.Label create_header_label (string text) {
var label = new Gtk.Label (text);
label.halign = Gtk.Align.START;
- label.margin = 3;
label.margin_start = 6;
+ label.margin_end = 3;
label.margin_top = 6;
+ label.margin_bottom = 3;
var attrs = new Pango.AttrList ();
attrs.insert (Pango.attr_weight_new (Pango.Weight.BOLD));
attrs.insert (Pango.attr_scale_new ((Pango.Scale.SMALL + Pango.Scale.MEDIUM) / 2.0));
@@ -206,7 +172,7 @@ public class Contacts.ContactList : Gtk.ListBox {
row.selector_button.toggled.connect ( () => { on_row_checkbox_toggled (row); });
row.selector_button.visible = (this.state == UiState.SELECTING);
- add (row);
+ this.listbox.append (row);
} else {
debug ("Contact %s was ignored", i.id);
}
@@ -228,9 +194,9 @@ public class Contacts.ContactList : Gtk.ListBox {
row.destroy ();
}
- public override void row_activated (Gtk.ListBoxRow row) {
+ private void on_row_activated (Gtk.ListBox listbox, Gtk.ListBoxRow row) {
if (!this.got_long_press) {
- var data = row as ContactDataRow;
+ unowned var data = row as ContactDataRow;
if (data != null && this.state == UiState.SELECTING)
data.selector_button.active = !data.selector_button.active;
} else {
@@ -238,10 +204,10 @@ public class Contacts.ContactList : Gtk.ListBox {
}
}
- public override void row_selected (Gtk.ListBoxRow? row) {
+ private void on_row_selected (Gtk.ListBox listbox, Gtk.ListBoxRow? row) {
if (this.state != UiState.SELECTING) {
- var data = row as ContactDataRow;
- var individual = data != null ? data.individual : null;
+ unowned var data = row as ContactDataRow;
+ unowned var individual = data != null ? data.individual : null;
selection_changed (individual);
#if HAVE_TELEPATHY
if (individual != null)
@@ -251,27 +217,26 @@ public class Contacts.ContactList : Gtk.ListBox {
}
private bool filter_row (Gtk.ListBoxRow row) {
- var individual = ((ContactDataRow) row).individual;
+ unowned var individual = ((ContactDataRow) row).individual;
return this.filter_query.is_match (individual) > 0;
}
public void select_contact (Individual? individual) {
if (individual == null) {
/* deselect */
- select_row (null);
+ this.listbox.select_row (null);
return;
}
ContactDataRow? row = find_row_for_contact (individual);
- select_row (row);
+ this.listbox.select_row (row);
scroll_to_contact (row);
}
public void scroll_to_contact (Gtk.ListBoxRow? row = null) {
unowned ContactDataRow? selected_row = null;
-
if (row == null)
- selected_row = get_selected_row () as ContactDataRow;
+ selected_row = this.listbox.get_selected_row () as ContactDataRow;
else
selected_row = row as ContactDataRow;
@@ -290,8 +255,11 @@ public class Contacts.ContactList : Gtk.ListBox {
private unowned ContactDataRow? find_row_for_contact (Individual individual) {
- foreach (weak Gtk.Widget widget in get_children ()) {
- unowned var row = ((ContactDataRow) widget);
+ for (int i = 0; true; i++) {
+ unowned var row = (ContactDataRow) this.listbox.get_row_at_index (i);
+ if (row == null)
+ break;
+
if (row.individual == individual)
return row;
}
@@ -301,18 +269,27 @@ public class Contacts.ContactList : Gtk.ListBox {
public Gee.LinkedList<Individual> get_marked_contacts () {
var cs = new Gee.LinkedList<Individual> ();
- foreach (weak Gtk.Widget widget in get_children ()) {
- unowned var row = widget as ContactDataRow;
+
+ for (int i = 0; true; i++) {
+ unowned var row = (ContactDataRow) this.listbox.get_row_at_index (i);
+ if (row == null)
+ break;
+
if (row.selector_button.active)
cs.add (row.individual);
}
+
return cs;
}
public Gee.LinkedList<Individual> get_marked_contacts_and_hide () {
var cs = new Gee.LinkedList<Individual> ();
- foreach (weak Gtk.Widget widget in get_children ()) {
- unowned var row = widget as ContactDataRow;
+
+ for (int i = 0; true; i++) {
+ unowned var row = (ContactDataRow) this.listbox.get_row_at_index (i);
+ if (row == null)
+ break;
+
if (row.selector_button.active) {
row.visible = false;
cs.add (row.individual);
@@ -321,17 +298,73 @@ public class Contacts.ContactList : Gtk.ListBox {
return cs;
}
+ private void on_right_click (Gtk.GestureClick gesture, int n_press, double x, double y) {
+ unowned var row = (ContactDataRow) this.listbox.get_row_at_y ((int) Math.round (y));
+ if (row != null) {
+ row.selector_button.active = this.state != UiState.SELECTING || !row.selector_button.active;
+ }
+ }
- public override bool button_press_event (Gdk.EventButton event) {
- base.button_press_event (event);
+ private void on_long_press (Gtk.GestureLongPress gesture, double x, double y) {
+ this.got_long_press = true;
+ var row = (ContactDataRow) this.listbox.get_row_at_y ((int) Math.round (y));
+ if (row != null) {
+ row.selector_button.active = this.state != UiState.SELECTING || !row.selector_button.active;
+ }
+ }
- if (event.button == Gdk.BUTTON_SECONDARY) {
- unowned var row = (ContactDataRow) get_row_at_y ((int) Math.round (event.y));
- if (row != null) {
- row.selector_button.active = this.state != UiState.SELECTING || !row.selector_button.active;
- }
+ // A class for the ListBoxRows
+ private class ContactDataRow : Gtk.ListBoxRow {
+ private const int LIST_AVATAR_SIZE = 48;
+
+ public unowned Individual individual;
+ private unowned Gtk.Label label;
+ private unowned Avatar avatar;
+ public unowned Gtk.CheckButton selector_button;
+
+ public ContactDataRow (Individual i) {
+ this.individual = i;
+ this.individual.notify.connect (on_contact_changed);
+
+ add_css_class ("contact-data-row");
+
+ var grid = new Gtk.Grid ();
+ grid.margin_start = 9;
+ grid.margin_end = 3;
+ grid.margin_top = 3;
+ grid.margin_bottom = 3;
+ grid.set_column_spacing (10);
+
+ var avatar = new Avatar (LIST_AVATAR_SIZE, this.individual);
+ grid.attach (avatar, 0, 0);
+ this.avatar = avatar;
+
+ var label = new Gtk.Label (individual.display_name);
+ label.ellipsize = Pango.EllipsizeMode.END;
+ label.valign = Gtk.Align.CENTER;
+ label.halign = Gtk.Align.START;
+ // Make sure it doesn't "twitch" when the checkbox becomes visible
+ label.xalign = 0;
+ grid.attach (label, 1, 0);
+ this.label = label;
+
+ var selector_button = new Gtk.CheckButton ();
+ selector_button.visible = false;
+ selector_button.valign = Gtk.Align.CENTER;
+ selector_button.halign = Gtk.Align.END;
+ selector_button.hexpand = true;
+ // Make sure it doesn't overlap with the scrollbar
+ selector_button.margin_end = 12;
+ grid.attach (selector_button, 2, 0);
+ this.selector_button = selector_button;
+
+ this.set_child (grid);
}
- return false;
+ private void on_contact_changed (Object obj, ParamSpec pspec) {
+ //TODO: Update also the Avatar
+ this.label.set_text (this.individual.display_name);
+ changed ();
+ }
}
}
diff --git a/src/contacts-contact-pane.vala b/src/contacts-contact-pane.vala
index bb52992e..21a0a27b 100644
--- a/src/contacts-contact-pane.vala
+++ b/src/contacts-contact-pane.vala
@@ -25,7 +25,7 @@ const int PROFILE_SIZE = 128;
* and a ContactEditor to edit contact information.
*/
[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-contact-pane.ui")]
-public class Contacts.ContactPane : Gtk.Bin {
+public class Contacts.ContactPane : Adw.Bin {
private MainWindow main_window;
@@ -35,22 +35,21 @@ public class Contacts.ContactPane : Gtk.Bin {
[GtkChild]
private unowned Gtk.Stack stack;
-
[GtkChild]
- private unowned Hdy.StatusPage none_selected_page;
+ private unowned Gtk.StackPage none_selected_page;
[GtkChild]
private unowned Gtk.ScrolledWindow contact_sheet_view;
[GtkChild]
- private unowned Gtk.Container contact_sheet_page;
+ private unowned Gtk.Box contact_sheet_box;
private ContactSheet? sheet = null;
[GtkChild]
private unowned Gtk.ScrolledWindow contact_editor_view;
[GtkChild]
- private unowned Gtk.Box contact_editor_page;
+ private unowned Gtk.Box contact_editor_box;
private ContactEditor? editor = null;
public bool on_edit_mode = false;
@@ -74,6 +73,7 @@ public class Contacts.ContactPane : Gtk.Bin {
remove_suggestion_grid ();
this.suggestion_grid = new LinkSuggestionGrid (i);
+ this.suggestion_grid.valign = Gtk.Align.END;
parent_overlay.add_overlay (this.suggestion_grid);
this.suggestion_grid.suggestion_accepted.connect ( () => {
@@ -104,7 +104,7 @@ public class Contacts.ContactPane : Gtk.Bin {
show_contact_sheet ();
} else {
remove_contact_sheet ();
- this.stack.set_visible_child (this.none_selected_page);
+ this.stack.set_visible_child_name ("none-selected-page");
}
}
@@ -113,8 +113,8 @@ public class Contacts.ContactPane : Gtk.Bin {
remove_contact_sheet();
this.sheet = new ContactSheet (this.individual, this.store);
- this.contact_sheet_page.add (this.sheet);
- this.stack.set_visible_child (this.contact_sheet_view);
+ this.contact_sheet_box.append (this.sheet);
+ this.stack.set_visible_child_name ("contact-sheet-page");
var matches = this.store.aggregator.get_potential_matches (this.individual, MatchResult.HIGH);
foreach (var i in matches.keys) {
@@ -132,7 +132,7 @@ public class Contacts.ContactPane : Gtk.Bin {
// Remove the suggestion grid that goes along with it.
remove_suggestion_grid ();
- this.contact_sheet_page.remove (this.sheet);
+ this.contact_sheet_box.remove (this.sheet);
this.sheet.destroy();
this.sheet = null;
}
@@ -142,14 +142,14 @@ public class Contacts.ContactPane : Gtk.Bin {
this.editor = new ContactEditor (this.individual, store.aggregator);
- this.contact_editor_page.add (this.editor);
+ this.contact_editor_box.append (this.editor);
}
private void remove_contact_editor () {
if (this.editor == null)
return;
- this.contact_editor_page.remove (this.editor);
+ this.contact_editor_box.remove (this.editor);
this.editor = null;
}
@@ -160,7 +160,7 @@ public class Contacts.ContactPane : Gtk.Bin {
this.on_edit_mode = true;
create_contact_editor ();
- this.stack.set_visible_child (this.contact_editor_view);
+ this.stack.set_visible_child_name ("contact-editor-page");
}
public void stop_editing (bool cancel = false) {
@@ -175,9 +175,9 @@ public class Contacts.ContactPane : Gtk.Bin {
if (fake_individual != null && fake_individual.real_individual != null) {
// Reset individual on to the real one
this.individual = fake_individual.real_individual;
- this.stack.set_visible_child (this.contact_sheet_view);
+ this.stack.set_visible_child_name ("contact-sheet-page");
} else {
- this.stack.set_visible_child (this.none_selected_page);
+ this.stack.set_visible_child_name ("none-selected-page");
}
return;
}
@@ -267,8 +267,8 @@ public class Contacts.ContactPane : Gtk.Bin {
Gtk.MessageType.ERROR,
Gtk.ButtonsType.OK,
"%s", message);
- dialog.run ();
- dialog.destroy ();
+ dialog.response.connect ((_) => dialog.close ());
+ dialog.show ();
}
private void remove_suggestion_grid () {
diff --git a/src/contacts-contact-sheet.vala b/src/contacts-contact-sheet.vala
index ceb41a54..5d71b331 100644
--- a/src/contacts-contact-sheet.vala
+++ b/src/contacts-contact-sheet.vala
@@ -63,53 +63,51 @@ public class Contacts.ContactSheet : Gtk.Grid {
}
private Gtk.Button create_button (string icon) {
- var button = new Gtk.Button.from_icon_name (icon, Gtk.IconSize.BUTTON);
- button.set_halign (Gtk.Align.END);
- button.get_style_context ().add_class ("flatten");
+ var button = new Gtk.Button.from_icon_name (icon);
+ button.valign = Gtk.Align.CENTER;
+ button.add_css_class ("flat");
return button;
}
- void add_row_with_label (string label_value,
- string value,
- Gtk.Widget? btn1 = null,
- Gtk.Widget? btn2 =null) {
+ private void add_row_with_label (string label_value,
+ string value,
+ Gtk.Widget? btn1 = null,
+ Gtk.Widget? btn2 =null) {
if (value == "" || value == null)
return;
- var type_label = new Gtk.Label (label_value);
- type_label.xalign = 1.0f;
- type_label.set_halign (Gtk.Align.END);
- type_label.set_valign (Gtk.Align.CENTER);
- type_label.get_style_context ().add_class ("dim-label");
- this.attach (type_label, 0, this.last_row, 1, 1);
-
- var value_label = new Gtk.Label (value);
- value_label.set_line_wrap (true);
- value_label.xalign = 0.0f;
- value_label.set_halign (Gtk.Align.START);
- value_label.set_ellipsize (Pango.EllipsizeMode.END);
- value_label.wrap_mode = Pango.WrapMode.CHAR;
- value_label.set_selectable (true);
- value_label.set_can_focus (false);
-
- if (btn1 != null || btn2 !=null) {
- var value_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12);
- value_box.pack_start (value_label, false, false, 0);
-
- if (btn1 != null)
- value_box.pack_end (btn1, false, false, 0);
- if (btn2 != null)
- value_box.pack_end (btn2, false, false, 0);
- this.attach (value_box, 1, this.last_row, 1, 1);
- } else {
- this.attach (value_label, 1, this.last_row, 1, 1);
- }
+
+ var action_row = new Adw.ActionRow ();
+ action_row.title = value;
+ action_row.subtitle = label_value;
+ if (btn1 != null)
+ action_row.add_suffix (btn1);
+ if (btn2 != null)
+ action_row.add_suffix (btn2);
+ attach_row (action_row);
+ }
+
+ // Helper function that attaches a row to our grid
+ private void attach_row (Gtk.ListBoxRow row) {
+ var list_box = new Gtk.ListBox ();
+ list_box.selection_mode = Gtk.SelectionMode.NONE;
+ list_box.add_css_class ("content");
+ list_box.append (row);
+
+ this.attach (list_box, 0, this.last_row, 3, 1);
this.last_row++;
}
private void update () {
this.last_row = 0;
- this.foreach ((child) => this.remove (child));
+
+ // Remove all fields
+ var child = get_first_child ();
+ while (child != null) {
+ var next = child.get_next_sibling ();
+ remove (child);
+ child = next;
+ }
var image_frame = new Avatar (PROFILE_SIZE, this.individual);
image_frame.set_vexpand (false);
@@ -141,8 +139,6 @@ public class Contacts.ContactSheet : Gtk.Grid {
this.last_row--;
}
}
-
- show_all ();
}
private void update_name_label (Gtk.Label name_label) {
@@ -198,39 +194,52 @@ public class Contacts.ContactSheet : Gtk.Grid {
}
private void add_emails (Persona persona) {
- var details = persona as EmailDetails;
- if (details != null) {
- var emails = Utils.sort_fields<EmailFieldDetails>(details.email_addresses);
- foreach (var email in emails) {
- var button = create_button ("mail-unread-symbolic");
- button.clicked.connect (() => {
- Utils.compose_mail ("%s <%s>".printf(this.individual.display_name, email.value));
- });
- add_row_with_label (TypeSet.email.format_type (email), email.value, button);
- }
+ unowned var details = persona as EmailDetails;
+ if (details == null)
+ return;
+
+ var emails = Utils.sort_fields<EmailFieldDetails>(details.email_addresses);
+ foreach (var email in emails) {
+ var action_row = new Adw.ActionRow ();
+
+ action_row.add_prefix (new Gtk.Image.from_icon_name ("mail-unread-symbolic"));
+ action_row.title = Markup.escape_text (email.value);
+ action_row.subtitle = TypeSet.email.format_type (email);
+
+ var button = create_button ("mail-send-symbolic");
+ button.clicked.connect (() => {
+ Utils.compose_mail ("%s <%s>".printf(this.individual.display_name, email.value));
+ });
+ action_row.add_suffix (button);
+
+ this.attach_row (action_row);
}
}
private void add_phone_nrs (Persona persona) {
- var phone_details = persona as PhoneDetails;
- if (phone_details != null) {
- var phones = Utils.sort_fields<PhoneFieldDetails>(phone_details.phone_numbers);
- foreach (var phone in phones) {
+ unowned var phone_details = persona as PhoneDetails;
+ if (phone_details == null)
+ return;
+
+ var phones = Utils.sort_fields<PhoneFieldDetails>(phone_details.phone_numbers);
+ foreach (var phone in phones) {
+ var action_row = new Adw.ActionRow ();
+
+ action_row.add_prefix (new Gtk.Image.from_icon_name ("call-start-symbolic"));
+ action_row.title = Markup.escape_text (phone.value);
+ action_row.subtitle = TypeSet.phone.format_type (phone);
+
#if HAVE_TELEPATHY
- if (this.store.caller_account != null) {
- var call_button = create_button ("call-start-symbolic");
- call_button.clicked.connect (() => {
- Utils.start_call (phone.value, this.store.caller_account);
- });
-
- add_row_with_label (TypeSet.phone.format_type (phone), phone.value, call_button);
- } else {
- add_row_with_label (TypeSet.phone.format_type (phone), phone.value);
- }
-#else
- add_row_with_label (TypeSet.phone.format_type (phone), phone.value);
-#endif
+ if (this.store.caller_account != null) {
+ var button = create_button ("call-start-symbolic");
+ button.clicked.connect (() => {
+ Utils.start_call (phone.value, this.store.caller_account);
+ });
+ action_row.add_suffix (button);
}
+#endif
+
+ this.attach_row (action_row);
}
}
@@ -261,33 +270,43 @@ public class Contacts.ContactSheet : Gtk.Grid {
}
private void add_urls (Persona persona) {
- var url_details = persona as UrlDetails;
- if (url_details != null) {
- foreach (var url in url_details.urls) {
- var button = create_button ("web-browser-symbolic");
- button.clicked.connect (() => {
- unowned var window = button.get_toplevel () as MainWindow;
- if (window == null)
- return;
-
- try {
- Gtk.show_uri_on_window (window,
- fallback_to_https (url.value),
- Gdk.CURRENT_TIME);
- } catch (Error e) {
- var message = "Failed to open url '%s'".printf(url.value);
-
- // Notify the user
- var notification = new InAppNotification (message);
- notification.show ();
- window.add_notification (notification);
-
- // Print details on stdout
- debug (message + ": " + e.message);
- }
- });
- add_row_with_label (_("Website"), url.value, button);
- }
+ unowned var url_details = persona as UrlDetails;
+ if (url_details == null)
+ return;
+
+ foreach (var url in url_details.urls) {
+ if (url.value == "")
+ continue;
+
+ var action_row = new Adw.ActionRow ();
+
+ action_row.add_prefix (new Gtk.Image.from_icon_name ("web-browser-symbolic"));
+ action_row.title = Markup.escape_text (url.value);
+
+ var button = create_button ("web-browser-symbolic");
+ button.clicked.connect (() => {
+ unowned var window = button.get_root () as MainWindow;
+ if (window == null)
+ return;
+
+ try {
+ Gtk.show_uri (window,
+ fallback_to_https (url.value),
+ Gdk.CURRENT_TIME);
+ } catch (Error e) {
+ var message = "Failed to open url '%s'".printf(url.value);
+
+ // Notify the user
+ var notification = new InAppNotification (message);
+ notification.show ();
+ window.add_notification (notification);
+
+ // Print details on stdout
+ debug (message + ": " + e.message);
+ }
+ });
+
+ this.attach_row (action_row);
}
}
@@ -301,32 +320,51 @@ public class Contacts.ContactSheet : Gtk.Grid {
}
private void add_nickname (Persona persona) {
- var name_details = persona as NameDetails;
- if (name_details != null && is_set (name_details.nickname))
- add_row_with_label (_("Nickname"), name_details.nickname);
+ unowned var name_details = persona as NameDetails;
+ if (name_details == null || name_details.nickname != "")
+ return;
+
+ add_row_with_label (_("Nickname"), name_details.nickname);
}
private void add_birthday (Persona persona) {
- var birthday_details = persona as BirthdayDetails;
- if (birthday_details != null && birthday_details.birthday != null)
- add_row_with_label (_("Birthday"), birthday_details.birthday.to_local ().format ("%x"));
+ unowned var birthday_details = persona as BirthdayDetails;
+ if (birthday_details == null || birthday_details.birthday == null)
+ return;
+
+ var action_row = new Adw.ActionRow ();
+ action_row.title = Markup.escape_text (birthday_details.birthday.to_local ().format ("%x"));
+ this.attach_row (action_row);
}
private void add_notes (Persona persona) {
- var note_details = persona as NoteDetails;
- if (note_details != null) {
- foreach (var note in note_details.notes)
- add_row_with_label (_("Note"), note.value);
+ unowned var note_details = persona as NoteDetails;
+ if (note_details == null)
+ return;
+
+ foreach (var note in note_details.notes) {
+ if (note.value == "")
+ continue;
+
+ var action_row = new Adw.ActionRow ();
+ action_row.title = Markup.escape_text (note.value);
+ this.attach_row (action_row);
}
}
private void add_postal_addresses (Persona persona) {
- var addr_details = persona as PostalAddressDetails;
- if (addr_details != null) {
- foreach (var addr in addr_details.postal_addresses) {
- var all_strs = string.joinv ("\n", Utils.format_address (addr.value));
- add_row_with_label (TypeSet.general.format_type (addr), all_strs);
- }
+ unowned var addr_details = persona as PostalAddressDetails;
+ if (addr_details == null)
+ return;
+
+ foreach (var addr in addr_details.postal_addresses) {
+ var action_row = new Adw.ActionRow ();
+
+ action_row.add_prefix (new Gtk.Image.from_icon_name ("mark-location-symbolic"));
+ action_row.title = Markup.escape_text (string.joinv ("\n", Utils.format_address (addr.value)));
+ action_row.subtitle = TypeSet.general.format_type (addr);
+
+ this.attach_row (action_row);
}
}
}
diff --git a/src/contacts-crop-cheese-dialog.vala b/src/contacts-crop-dialog.vala
similarity index 78%
rename from src/contacts-crop-cheese-dialog.vala
rename to src/contacts-crop-dialog.vala
index 1904d8a4..c3b20e7d 100644
--- a/src/contacts-crop-cheese-dialog.vala
+++ b/src/contacts-crop-dialog.vala
@@ -15,12 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-crop-cheese-dialog.ui")]
-public class Contacts.CropCheeseDialog : Gtk.Window {
+[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-crop-dialog.ui")]
+public class Contacts.CropDialog : Gtk.Window {
+
[GtkChild]
private unowned Gtk.Stack stack;
- [GtkChild]
- private unowned Gtk.Button take_another_button;
+ // [GtkChild]
+ // private unowned Gtk.Button take_another_button;
private Cc.CropArea crop_area;
private const string STACK_NAME_CROP = "crop";
@@ -33,33 +34,37 @@ public class Contacts.CropCheeseDialog : Gtk.Window {
public signal void picture_selected (Gdk.Pixbuf buf);
- public CropCheeseDialog.for_cheese (Gtk.Window parent) {
-#if HAVE_CHEESE
- setup_widget (parent);
- this.flash = new Cheese.Flash (this);
- this.cheese = new Cheese.Widget ();
- this.cheese.show ();
- this.stack.add_named (this.cheese, STACK_NAME_CHEESE);
- this.stack.set_visible_child_name (STACK_NAME_CHEESE);
-#endif
+ construct {
+ this.crop_area = new Cc.CropArea ();
+ this.crop_area.set_vexpand (true);
+ this.crop_area.set_hexpand (true);
+ this.crop_area.set_min_size (48, 48);
+ this.crop_area.set_constrain_aspect (true);
+ this.stack.add_named (this.crop_area, STACK_NAME_CROP);
+
+ // this.close_request.connect(on_close_request);
}
- public CropCheeseDialog.for_crop (Gtk.Window parent, Gdk.Pixbuf pixbuf) {
- setup_widget (parent);
- this.take_another_button.visible = false;
+ public CropDialog.for_pixbuf (Gdk.Pixbuf pixbuf,
+ Gtk.Window? parent = null) {
+ this.set_transient_for (parent);
+
+ // this.take_another_button.visible = false;
this.crop_area.set_picture (pixbuf);
}
- /* this function is called from both constructors */
- private void setup_widget (Gtk.Window parent) {
+ public CropDialog.for_camera_portal (Xdg.Portal.Camera camera_portal,
+ Gtk.Window? parent = null) {
this.set_transient_for (parent);
- this.crop_area = new Cc.CropArea ();
- this.crop_area.set_vexpand (true);
- this.crop_area.set_hexpand (true);
- this.crop_area.set_min_size (48, 48);
- this.crop_area.set_constrain_aspect (true);
- this.stack.add_named (this.crop_area, STACK_NAME_CROP);
+ // XXX use a pipewire fd and a GStreamer pipeline
+#if HAVE_CHEESE
+ this.flash = new Cheese.Flash (this);
+ this.cheese = new Cheese.Widget ();
+ this.cheese.show ();
+ this.stack.add_named (this.cheese, STACK_NAME_CHEESE);
+ this.stack.set_visible_child_name (STACK_NAME_CHEESE);
+#endif
}
[GtkCallback]
@@ -97,8 +102,7 @@ public class Contacts.CropCheeseDialog : Gtk.Window {
destroy();
}
- [GtkCallback]
- private void on_destroy () {
+ private bool on_close_request () {
#if HAVE_CHEESE
/* Ensure the Vala garbage collector disposes of the Cheese widget.
* This prevents the 'Device or resource busy' warnings, see:
@@ -106,6 +110,8 @@ public class Contacts.CropCheeseDialog : Gtk.Window {
*/
this.cheese = null;
#endif
+
+ return Gdk.EVENT_STOP; // XXX what the hell am i supposed to retunr here?
}
}
diff --git a/src/contacts-editor-persona.vala b/src/contacts-editor-persona.vala
index f0888a07..88a9889a 100644
--- a/src/contacts-editor-persona.vala
+++ b/src/contacts-editor-persona.vala
@@ -39,17 +39,18 @@ public class Contacts.EditorPersona : Gtk.Box {
private Folks.Persona persona;
private Gtk.Box header;
- private Gtk.ListBox content;
+ private unowned Gtk.Box content;
private Folks.IndividualAggregator aggregator;
construct {
this.header = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
- add (this.header);
+ append (this.header);
- this.content = new Gtk.ListBox ();
- this.content.get_style_context ().add_class ("content");
- add (this.content);
+ var listbox = new Gtk.Box (Gtk.Orientation.VERTICAL, 12);
+ this.content = listbox;
+ this.content.add_css_class ("content");
+ append (this.content);
}
public EditorPersona (Persona persona, IndividualAggregator aggregator) {
@@ -57,7 +58,7 @@ public class Contacts.EditorPersona : Gtk.Box {
this.persona = persona;
this.aggregator = aggregator;
create_label ();
- // TODO: implement the possibility of changing the addressbook of a persona
+ // TODO: implement the possibility f changing the addressbook of a persona
// Add most important properites
foreach (var property in PROPERTIES) {
@@ -66,32 +67,29 @@ public class Contacts.EditorPersona : Gtk.Box {
foreach (var row in rows) {
row.show_with_animation (false);
connect_row (row);
- this.content.add (row);
+ this.content.append (row);
}
}
- // Add a row with a button to show all properties
- Gtk.ListBoxRow show_all_row = new Gtk.ListBoxRow ();
- show_all_row.set_selectable (false);
- // Add less important property when the show_more button is clicked
- this.content.row_activated.connect ((current_row) => {
- if (current_row == show_all_row) {
+
+ // Add less important properties when the show_more button is clicked
+ var show_more_button = new Gtk.Button ();
+ var show_more_content = new Adw.ButtonContent ();
+ show_more_content.icon_name = "view-more-symbolic";
+ show_more_content.label = _("Show More");
+ show_more_button.set_child (show_more_content);
+ show_more_button.clicked.connect ((current_row) => {
foreach (var property in OTHER_PROPERTIES) {
debug ("Create property entry for %s", property);
var rows = new EditorProperty (persona, property);
foreach (var row in rows) {
connect_row (row);
- this.content.add (row);
+ this.content.append (row);
row.show_with_animation ();
}
}
- show_all_row.destroy ();
- }
+ this.content.remove (show_more_button);
});
- Gtk.Image show_all = new Gtk.Image.from_icon_name ("view-more-symbolic",
- Gtk.IconSize.BUTTON);
- show_all.margin = 12;
- show_all_row.add (show_all);
- this.content.add (show_all_row);
+ this.content.append (show_more_button);
}
private void connect_row (EditorPropertyRow row) {
@@ -105,9 +103,8 @@ public class Contacts.EditorPersona : Gtk.Box {
// We are sure that we only created one new row
var new_rows = new EditorProperty (persona, row.ptype, true);
if (new_rows.size > 0) {
- this.content.insert (new_rows[0], row.get_index () + 1);
+ this.content.insert_child_after (new_rows[0], row);
connect_row (new_rows[0]);
- new_rows[0].show_with_animation ();
} else {
debug ("Couldn't add new row with type %s", row.ptype);
}
@@ -117,8 +114,10 @@ public class Contacts.EditorPersona : Gtk.Box {
private uint count_empty_rows (string type) {
uint count = 0;
- foreach (var row in this.content.get_children ()) {
- var prop = (row as EditorPropertyRow);
+ for (unowned Gtk.Widget? child = this.content.get_first_child ();
+ child != null;
+ child = child.get_next_sibling ()) {
+ unowned var prop = (child as EditorPropertyRow);
if (prop != null && !prop.is_removed && prop.is_empty && prop.ptype == type) {
count++;
}
@@ -126,13 +125,16 @@ public class Contacts.EditorPersona : Gtk.Box {
return count;
}
- private void destroy_empty_rows (Gtk.ListBoxRow current_row, string type) {
- foreach (var row in this.content.get_children ()) {
- if (current_row != row) {
- var prop = (row as EditorPropertyRow);
- if (prop != null && !prop.is_removed && prop.is_empty && prop.ptype == type) {
- prop.remove ();
- }
+ private void destroy_empty_rows (Gtk.Widget current_row, string type) {
+ for (unowned Gtk.Widget? child = this.content.get_first_child ();
+ child != null;
+ child = child.get_next_sibling ()) {
+ if (current_row == child)
+ continue;
+
+ unowned var prop = (child as EditorPropertyRow);
+ if (prop != null && !prop.is_removed && prop.is_empty && prop.ptype == type) {
+ prop.remove ();
}
}
}
@@ -147,7 +149,7 @@ public class Contacts.EditorPersona : Gtk.Box {
}
Gtk.Label addressbook = new Gtk.Label (title);
- addressbook.get_style_context ().add_class ("heading");
- this.header.pack_start (addressbook, false, false, 0);
+ addressbook.add_css_class ("heading");
+ this.header.append (addressbook);
}
}
diff --git a/src/contacts-editor-property.vala b/src/contacts-editor-property.vala
index d03cde3b..d992bbcb 100644
--- a/src/contacts-editor-property.vala
+++ b/src/contacts-editor-property.vala
@@ -19,47 +19,46 @@
using Folks;
public class Contacts.BirthdayEditor : Gtk.Dialog {
- private Gtk.SpinButton day_spin;
- private Gtk.ComboBoxText month_combo;
- private Gtk.SpinButton year_spin;
+
+ private unowned Gtk.SpinButton day_spin;
+ private unowned Gtk.ComboBoxText month_combo;
+ private unowned Gtk.SpinButton year_spin;
+
public bool is_set { get; set; default = false; }
public signal void changed ();
- delegate void AdjustingDateFn ();
- public GLib.DateTime get_birthday () {
- return new GLib.DateTime.local (year_spin.get_value_as_int (),
- month_combo.get_active () + 1,
- day_spin.get_value_as_int (),
- 0, 0, 0).to_utc ();
- }
+ construct {
+ // The grid that will contain the Y/M/D fields
+ var grid = new Gtk.Grid ();
+ grid.set_column_spacing (12);
+ grid.set_row_spacing (12);
+ grid.add_css_class ("contacts-editor-birthday");
+ ((Gtk.Box) this.get_content_area ()).append (grid);
- public BirthdayEditor (Gtk.Window window, DateTime birthday) {
- Object (transient_for: window, use_header_bar: 1);
- day_spin = new Gtk.SpinButton.with_range (1.0, 31.0, 1.0);
- day_spin.set_digits (0);
- day_spin.numeric = true;
- day_spin.set_value ((double)birthday.to_local ().get_day_of_month ());
+ // Day
+ var d_spin = new Gtk.SpinButton.with_range (1.0, 31.0, 1.0);
+ d_spin.digits = 0;
+ d_spin.numeric = true;
+ this.day_spin = d_spin;
- month_combo = new Gtk.ComboBoxText ();
+ // Month
+ var m_combo = new Gtk.ComboBoxText ();
var january = new DateTime.local (1, 1, 1, 1, 1, 1);
for (int i = 0; i < 12; i++) {
var month = january.add_months (i);
- month_combo.append_text (month.format ("%B"));
+ m_combo.append_text (month.format ("%B"));
}
- month_combo.set_active (birthday.to_local ().get_month () - 1);
- month_combo.hexpand = true;
+ m_combo.hexpand = true;
+ this.month_combo = m_combo;
- year_spin = new Gtk.SpinButton.with_range (1800, 3000, 1);
- year_spin.set_digits (0);
- year_spin.numeric = true;
- year_spin.set_value ((double)birthday.to_local ().get_year ());
+ // Year
+ var y_spin = new Gtk.SpinButton.with_range (1800, 3000, 1);
+ y_spin.set_digits (0);
+ y_spin.numeric = true;
+ this.year_spin = y_spin;
// Create grid and labels
- var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 12);
- var grid = new Gtk.Grid ();
- grid.set_column_spacing (12);
- grid.set_row_spacing (12);
Gtk.Label day = new Gtk.Label(_("Day"));
day.set_halign (Gtk.Align.END);
grid.attach (day, 0, 0);
@@ -72,18 +71,13 @@ public class Contacts.BirthdayEditor : Gtk.Dialog {
year.set_halign (Gtk.Align.END);
grid.attach (year, 0, 2);
grid.attach (year_spin, 1, 2);
- box.pack_start (grid);
-
- var content = this.get_content_area ();
- content.set_valign (Gtk.Align.CENTER);
- content.add (box);
this.title = _("Change Birthday");
add_buttons (_("Set"), Gtk.ResponseType.OK,
_("Cancel"), Gtk.ResponseType.CANCEL,
null);
var ok_button = this.get_widget_for_response (Gtk.ResponseType.OK);
- ok_button.get_style_context ().add_class ("suggested-action");
+ ok_button.add_css_class ("suggested-action");
this.response.connect ((id) => {
switch (id) {
case Gtk.ResponseType.OK:
@@ -95,39 +89,48 @@ public class Contacts.BirthdayEditor : Gtk.Dialog {
}
this.destroy ();
});
+ }
- box.margin = 12;
- box.show_all ();
-
- AdjustingDateFn fn = () => {
- int[] month_of_31 = {3, 5, 8, 10};
- if (month_combo.get_active () in month_of_31) {
- day_spin.set_range (1, 30);
- } else if (month_combo.get_active () == 1) {
- if (year_spin.get_value_as_int () % 400 == 0 ||
- (year_spin.get_value_as_int () % 4 == 0 &&
- year_spin.get_value_as_int () % 100 != 0)) {
- day_spin.set_range (1, 29);
- } else {
- day_spin.set_range (1, 28);
- }
- } else {
- day_spin.set_range (1, 31);
- }
- };
+ public BirthdayEditor (Gtk.Window window, DateTime birthday) {
+ Object (transient_for: window, use_header_bar: 1);
- /* adjusting day_spin value using selected month/year constraints*/
- fn ();
+ this.day_spin.set_value ((double) birthday.to_local ().get_day_of_month ());
+ this.month_combo.set_active (birthday.to_local ().get_month () - 1);
+ this.year_spin.set_value ((double)birthday.to_local ().get_year ());
+ update_date ();
month_combo.changed.connect (() => {
- /* adjusting day_spin value using selected month constraints*/
- fn ();
+ update_date ();
});
year_spin.value_changed.connect (() => {
- /* adjusting day_spin value using selected year constraints*/
- fn ();
+ update_date ();
});
}
+
+ public GLib.DateTime get_birthday () {
+ return new GLib.DateTime.local (year_spin.get_value_as_int (),
+ month_combo.get_active () + 1,
+ day_spin.get_value_as_int (),
+ 0, 0, 0).to_utc ();
+ }
+
+ private void update_date() {
+ const int[] month_of_31 = {3, 5, 8, 10};
+
+ if (this.month_combo.get_active () in month_of_31) {
+ this.day_spin.set_range (1, 30);
+ } else if (this.month_combo.get_active () == 1) {
+ if (this.year_spin.get_value_as_int () % 400 == 0 ||
+ (this.year_spin.get_value_as_int () % 4 == 0 &&
+ this.year_spin.get_value_as_int () % 100 != 0)) {
+ this.day_spin.set_range (1, 29);
+ } else {
+ this.day_spin.set_range (1, 28);
+ }
+ } else {
+ this.day_spin.set_range (1, 31);
+ }
+ }
}
public class Contacts.AddressEditor : Gtk.Box {
@@ -138,10 +141,14 @@ public class Contacts.AddressEditor : Gtk.Box {
public signal void changed ();
- public AddressEditor (PostalAddressFieldDetails details) {
- set_hexpand (true);
- set_orientation (Gtk.Orientation.VERTICAL);
+ construct {
+ this.add_css_class ("contacts-editor-address");
+
+ this.hexpand = true;
+ this.orientation = Gtk.Orientation.VERTICAL;
+ }
+ public AddressEditor (PostalAddressFieldDetails details) {
for (int i = 0; i < entries.length; i++) {
string postal_part;
details.value.get (AddressEditor.postal_element_props[i], out postal_part);
@@ -153,8 +160,7 @@ public class Contacts.AddressEditor : Gtk.Box {
if (postal_part != null)
entries[i].set_text (postal_part);
- entries[i].get_style_context ().add_class ("contacts-postal-entry");
- add (entries[i]);
+ append (entries[i]);
var entry = entries[i];
var prop_name = AddressEditor.postal_element_props[i];
@@ -173,10 +179,6 @@ public class Contacts.AddressEditor : Gtk.Box {
}
return true;
}
-
- public override void grab_focus () {
- entries[0].grab_focus ();
- }
}
public class Contacts.EditorPropertyRow : Gtk.ListBoxRow {
@@ -188,24 +190,21 @@ public class Contacts.EditorPropertyRow : Gtk.ListBoxRow {
public Gtk.Revealer revealer;
construct {
+ this.add_css_class ("contacts-editor-property-row");
+
this.revealer = new Gtk.Revealer ();
//TODO: bind orientation property to available space
var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
box.set_valign (Gtk.Align.START);
- box.set_can_focus (false);
this.container = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6);
- this.container.set_can_focus (false);
this.header = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6);
- this.header.set_can_focus (false);
- box.pack_start (this.header);
- box.pack_end (this.container);
+ box.append (this.header);
+ box.append (this.container);
this.set_activatable (false);
this.set_selectable (false);
- this.set_can_focus (false);
- box.margin = 12;
- this.revealer.add (box);
- add (this.revealer);
- this.get_style_context ().add_class ("editor-property-row");
+
+ this.revealer.set_child (box);
+ this.set_child (this.revealer);
this.revealer.bind_property ("reveal-child", this, "is-removed", BindingFlags.INVERT_BOOLEAN);
}
@@ -232,9 +231,7 @@ public class Contacts.EditorPropertyRow : Gtk.ListBoxRow {
var duration = this.revealer.get_transition_duration ();
this.revealer.set_reveal_child (true);
this.revealer.set_transition_duration (duration);
- this.show_all ();
} else {
- this.show_all ();
this.revealer.set_reveal_child (true);
}
}
@@ -244,7 +241,7 @@ public class Contacts.EditorPropertyRow : Gtk.ListBoxRow {
title_label.set_hexpand (false);
title_label.set_halign (Gtk.Align.START);
title_label.margin_end = 6;
- this.header.pack_start (title_label);
+ this.header.append (title_label);
}
public void add_base_combo (Gee.Set<AbstractFieldDetails> details_set,
@@ -253,11 +250,11 @@ public class Contacts.EditorPropertyRow : Gtk.ListBoxRow {
AbstractFieldDetails details) {
var title_label = new Gtk.Label (label);
title_label.set_halign (Gtk.Align.START);
- this.header.pack_start (title_label);
+ this.header.append (title_label);
TypeCombo combo = new TypeCombo (combo_type);
combo.set_hexpand (false);
combo.set_active_from_field_details (details);
- this.header.pack_start (combo);
+ this.header.append (combo);
combo.changed.connect (() => {
combo.active_descriptor.save_to_field_details(details);
@@ -276,7 +273,7 @@ public class Contacts.EditorPropertyRow : Gtk.ListBoxRow {
value_entry.placeholder_text = placeholder;
value_entry.set_text (details.value);
value_entry.set_hexpand (true);
- this.container.pack_start (value_entry);
+ this.container.append (value_entry);
this.is_empty = details.value == "";
@@ -297,7 +294,7 @@ public class Contacts.EditorPropertyRow : Gtk.ListBoxRow {
value_entry.placeholder_text = placeholder;
value_entry.set_text (details.value);
value_entry.set_hexpand (true);
- this.container.pack_start (value_entry);
+ this.container.append (value_entry);
this.is_empty = details.value == "";
@@ -319,7 +316,7 @@ public class Contacts.EditorPropertyRow : Gtk.ListBoxRow {
value_entry.set_input_purpose (Gtk.InputPurpose.URL);
value_entry.set_text (details.value);
value_entry.set_hexpand (true);
- this.container.pack_start (value_entry);
+ this.container.append (value_entry);
this.is_empty = details.value == "";
@@ -336,10 +333,10 @@ public class Contacts.EditorPropertyRow : Gtk.ListBoxRow {
public void add_base_delete (Gee.Set<AbstractFieldDetails> details_set,
AbstractFieldDetails details) {
var delete_button = new Gtk.Button.from_icon_name ("user-trash-symbolic");
- delete_button.get_accessible ().set_name (_("Delete field"));
+ delete_button.tooltip_text = _("Delete field");
delete_button.set_valign (Gtk.Align.START);
this.bind_property ("is-empty", delete_button, "sensitive", BindingFlags.SYNC_CREATE |
BindingFlags.INVERT_BOOLEAN);
- this.container.pack_end (delete_button, false);
+ this.container.append (delete_button);
delete_button.clicked.connect (() => {
@@ -506,7 +503,7 @@ public class Contacts.EditorProperty : Gee.ArrayList<EditorPropertyRow> {
var value_entry = new Gtk.Entry ();
value_entry.set_text (details.nickname);
value_entry.set_hexpand (true);
- box.container.pack_start (value_entry);
+ box.container.append (value_entry);
value_entry.changed.connect (() => {
details.nickname = value_entry.get_text ();
@@ -531,14 +528,14 @@ public class Contacts.EditorProperty : Gee.ArrayList<EditorPropertyRow> {
var box = new EditorPropertyRow ("notes");
box.add_base_label (_("Note"));
- var sw = new Gtk.ScrolledWindow (null, null);
- sw.set_shadow_type (Gtk.ShadowType.OUT);
+ var sw = new Gtk.ScrolledWindow ();
+ sw.has_frame = true;
sw.set_size_request (-1, 100);
var value_text = new Gtk.TextView ();
value_text.get_buffer ().set_text (details.value);
value_text.set_hexpand (true);
- sw.add (value_text);
- box.container.pack_start (sw);
+ sw.set_child (value_text);
+ box.container.append (sw);
box.add_base_delete (details_set, details);
@@ -571,10 +568,10 @@ public class Contacts.EditorProperty : Gee.ArrayList<EditorPropertyRow> {
var box = new EditorPropertyRow ("birthday");
box.add_base_label (_("Birthday"));
- box.container.pack_start (button);
+ box.container.append (button);
button.clicked.connect (() => {
- var parent_window = button.get_toplevel () as Gtk.Window;
+ unowned var parent_window = button.get_root () as Gtk.Window;
if (parent_window != null) {
var dialog = new BirthdayEditor (parent_window, date);
@@ -585,17 +582,17 @@ public class Contacts.EditorProperty : Gee.ArrayList<EditorPropertyRow> {
box.is_empty = false;
}
});
- dialog.show_all ();
+ dialog.show ();
}
});
box.is_empty = details.birthday == null;
var delete_button = new Gtk.Button.from_icon_name ("user-trash-symbolic");
- delete_button.get_accessible ().set_name (_("Delete field"));
+ delete_button.tooltip_text = _("Delete field");
delete_button.set_valign (Gtk.Align.START);
box.bind_property ("is-empty", delete_button, "sensitive", BindingFlags.SYNC_CREATE |
BindingFlags.INVERT_BOOLEAN);
- box.container.pack_end (delete_button, false);
+ box.container.append (delete_button);
delete_button.clicked.connect (() => {
debug ("Birthday removed");
@@ -622,7 +619,7 @@ public class Contacts.EditorProperty : Gee.ArrayList<EditorPropertyRow> {
box.add_base_combo (details_set, _("Address"), TypeSet.general, details);
var value_address = new AddressEditor (details);
- box.container.pack_start (value_address);
+ box.container.append (value_address);
box.is_empty = value_address.is_empty ();
diff --git a/src/contacts-esd-setup.vala b/src/contacts-esd-setup.vala
index b0c58adb..5a958fc6 100644
--- a/src/contacts-esd-setup.vala
+++ b/src/contacts-esd-setup.vala
@@ -23,7 +23,7 @@ extern bool e_trust_prompt_run_for_source_finish (E.Source source, AsyncResult r
namespace Contacts {
public E.SourceRegistry? eds_source_registry = null;
-private E.CredentialsPrompter? eds_credentials_prompter = null;
+// private E.CredentialsPrompter? eds_credentials_prompter = null;
public bool ensure_eds_accounts (bool allow_interaction) {
if (eds_source_registry != null)
@@ -39,70 +39,72 @@ public bool ensure_eds_accounts (bool allow_interaction) {
return false;
}
- eds_credentials_prompter = new E.CredentialsPrompter (eds_source_registry);
+ // XXX
+ // eds_credentials_prompter = new E.CredentialsPrompter (eds_source_registry);
- if (!allow_interaction)
- eds_credentials_prompter.set_auto_prompt (false);
+ // if (!allow_interaction)
+ // eds_credentials_prompter.set_auto_prompt (false);
- var credentials_provider = eds_credentials_prompter.get_provider ();
+ // var credentials_provider = eds_credentials_prompter.get_provider ();
// First disable credentials prompt for all but addressbook sources...
foreach (var source in eds_source_registry.list_sources (null)) {
- // Mark for skip also currently disabled sources
- if (!source.has_extension (E.SOURCE_EXTENSION_ADDRESS_BOOK))
- eds_credentials_prompter.set_auto_prompt_disabled_for (source, true);
+ // Mark for skip also currently disabled sources
+ // if (!source.has_extension (E.SOURCE_EXTENSION_ADDRESS_BOOK))
+ // eds_credentials_prompter.set_auto_prompt_disabled_for (source, true);
}
// ...then enable credentials prompt for credential source of the addressbook sources,
// which can be a collection source.
foreach (var source in eds_source_registry.list_sources (E.SOURCE_EXTENSION_ADDRESS_BOOK)) {
- var cred_source = credentials_provider.ref_credentials_source (source);
- if (cred_source != null && !source.equal (cred_source))
- eds_credentials_prompter.set_auto_prompt_disabled_for (cred_source, false);
+ // var cred_source = credentials_provider.ref_credentials_source (source);
+ // if (cred_source != null && !source.equal (cred_source))
+ // eds_credentials_prompter.set_auto_prompt_disabled_for (cred_source, false);
}
// The eds_credentials_prompter responses to REQUIRED and REJECTED reasons,
// the SSL_FAILED should be handled elsewhere.
eds_source_registry.credentials_required.connect((src, reason, cert_pem, cert_err, err) => {
- on_credentials_required.begin (src, reason, cert_pem, cert_err, err);
+ on_credentials_required.begin (src, reason, cert_pem, cert_err, err);
});
- eds_credentials_prompter.process_awaiting_credentials ();
+ // eds_credentials_prompter.process_awaiting_credentials ();
return true;
}
private async void on_credentials_required (E.Source source, E.SourceCredentialsReason reason, string
cert_pem, TlsCertificateFlags cert_errors, Error err) {
- if (eds_credentials_prompter.get_auto_prompt_disabled_for (source))
- return;
-
- if (reason == E.SourceCredentialsReason.ERROR && err != null) {
- warning ("Failed to authenticate for source \"%s\": %s", source.display_name, err.message);
- return;
- }
-
- if (reason == E.SourceCredentialsReason.SSL_FAILED) {
- e_trust_prompt_run_for_source (eds_credentials_prompter.get_dialog_parent (),
- source, cert_pem, cert_errors, (err != null)? err.message : null, true,
- null, (obj, res) => on_source_trust_prompt_has_run.begin (source, res));
- }
+// if (eds_credentials_prompter.get_auto_prompt_disabled_for (source))
+// return;
+
+ if (reason == E.SourceCredentialsReason.ERROR && err != null) {
+ warning ("Failed to authenticate for source \"%s\": %s",
+ source.display_name, err.message);
+ return;
+ }
+
+ if (reason == E.SourceCredentialsReason.SSL_FAILED) {
+// e_trust_prompt_run_for_source (eds_credentials_prompter.get_dialog_parent (),
+// source, cert_pem, cert_errors, (err != null)? err.message : null, true,
+// null, (obj, res) => on_source_trust_prompt_has_run.begin (source, res));
+ }
}
-private async void on_source_trust_prompt_has_run (E.Source source, AsyncResult res) {
- try {
- e_trust_prompt_run_for_source_finish (source, res, null);
- } catch (Error e) {
- warning ("Failed to prompt for trust for source \"%s\": %s", source.display_name, e.message);
- return;
- }
-
- try {
- // Use null credentials to reuse those from the last time.
- yield source.invoke_authenticate (null, null);
- } catch (Error e) {
- warning ("Failed to invoke authenticate() for source \"%s\": %s", source.display_name, e.message);
- }
-}
+// private async void on_source_trust_prompt_has_run (E.Source source, AsyncResult res) {
+// try {
+// e_trust_prompt_run_for_source_finish (source, res, null);
+// } catch (Error e) {
+// warning ("Failed to prompt for trust for source \"%s\": %s", source.display_name, e.message);
+// return;
+// }
+
+// try {
+// // Use null credentials to reuse those from the last time.
+// yield source.invoke_authenticate (null, null);
+// } catch (Error e) {
+// warning ("Failed to invoke authenticate() for source \"%s\": %s", source.display_name, e.message);
+// }
+// }
public bool has_goa_account () {
foreach (var source in eds_source_registry.list_sources (E.SOURCE_EXTENSION_GOA)) {
@@ -188,6 +190,6 @@ public Gtk.Image? get_icon_for_goa_account (string goa_id) {
return null;
}
- return new Gtk.Image.from_gicon (provider_icon, Gtk.IconSize.DIALOG);
+ return new Gtk.Image.from_gicon (provider_icon);
}
}
diff --git a/src/contacts-in-app-notification.vala b/src/contacts-in-app-notification.vala
index 63256655..830d9c22 100644
--- a/src/contacts-in-app-notification.vala
+++ b/src/contacts-in-app-notification.vala
@@ -16,10 +16,14 @@
*/
[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-in-app-notification.ui")]
-public class Contacts.InAppNotification : Gtk.Revealer {
+public class Contacts.InAppNotification : Adw.Bin {
+
// Close the in-app notification after 5 seconds by default.
private const uint DEFAULT_KEEPALIVE = 5;
+ [GtkChild]
+ private unowned Gtk.Revealer revealer;
+
[GtkChild]
private unowned Gtk.Grid grid;
@@ -46,12 +50,11 @@ public class Contacts.InAppNotification : Gtk.Revealer {
button.show();
}
- this.notify["child-revealed"].connect (on_child_revealed_changed);
+ this.revealer.notify["child-revealed"].connect (on_child_revealed_changed);
}
- public new void show () {
- base.show ();
- this.reveal_child = true;
+ public void reveal () {
+ this.revealer.reveal_child = true;
Timeout.add_seconds (DEFAULT_KEEPALIVE, () => {
dismiss ();
@@ -60,18 +63,18 @@ public class Contacts.InAppNotification : Gtk.Revealer {
}
public void dismiss () {
- this.reveal_child = false;
+ this.revealer.reveal_child = false;
}
private void on_child_revealed_changed (Object o, ParamSpec p) {
- if (!this.child_revealed) {
+ if (!this.revealer.child_revealed) {
dismissed ();
destroy ();
}
}
[GtkCallback]
- private void on_close_button_clicked(Gtk.Button close_button) {
- dismiss();
+ private void on_close_button_clicked (Gtk.Button close_button) {
+ dismiss ();
}
}
diff --git a/src/contacts-link-suggestion-grid.vala b/src/contacts-link-suggestion-grid.vala
index 967ed68f..bff1bec4 100644
--- a/src/contacts-link-suggestion-grid.vala
+++ b/src/contacts-link-suggestion-grid.vala
@@ -24,6 +24,7 @@ using Folks;
*/
[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-link-suggestion-grid.ui")]
public class Contacts.LinkSuggestionGrid : Gtk.Grid {
+
private const int AVATAR_SIZE = 54;
[GtkChild]
@@ -39,13 +40,9 @@ public class Contacts.LinkSuggestionGrid : Gtk.Grid {
public signal void suggestion_rejected ();
public LinkSuggestionGrid (Individual individual) {
- get_style_context ().add_class ("contacts-suggestion");
-
var image_frame = new Avatar (AVATAR_SIZE, individual);
image_frame.hexpand = false;
- image_frame.margin = 12;
- image_frame.show ();
- attach (image_frame, 0, 0, 1, 2);
+ this.attach (image_frame, 0, 0, 1, 2);
this.description_label.xalign = 0;
this.description_label.label = Contacts.Utils.has_main_persona (individual) ?
@@ -56,7 +53,6 @@ public class Contacts.LinkSuggestionGrid : Gtk.Grid {
var extra_info = find_extra_description (individual);
if (extra_info != null) {
- this.extra_info_label.show ();
this.extra_info_label.label = extra_info;
}
@@ -66,22 +62,22 @@ public class Contacts.LinkSuggestionGrid : Gtk.Grid {
private string? find_extra_description (Individual individual) {
// First try an email address
- var emails = individual.email_addresses;
+ unowned var emails = individual.email_addresses;
if (!emails.is_empty)
return Utils.get_first<EmailFieldDetails> (emails).value;
// Maybe a website? Works well with e.g. social media profiles
- var urls = individual.urls;
+ unowned var urls = individual.urls;
if (!urls.is_empty)
return Utils.get_first<UrlFieldDetails> (urls).value;
// Try a phone number
- var phones = individual.phone_numbers;
+ unowned var phones = individual.phone_numbers;
if (!phones.is_empty)
return Utils.get_first<PhoneFieldDetails> (phones).value;
// A postal address maybe?
- var addresses = individual.postal_addresses;
+ unowned var addresses = individual.postal_addresses;
if (!addresses.is_empty)
return Utils.get_first<PostalAddressFieldDetails> (addresses).value.to_string ();
diff --git a/src/contacts-linked-personas-dialog.vala b/src/contacts-linked-personas-dialog.vala
index 26f3ca36..4f89d892 100644
--- a/src/contacts-linked-personas-dialog.vala
+++ b/src/contacts-linked-personas-dialog.vala
@@ -51,7 +51,7 @@ public class Contacts.LinkedPersonasDialog : Gtk.Dialog {
var image_frame = new Avatar (AVATAR_SIZE, individual);
image_frame.set_hexpand (false);
- image_frame.margin = 6;
+ // image_frame.margin = 6; XXX
image_frame.margin_end = 12;
row_grid.attach (image_frame, 0, 0, 1, 2);
@@ -73,7 +73,7 @@ public class Contacts.LinkedPersonasDialog : Gtk.Dialog {
var button = new Gtk.Button.with_label (_("Unlink"));
button.margin_end = 6;
button.set_valign (Gtk.Align.CENTER);
- button.get_child ().margin = 1;
+ // button.get_child ().margin = 1; XXX
row_grid.attach (button, 2, 0, 1, 2);
/* signal */
@@ -81,8 +81,7 @@ public class Contacts.LinkedPersonasDialog : Gtk.Dialog {
// TODO: handly unlinking
});
- row_grid.show_all ();
- this.linked_accounts_view.add (row_grid);
+ this.linked_accounts_view.append (row_grid);
}
}
}
diff --git a/src/contacts-list-pane.vala b/src/contacts-list-pane.vala
index 5439b365..797948c1 100644
--- a/src/contacts-list-pane.vala
+++ b/src/contacts-list-pane.vala
@@ -18,12 +18,12 @@
using Folks;
[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-list-pane.ui")]
-public class Contacts.ListPane : Gtk.Frame {
+public class Contacts.ListPane : Adw.Bin {
private Store store;
[GtkChild]
private unowned Gtk.ScrolledWindow contacts_list_container;
- private ContactList contacts_list;
+ private unowned ContactList contacts_list;
[GtkChild]
public unowned Gtk.SearchEntry filter_entry;
@@ -57,9 +57,10 @@ public class Contacts.ListPane : Gtk.Frame {
// Load the ContactsView and connect the necessary signals
- this.contacts_list = new ContactList (settings, contacts_store, this.filter_query);
+ var contactslist = new ContactList (settings, contacts_store, this.filter_query);
+ this.contacts_list = contactslist;
+ this.contacts_list_container.set_child (this.contacts_list);
bind_property ("state", this.contacts_list, "state", BindingFlags.BIDIRECTIONAL |
BindingFlags.SYNC_CREATE);
- this.contacts_list_container.add (this.contacts_list);
this.contacts_list.selection_changed.connect( (l, individual) => {
selection_changed (individual);
@@ -73,7 +74,7 @@ public class Contacts.ListPane : Gtk.Frame {
}
public void undo_deletion () {
- contacts_list.show_all ();
+ contacts_list.show ();
}
private void on_ui_state_changed (Object obj, ParamSpec pspec) {
@@ -111,9 +112,4 @@ public class Contacts.ListPane : Gtk.Frame {
private void on_delete_button_clicked (Gtk.Button delete_button) {
delete_contacts (this.contacts_list.get_marked_contacts_and_hide ());
}
-
- /* Limiting width hack */
- public override void get_preferred_width (out int minimum_width, out int natural_width) {
- minimum_width = natural_width = 300;
- }
}
diff --git a/src/contacts-main-window.vala b/src/contacts-main-window.vala
index 47c67e47..e471c326 100644
--- a/src/contacts-main-window.vala
+++ b/src/contacts-main-window.vala
@@ -18,31 +18,32 @@
using Folks;
[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-main-window.ui")]
-public class Contacts.MainWindow : Hdy.ApplicationWindow {
-
- private const GLib.ActionEntry[] action_entries = {
- { "edit-contact", edit_contact },
- { "share-contact", share_contact },
- { "unlink-contact", unlink_contact },
- { "delete-contact", delete_contact }
+public class Contacts.MainWindow : Adw.ApplicationWindow {
+
+ private const GLib.ActionEntry[] ACTION_ENTRIES = {
+ { "edit-contact", edit_contact },
+ // { "share-contact", share_contact },
+ { "unlink-contact", unlink_contact },
+ { "delete-contact", delete_contact },
+ { "sort-on", null, "s", "'surname'", sort_on_changed },
};
[GtkChild]
- private unowned Hdy.Leaflet header;
+ private unowned Adw.Leaflet header;
[GtkChild]
- private unowned Hdy.Leaflet content_box;
+ private unowned Adw.Leaflet content_box;
[GtkChild]
private unowned Gtk.Revealer back_revealer;
[GtkChild]
private unowned Gtk.Stack list_pane_stack;
[GtkChild]
- private unowned Gtk.Container contact_pane_container;
+ private unowned Gtk.Overlay contact_pane_container;
[GtkChild]
- private unowned Hdy.HeaderBar left_header;
+ private unowned Adw.HeaderBar left_header;
[GtkChild]
private unowned Gtk.Separator header_separator;
[GtkChild]
- private unowned Hdy.HeaderBar right_header;
+ private unowned Adw.HeaderBar right_header;
[GtkChild]
private unowned Gtk.Overlay notification_overlay;
[GtkChild]
@@ -50,17 +51,11 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
[GtkChild]
private unowned Gtk.MenuButton hamburger_menu_button;
[GtkChild]
- private unowned Gtk.ModelButton sort_on_firstname_button;
- [GtkChild]
- private unowned Gtk.ModelButton sort_on_surname_button;
- [GtkChild]
- private unowned Gtk.MenuButton contact_menu_button;
+ private unowned Gtk.Box contact_sheet_buttons;
[GtkChild]
private unowned Gtk.ToggleButton favorite_button;
private bool ignore_favorite_button_toggled;
[GtkChild]
- private unowned Gtk.Button unlink_button;
- [GtkChild]
private unowned Gtk.Button add_button;
[GtkChild]
private unowned Gtk.Button cancel_button;
@@ -73,13 +68,14 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
private ListPane list_pane;
private ContactPane contact_pane;
+ // Actions
+ private SimpleActionGroup actions = new SimpleActionGroup ();
+
public UiState state { get; set; default = UiState.NORMAL; }
// Window state
public int window_width { get; set; }
public int window_height { get; set; }
- public bool window_maximized { get; set; }
- public bool window_fullscreen { get; set; }
public Settings settings { get; construct set; }
@@ -88,94 +84,51 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
}
construct {
- SimpleActionGroup actions = new SimpleActionGroup ();
- actions.add_action_entries (action_entries, this);
- insert_action_group ("window", actions);
-
- this.sort_on_firstname_button.clicked.connect (() => {
- this.settings.sort_on_surname = false;
- on_sort_changed ();
- });
- this.sort_on_surname_button.clicked.connect (() => {
- this.settings.sort_on_surname = true;
- on_sort_changed ();
- });
- on_sort_changed ();
+ this.actions.add_action_entries (ACTION_ENTRIES, this);
+ this.insert_action_group ("window", this.actions);
this.notify["state"].connect (on_ui_state_changed);
- create_contact_pane ();
- connect_button_signals ();
- restore_window_state ();
+ this.create_contact_pane ();
+ this.connect_button_signals ();
+ this.restore_window_state ();
+ this.close_request.connect (on_close_request);
if (Config.PROFILE == "development")
- get_style_context ().add_class ("devel");
+ this.add_css_class ("devel");
}
public MainWindow (Settings settings, App app, Store contacts_store) {
Object (
application: app,
settings: settings,
- show_menubar: false,
- visible: true,
store: contacts_store
);
- }
- private void on_sort_changed () {
- this.sort_on_firstname_button.active = !this.settings.sort_on_surname;
- this.sort_on_surname_button.active = this.settings.sort_on_surname;
+ unowned var sort_key = this.settings.sort_on_surname? "surname" : "firstname";
+ var sort_action = (SimpleAction) this.actions.lookup_action ("sort-on");
+ sort_action.set_state (new Variant.string (sort_key));
}
private void restore_window_state () {
- // Load initial values
- this.window_width = this.settings.window_width;
- this.window_height = this.settings.window_height;
- this.window_maximized = this.settings.window_maximized;
- this.window_fullscreen = this.settings.window_fullscreen;
-
// Apply them
- if (this.window_width > 0 && this.window_height > 0)
- set_default_size (this.window_width, this.window_height);
- if (this.window_maximized)
+ if (this.settings.window_width > 0 && this.settings.window_height > 0)
+ set_default_size (this.settings.window_width, this.settings.window_height);
+ if (this.settings.window_maximized)
maximize ();
- if (this.window_fullscreen)
+ if (this.settings.window_fullscreen)
fullscreen ();
}
- public override bool window_state_event (Gdk.EventWindowState event) {
- this.window_maximized = (Gdk.WindowState.MAXIMIZED in event.new_window_state);
- this.window_fullscreen = (Gdk.WindowState.FULLSCREEN in event.new_window_state);
-
- return base.window_state_event (event);
- }
-
- // Called on window resize. Save window size for the next start.
- public override void size_allocate (Gtk.Allocation allocation) {
- base.size_allocate (allocation);
-
- if (this.window_fullscreen || this.window_maximized)
- return;
-
- // Get the size via widget.get_size() instead of the allocation
- // so that the window isn't ever-expanding (in case of CSD).
- int width = 0;
- int height = 0;
- get_size(out width, out height);
-
- this.window_width = width;
- this.window_height = height;
- }
-
private void create_contact_pane () {
this.contact_pane = new ContactPane (this, this.store);
this.contact_pane.visible = true;
this.contact_pane.hexpand = true;
this.contact_pane.contacts_linked.connect (contact_pane_contacts_linked_cb);
this.contact_pane.display_name_changed.connect ((display_name) => {
- this.right_header.title = display_name;
+ update_header_titles (null, display_name);
});
- this.contact_pane_container.add (this.contact_pane);
+ this.contact_pane_container.set_child (this.contact_pane);
}
/**
@@ -196,15 +149,14 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
list_pane.delete_contacts.connect (delete_contacts);
list_pane.contacts_marked.connect ((nr_contacts) => {
- if (this.state == UiState.SELECTING)
- this.left_header.title = ngettext ("%d Selected", "%d Selected", nr_contacts)
- .printf (nr_contacts);
- else
- this.left_header.title = _("Contacts");
- });
+ string left_title = _("Contacts");
+ if (this.state == UiState.SELECTING)
+ left_title = ngettext ("%d Selected", "%d Selected", nr_contacts)
+ .printf (nr_contacts);
+ update_header_titles (left_title, null);
+ });
- list_pane_stack.add (list_pane);
- list_pane.show ();
+ list_pane_stack.add_child (list_pane);
list_pane_stack.visible_child = list_pane;
if (this.contact_pane.individual != null)
@@ -219,8 +171,7 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
= (this.state == UiState.NORMAL || this.state == UiState.SHOWING);
// UI when showing a contact
- this.contact_menu_button.visible
- = this.favorite_button.visible
+ this.contact_sheet_buttons.visible
= (this.state == UiState.SHOWING);
// Selecting UI
@@ -228,21 +179,21 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
this.selection_button.visible = !(this.state == UiState.SELECTING || this.state.editing ());
if (this.state != UiState.SELECTING)
- this.left_header.title = _("Contacts");
+ update_header_titles (_("Contacts"), null);
// Editing UI
this.cancel_button.visible
= this.done_button.visible
+ = this.right_header.show_end_title_buttons
= this.state.editing ();
+ this.right_header.show_end_title_buttons = !this.state.editing ();
if (this.state.editing ()) {
this.done_button.use_underline = true;
this.done_button.label = (this.state == UiState.CREATING)? _("_Add") : _("Done");
// Cast is required because Gtk.Button.set_focus_on_click is deprecated and
// we have to use Gtk.Widget.set_focus_on_click instead
- ((Gtk.Widget) this.done_button).set_focus_on_click (true);
+ this.done_button.set_focus_on_click (true);
}
- // When selecting or editing, we get special headerbars
- set_selection_mode (this.state == UiState.SELECTING || this.state.editing ());
// Allow the back gesture when not browsing
this.content_box.can_swipe_back = this.state == UiState.NORMAL ||
@@ -250,30 +201,11 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
this.state == UiState.SELECTING;
}
- private void set_selection_mode (bool selection_mode) {
- unowned var left_ctx = this.left_header.get_style_context ();
- unowned var separator_ctx = this.header_separator.get_style_context ();
- unowned var right_ctx = this.right_header.get_style_context ();
- if (selection_mode) {
- left_ctx.add_class ("selection-mode");
- separator_ctx.add_class ("selection-mode");
- right_ctx.add_class ("selection-mode");
- } else {
- left_ctx.remove_class ("selection-mode");
- separator_ctx.remove_class ("selection-mode");
- right_ctx.remove_class ("selection-mode");
- }
- }
-
[GtkCallback]
private void on_back_clicked () {
show_list_pane ();
}
- private void share_contact () {
- debug ("Share isn't implemented, yet");
- }
-
private void edit_contact () {
if (this.contact_pane.individual == null)
return;
@@ -281,7 +213,7 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
this.state = UiState.UPDATING;
unowned var name = this.contact_pane.individual.display_name;
- this.right_header.title = _("Editing %s").printf (name);
+ update_header_titles (null, _("Editing %s").printf (name));
this.contact_pane.edit_contact ();
}
@@ -300,8 +232,8 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
[GtkCallback]
private void on_selection_button_clicked () {
this.state = UiState.SELECTING;
- this.left_header.title = ngettext ("%d Selected", "%d Selected", 0)
- .printf (0);
+ update_header_titles (ngettext ("%d Selected", "%d Selected", 0) .printf (0),
+ null);
}
private void unlink_contact () {
@@ -337,6 +269,12 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
delete_contacts (new Gee.ArrayList<Individual>.wrap ({ individual }));
}
+ private void sort_on_changed (SimpleAction action, GLib.Variant? new_state) {
+ unowned var sort_key = new_state.get_string ();
+ this.settings.sort_on_surname = (sort_key == "surname");
+ action.set_state (new_state);
+ }
+
private void stop_editing (bool cancel = false) {
if (this.state == UiState.CREATING) {
if (cancel) {
@@ -350,16 +288,12 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
this.contact_pane.stop_editing (cancel);
this.list_pane.scroll_to_contact ();
- if (this.contact_pane.individual != null) {
- this.right_header.title = this.contact_pane.individual.display_name;
- } else {
- this.right_header.title = "";
- }
+ update_header_titles (null, "");
}
public void add_notification (InAppNotification notification) {
this.notification_overlay.add_overlay (notification);
- notification.show ();
+ notification.reveal ();
}
public void set_shown_contact (Individual? i) {
@@ -372,15 +306,13 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
list_pane.select_contact (i);
// clearing right_header
+ update_header_titles (null, "");
if (i != null) {
this.ignore_favorite_button_toggled = true;
this.favorite_button.active = i.is_favourite;
this.ignore_favorite_button_toggled = false;
this.favorite_button.tooltip_text = (i.is_favourite)? _("Unmark as favorite")
- : _("Mark as favorite");
- this.right_header.title = i.display_name;
- } else {
- this.right_header.title = "";
+ : _("Mark as favorite");
}
}
@@ -393,7 +325,7 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
this.state = UiState.CREATING;
- this.right_header.title = _("New Contact");
+ update_header_titles (null, _("New Contact"));
this.contact_pane.new_contact ();
show_contact_pane ();
@@ -423,6 +355,20 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
this.header.visible_child == this.right_header;
}
+ private void update_header_titles (string? left_title, string? right_title) {
+ if (left_title != null) {
+ var label = new Gtk.Label (left_title);
+ label.add_css_class ("title");
+ this.left_header.set_title_widget (label);
+ }
+
+ if (right_title != null) {
+ var label = new Gtk.Label (right_title);
+ label.add_css_class ("title");
+ this.right_header.set_title_widget (label);
+ }
+ }
+
private void show_list_pane () {
content_box.visible_child_name = "list-pane";
update_header ();
@@ -434,7 +380,7 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
}
public void show_search (string query) {
- list_pane.filter_entry.set_text (query);
+ this.list_pane.filter_entry.set_text (query);
}
private void connect_button_signals () {
@@ -452,46 +398,53 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
unowned var individual = this.contact_pane.individual;
if (individual == null)
return;
- this.unlink_button.set_visible (individual.personas.size > 1);
+
+ var unlink_action = this.actions.lookup_action ("unlink-contact");
+ ((SimpleAction) unlink_action).set_enabled (individual.personas.size > 1);
});
}
[GtkCallback]
- bool key_press_event_cb (Gdk.EventKey event) {
- if ((event.keyval == Gdk.keyval_from_name ("q")) &&
- ((event.state & Gdk.ModifierType.CONTROL_MASK) != 0)) {
+ bool on_key_pressed (Gtk.EventControllerKey controller,
+ uint keyval,
+ uint keycode,
+ Gdk.ModifierType state) {
+ if ((keyval == Gdk.keyval_from_name ("q")) &&
+ ((state & Gdk.ModifierType.CONTROL_MASK) != 0)) {
// Clear the contacts so any changed information is stored
this.contact_pane.show_contact (null);
destroy ();
- } else if (((event.keyval == Gdk.Key.s) ||
- (event.keyval == Gdk.Key.f)) &&
- ((event.state & Gdk.ModifierType.CONTROL_MASK) != 0)) {
+ } else if ((keyval == Gdk.Key.s || keyval == Gdk.Key.f) &&
+ ((state & Gdk.ModifierType.CONTROL_MASK) != 0)) {
// Explicitly check if this.list_pane is already initialized,
// or we might crash at startup
if (this.list_pane != null && this.list_pane.filter_entry != null)
Utils.grab_entry_focus_no_select (this.list_pane.filter_entry);
- } else if (event.length >= 1 &&
- Gdk.keyval_to_unicode (event.keyval) != 0 &&
- (event.state & Gdk.ModifierType.CONTROL_MASK) == 0 &&
- (event.state & Gdk.ModifierType.MOD1_MASK) == 0 &&
- (event.keyval != Gdk.Key.Escape) &&
- (event.keyval != Gdk.Key.Tab) &&
- (event.keyval != Gdk.Key.BackSpace) ) {
+ } else if (Gdk.keyval_to_unicode (keyval) != 0 &&
+ (state & Gdk.ModifierType.CONTROL_MASK) == 0 &&
+ (state & Gdk.ModifierType.ALT_MASK) == 0 &&
+ (keyval != Gdk.Key.Escape) &&
+ (keyval != Gdk.Key.Tab) &&
+ (keyval != Gdk.Key.BackSpace) ) {
// Explicitly check if this.list_pane is already initialized,
// or we might crash at startup
if (this.list_pane != null && this.list_pane.filter_entry != null)
Utils.grab_entry_focus_no_select (this.list_pane.filter_entry);
- propagate_key_event (event);
}
- return false;
+ return Gdk.EVENT_PROPAGATE;
}
- [GtkCallback]
- bool delete_event_cb (Gdk.EventAny event) {
+ private bool on_close_request () {
// Clear the contacts so any changed information is stored
this.contact_pane.show_contact (null);
- return false;
+
+ this.settings.window_width = this.default_width; // XXX is default_ correct here?
+ this.settings.window_height = this.default_height;
+ this.settings.window_maximized = this.maximized;
+ this.settings.window_fullscreen = this.fullscreened;
+
+ return Gdk.EVENT_STOP; // XXX what the hell am i supposed to retunr here?
}
void list_pane_selection_changed_cb (Individual? new_selection) {
@@ -594,14 +547,4 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
add_notification (notification);
}
-
- // Override the default destroy() to save the window state
- public override void destroy () {
- this.settings.window_width = this.window_width;
- this.settings.window_height = this.window_height;
- this.settings.window_maximized = this.window_maximized;
- this.settings.window_fullscreen = this.window_fullscreen;
-
- base.destroy ();
- }
}
diff --git a/src/contacts-setup-window.vala b/src/contacts-setup-window.vala
index 9305b8a9..4dad6759 100644
--- a/src/contacts-setup-window.vala
+++ b/src/contacts-setup-window.vala
@@ -18,7 +18,7 @@
using Folks;
[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-setup-window.ui")]
-public class Contacts.SetupWindow : Hdy.ApplicationWindow {
+public class Contacts.SetupWindow : Adw.ApplicationWindow {
[GtkChild]
private unowned Gtk.Box content;
@@ -37,7 +37,7 @@ public class Contacts.SetupWindow : Hdy.ApplicationWindow {
this.setup_accounts_list = new AccountsList (store);
this.setup_accounts_list.hexpand = true;
this.setup_accounts_list.show ();
- this.content.add (this.setup_accounts_list);
+ this.content.append (this.setup_accounts_list);
// Listen for changes
store.backend_store.backend_available.connect ( () => {
diff --git a/src/contacts-utils.vala b/src/contacts-utils.vala
index 48388765..f7a95f31 100644
--- a/src/contacts-utils.vala
+++ b/src/contacts-utils.vala
@@ -68,7 +68,7 @@ namespace Contacts.Utils {
public void compose_mail (string email) {
var mailto_uri = "mailto:" + Uri.escape_string (email, "@" , false);
try {
- Gtk.show_uri_on_window (null, mailto_uri, 0);
+ Gtk.show_uri (null, mailto_uri, 0);
} catch (Error e) {
debug ("Couldn't launch URI \"%s\": %s", mailto_uri, e.message);
}
@@ -116,7 +116,7 @@ namespace Contacts.Utils {
return null;
}
- public void grab_entry_focus_no_select (Gtk.Entry entry) {
+ public void grab_entry_focus_no_select (Gtk.SearchEntry entry) {
int start, end;
if (!entry.get_selection_bounds (out start, out end)) {
start = end = entry.get_position ();
@@ -189,8 +189,8 @@ namespace Contacts.Utils {
Gtk.MessageType.ERROR,
Gtk.ButtonsType.OK,
"%s", error);
- dialog.run();
- dialog.destroy();
+ dialog.response.connect(() => { dialog.destroy(); });
+ dialog.show();
}
public bool persona_is_main (Persona persona) {
diff --git a/src/meson.build b/src/meson.build
index d9776384..733c9822 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -14,6 +14,7 @@ libcontacts_sources = files(
'contacts-type-descriptor.vala',
'contacts-utils.vala',
'contacts-vcard-type-mapping.vala',
+ 'xdg-portal-camera.vala',
)
contacts_vala_args = [
@@ -24,7 +25,6 @@ contacts_vala_args = [
contacts_c_args = [
'-include', 'config.h',
- '-DGNOME_DESKTOP_USE_UNSTABLE_API',
'-DLOCALEDIR="@0@"'.format(locale_dir),
]
@@ -34,22 +34,15 @@ contacts_deps = [
gee,
gio_unix,
glib,
- gnome_desktop,
goa,
- gtk,
+ gtk4_dep,
+ libadwaita_dep,
libebook,
libedataserver,
- libedataserverui,
- libhandy,
+ # libedataserverui,
math,
]
-# Add extra stuff given a certain set of options
-if cheese_dep.found() and cheese_gtk_dep.found()
- contacts_deps += [ cheese_dep, cheese_gtk_dep ]
- contacts_vala_args += [ '-D', 'HAVE_CHEESE' ]
-endif
-
if get_option('telepathy')
contacts_deps += [ folks_telepathy, telepathy_glib ]
contacts_vala_args += [ '-D', 'HAVE_TELEPATHY' ]
@@ -82,7 +75,7 @@ contacts_vala_sources = files(
'contacts-contact-list.vala',
'contacts-contact-pane.vala',
'contacts-contact-sheet.vala',
- 'contacts-crop-cheese-dialog.vala',
+ 'contacts-crop-dialog.vala',
'contacts-editor-persona.vala',
'contacts-editor-property.vala',
'contacts-in-app-notification.vala',
diff --git a/src/xdg-portal-camera.vala b/src/xdg-portal-camera.vala
new file mode 100644
index 00000000..88648a3e
--- /dev/null
+++ b/src/xdg-portal-camera.vala
@@ -0,0 +1,17 @@
+using GLib;
+
+[DBus (name = "org.freedesktop.portal.Camera", timeout = 120000)]
+public interface Xdg.Portal.Camera : GLib.Object {
+
+ [DBus (name = "IsCameraPresent")]
+ public abstract bool is_camera_present { get; }
+
+ [DBus (name = "Version")]
+ public abstract bool version { get; }
+
+ [DBus (name = "AccessCamera")]
+ public abstract int access_camera (GLib.HashTable<string, GLib.Variant> options) throws DBusError, IOError;
+
+ [DBus (name = "OpenPipeWireRemote")]
+ public abstract int open_pipe_wire_remote (GLib.HashTable<string, GLib.Variant> options) throws DBusError,
IOError;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]