[gnome-contacts/nielsdg/gtk4] WIP




commit 9973eacc2baed9452063c391b952cdfeed61df45
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Thu Oct 14 01:19:13 2021 +0200

    WIP

 data/ui/contacts-accounts-list.ui        |  13 +-
 data/ui/contacts-avatar-selector.ui      |  61 +--
 data/ui/contacts-contact-pane.ui         | 101 ++---
 data/ui/contacts-in-app-notification.ui  |  82 ++--
 data/ui/contacts-link-suggestion-grid.ui |  37 +-
 data/ui/contacts-list-pane.ui            |  43 +-
 data/ui/contacts-main-window.ui          | 658 ++++++++++++-------------------
 data/ui/contacts-setup-window.ui         |  51 +--
 data/ui/style.css                        |  23 +-
 docs/meson.build                         |   4 +-
 meson.build                              |   8 +-
 meson_options.txt                        |   2 +-
 src/cc-crop-area.c                       | 163 ++++----
 src/contacts-accounts-list.vala          |  85 ++--
 src/contacts-addressbook-dialog.vala     |  21 +-
 src/contacts-addressbook-list.vala       |  45 ++-
 src/contacts-app.vala                    |  35 +-
 src/contacts-avatar-selector.vala        | 119 ++----
 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          |  29 +-
 src/contacts-crop-cheese-dialog.vala     |   9 +-
 src/contacts-editor-persona.vala         |  38 +-
 src/contacts-editor-property.vala        | 180 +++++----
 src/contacts-esd-setup.vala              | 107 ++---
 src/contacts-in-app-notification.vala    |  18 +-
 src/contacts-link-suggestion-grid.vala   |   3 +-
 src/contacts-linked-personas-dialog.vala |   7 +-
 src/contacts-list-pane.vala              |  19 +-
 src/contacts-main-window.vala            | 209 ++++------
 src/contacts-setup-window.vala           |   4 +-
 src/contacts-utils.vala                  |   8 +-
 src/meson.build                          |  10 +-
 35 files changed, 1135 insertions(+), 1364 deletions(-)
---
diff --git a/data/ui/contacts-accounts-list.ui b/data/ui/contacts-accounts-list.ui
index d08d297e..2fabac96 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">
+  <template class="ContactsAccountsList" parent="AdwBin">
     <property name="visible">True</property>
-    <property name="selection_mode">none</property>
     <style>
-      <class name="content"/>
+      <class name="contacts-accounts-list"/>
     </style>
+    <object class="GtkListBox" id="listbox">
+      <property name="visible">True</property>
+      <property name="selection_mode">none</property>
+      <style>
+        <class name="content"/>
+      </style>
+    </object>
   </template>
 </interface>
diff --git a/data/ui/contacts-avatar-selector.ui b/data/ui/contacts-avatar-selector.ui
index 336b6baf..b0029163 100644
--- a/data/ui/contacts-avatar-selector.ui
+++ b/data/ui/contacts-avatar-selector.ui
@@ -7,13 +7,15 @@
     <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="visible">True</property>
-        <property name="can_focus">False</property>
-        <property name="can_focus">False</property>
+      <object class="AdwHeaderBar">
+        <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">Select a new avatar</property>
+          </object>
+        </property>
         <child>
           <object class="GtkButton">
             <property name="label" translatable="yes">Cancel</property>
@@ -23,48 +25,36 @@
             <signal name="clicked" handler="on_cancel_clicked" swapped="no"/>
           </object>
         </child>
-        <child>
+        <child type="end">
           <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>
       </object>
     </child>
     <child>
       <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,36 +62,26 @@
                     <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">
                 <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"/>
               </object>
@@ -109,16 +89,11 @@
             <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"/>
               </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-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..f0ab5f12 100644
--- a/data/ui/contacts-link-suggestion-grid.ui
+++ b/data/ui/contacts-link-suggestion-grid.ui
@@ -1,26 +1,21 @@
 <?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>
     <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="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 +27,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 +44,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 +51,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..0cbda4ed 100644
--- a/data/ui/contacts-list-pane.ui
+++ b/data/ui/contacts-list-pane.ui
@@ -1,69 +1,41 @@
 <?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">
+  <template class="ContactsListPane" parent="AdwBin">
     <property name="can_focus">False</property>
     <property name="hexpand">False</property>
     <property name="hexpand_set">True</property>
-    <property name="shadow_type">none</property>
     <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"/>
           </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>
@@ -73,17 +45,8 @@
                   <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..601e707a 100644
--- a/data/ui/contacts-main-window.ui
+++ b/data/ui/contacts-main-window.ui
@@ -1,458 +1,326 @@
 <?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 &lt;sup&gt;↗&lt;/sup&gt;</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">
+  <menu id="hamburger_menu_popover">
+    <section>
+      <!-- <property name="halign">start</property> XXX -->
+      <attribute name="label" translatable="yes">List Contacts By:</attribute>
+      <item>
+        <attribute name="label" translatable="yes">First Name</attribute>
+        <attribute name="action">window.sort-on-surname</attribute>
+        <attribute name="target">false</attribute>
+      </item>
+      <item>
+        <attribute name="label" translatable="yes">Surname</attribute>
+        <attribute name="action">window.sort-on-surname</attribute>
+        <attribute name="target">true</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>
+      <item>
+        <attribute name="action">window.share-contact</attribute>
+        <attribute name="label" translatable="yes">Share</attribute>
+        <attribute name="hidden-when">action-missing</attribute>
+      </item>
+      <item>
+        <attribute name="action">window.edit-contact</attribute>
+        <attribute name="label" translatable="yes">Edit</attribute>
+      </item>
+      <item>
+        <attribute name="action">window.unlink-contact</attribute>
+        <attribute name="label" translatable="yes">Unlink</attribute>
+        <attribute name="hidden-when">action-disabled</attribute>
+      </item>
+    </section>
+    <section>
+      <item>
+        <attribute name="action">window.delete-contact</attribute>
+        <attribute name="label" translatable="yes">Delete</attribute>
+      </item>
+    </section>
+  </menu>
+
+  <template class="ContactsMainWindow" parent="AdwApplicationWindow">
     <property name="can_focus">False</property>
     <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>
+          <object class="AdwLeaflet" id="header">
             <property name="can_focus">False</property>
             <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="can_focus">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="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>
+                          <object class="GtkImage">
+                            <property name="can_focus">False</property>
+                            <property name="icon_name">list-add-symbolic</property>
+                            <property name="icon_size">1</property>
+                          </object>
+                        </child>
                       </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="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="can_focus">False</property>
+                            <property name="icon_name">object-select-symbolic</property>
+                            <property name="icon_size">1</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="end">
+                      <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>
                     </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"/>
-                        <style>
-                          <class name="image-button"/>
-                        </style>
-                        <child internal-child="accessible">
-                          <object class="AtkObject" id="a11y-back">
-                            <property name="accessible-name" translatable="yes">Back</property>
-                          </object>
-                        </child>
+                      <object class="GtkRevealer" id="back_revealer">
+                        <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"/>
                         <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="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>
-                  </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 class="GtkButton" id="cancel_button">
+                        <property name="visible">False</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>
                     </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>
+                    <child type="end">
+                      <object class="GtkMenuButton" id="contact_menu_button">
+                        <property name="visible">False</property>
+                        <property name="focus_on_click">False</property>
+                        <property name="menu-model">contact_sheet_menu</property>
+                        <property name="tooltip_text" translatable="yes">Main Menu</property>
                         <property name="icon_name">view-more-symbolic</property>
                       </object>
                     </child>
+                    <child type="end">
+                      <object class="GtkToggleButton" id="favorite_button">
+                        <property name="visible">False</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="can_focus">False</property>
+                            <property name="icon_name">starred-symbolic</property>
+                            <property name="icon_size">1</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="end">
+                      <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>
+                    </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>
           <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>
+              <object class="AdwLeaflet" id="content_box">
                 <property name="can_focus">False</property>
                 <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>
+                  <object class="AdwLeafletPage">
+                    <property name="name">list-pane</property>
+                    <property name="child">
+                      <object class="GtkStack" id="list_pane_stack">
                         <property name="can_focus">False</property>
-                        <property name="orientation">vertical</property>
-                        <property name="width_request">300</property>
-                        <property name="homogeneous">True</property>
+                        <property name="hexpand">False</property>
                         <child>
-                          <object class="GtkSpinner">
-                            <property name="visible">True</property>
+                          <object class="GtkBox">
                             <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>
-                        <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>
+                            <property name="orientation">vertical</property>
+                            <property name="width_request">300</property>
+                            <property name="homogeneous">True</property>
+                            <child>
+                              <object class="GtkSpinner">
+                                <property name="can_focus">False</property>
+                                <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="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>
+                            </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="can_focus">False</property>
+                        <property name="hexpand">True</property>
+                      </object>
+                    </property>
+                  </object>
                 </child>
               </object>
             </child>
@@ -475,18 +343,10 @@
       <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>
+  <!-- <object class="AdwSwipeGroup" id="swipe_group"> XXX -->
+  <!--   <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..2b99e4a6 100644
--- a/data/ui/style.css
+++ b/data/ui/style.css
@@ -23,14 +23,14 @@
  border-width: 1px 1px 0 1px;
 }
 
-.contacts-postal-entry:nth-child(first) {
- border-radius: 4px 4px 0 0;
-}
+  .contacts-postal-entry:first-child {
+    border-radius: 4px 4px 0 0;
+  }
 
-.contacts-postal-entry:nth-child(last) {
- border-radius: 0 0 4px 4px;
- border-width: 1px;
-}
+  .contacts-postal-entry:first-child {
+    border-radius: 0 0 4px 4px;
+    border-width: 1px;
+  }
 
 /* The style for the background "watermark" image and text.
  * (copied from dim-label) */
@@ -45,7 +45,7 @@
 flowboxchild.circular {
   padding: 4px;
   border-radius: 9999px;
-  -gtk-outline-radius: 9999px;
+  /* -gtk-outline-radius: 9999px; XXX */
 }
 
 .avatar-button {
@@ -70,6 +70,7 @@ row.editor-property-row {
 popover list {
   background-color: @theme_bg_color;
 }
-popover list row:hover {
-  background-color: @theme_selected_fg_color
-}
+
+  popover list row:hover {
+    background-color: @theme_selected_fg_color;
+  }
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..a8c87adf 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('cheese', type: 'feature', value: 'disabled', description: 'If enabled, allows creaing an avatar with 
the webcam')
 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/src/cc-crop-area.c b/src/cc-crop-area.c
index 799d55c1..e3114844 100644
--- a/src/cc-crop-area.c
+++ b/src/cc-crop-area.c
@@ -35,7 +35,7 @@ struct _CcCropArea {
         GdkPixbuf *color_shifted;
         gdouble scale;
         GdkRectangle image;
-        GdkCursorType current_cursor;
+        const char *current_cursor;
         GdkRectangle crop;
         gint active_region;
         gint last_press_x;
@@ -90,14 +90,13 @@ shift_colors (GdkPixbuf *pixbuf,
 static void
 update_pixbufs (CcCropArea *area)
 {
-        gint width;
-        gint height;
+        GtkWidget *widget = GTK_WIDGET (area);
+        int width;
+        int height;
         GtkAllocation allocation;
-        gdouble scale;
-        gint dest_width, dest_height;
-        GtkWidget *widget;
+        double scale;
+        int dest_width, dest_height;
 
-        widget = GTK_WIDGET (area);
         gtk_widget_get_allocation (widget, &allocation);
 
         width = gdk_pixbuf_get_width (area->browse_pixbuf);
@@ -179,16 +178,19 @@ typedef enum {
         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)
 {
+        CcCropArea *uarea = CC_CROP_AREA (draw_area);
         GdkRectangle crop;
-        gint width, height, ix, iy;
-        CcCropArea *uarea = CC_CROP_AREA (widget);
+        int width, height, ix, iy;
 
         if (uarea->browse_pixbuf == NULL)
-                return FALSE;
+                return;
 
         update_pixbufs (uarea);
 
@@ -232,8 +234,6 @@ cc_crop_area_draw (GtkWidget *widget,
         cairo_line_to (cr, crop.x, crop.y + crop.height - 15);
 
         cairo_stroke (cr);
-
-        return FALSE;
 }
 
 typedef enum {
@@ -287,7 +287,7 @@ update_cursor (CcCropArea *area,
                gint           x,
                gint           y)
 {
-        gint cursor_type;
+        const char *cursor_type;
         GdkRectangle crop;
         gint region;
 
@@ -299,43 +299,50 @@ update_cursor (CcCropArea *area,
 
         switch (region) {
         case OUTSIDE:
-                cursor_type = GDK_LEFT_PTR;
+                cursor_type = "default";
                 break;
         case TOP_LEFT:
-                cursor_type = GDK_TOP_LEFT_CORNER;
+                cursor_type = "nw-resize";
                 break;
         case TOP:
-                cursor_type = GDK_TOP_SIDE;
+                cursor_type = "n-resize";
                 break;
         case TOP_RIGHT:
-                cursor_type = GDK_TOP_RIGHT_CORNER;
+                cursor_type = "ne-resize";
                 break;
         case LEFT:
-                cursor_type = GDK_LEFT_SIDE;
+                cursor_type = "w-resize";
                 break;
         case INSIDE:
-                cursor_type = GDK_FLEUR;
+                cursor_type = "move";
                 break;
         case RIGHT:
-                cursor_type = GDK_RIGHT_SIDE;
+                cursor_type = "e-resize";
                 break;
         case BOTTOM_LEFT:
-                cursor_type = GDK_BOTTOM_LEFT_CORNER;
+                cursor_type = "sw-resize";
                 break;
         case BOTTOM:
-                cursor_type = GDK_BOTTOM_SIDE;
+                cursor_type = "s-resize";
                 break;
         case BOTTOM_RIGHT:
-                cursor_type = GDK_BOTTOM_RIGHT_CORNER;
+                cursor_type = "se-resize";
                 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);
+                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;
         }
@@ -356,10 +363,12 @@ eval_radial_line (gdouble center_x, gdouble center_y,
 }
 
 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);
+        CcCropArea *area = CC_CROP_AREA (user_data);
         gint x, y;
         gint delta_x, delta_y;
         gint width, height;
@@ -374,18 +383,19 @@ cc_crop_area_motion_notify_event (GtkWidget      *widget,
         if (area->browse_pixbuf == NULL)
                 return FALSE;
 
-        update_cursor (area, event->x, event->y);
+        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);
+               // XXX
+        /* gtk_widget_queue_draw_area (GTK_WIDGET (area), */
+        /*                             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;
+        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;
@@ -609,18 +619,22 @@ cc_crop_area_motion_notify_event (GtkWidget      *widget,
         area->crop.height = bottom - top + 1;
 
         crop_to_widget (area, &damage);
-        gtk_widget_queue_draw_area (widget,
-                                    damage.x - 4, damage.y - 4,
-                                    damage.width + 6, damage.height + 6);
+               // 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_press_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);
+        CcCropArea *area = CC_CROP_AREA (user_data);
         GdkRectangle crop;
 
         if (area->browse_pixbuf == NULL)
@@ -628,22 +642,26 @@ cc_crop_area_button_press_event (GtkWidget      *widget,
 
         crop_to_widget (area, &crop);
 
-        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);
+        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 gboolean
-cc_crop_area_button_release_event (GtkWidget      *widget,
-                                   GdkEventButton *event)
+on_button_released (GtkGestureClick *gesture,
+                    int n_press,
+                    double x,
+                    double y,
+                    gpointer user_data)
 {
-        CcCropArea *area = CC_CROP_AREA (widget);
+        CcCropArea *area = CC_CROP_AREA (user_data);
         GdkRectangle crop;
 
         if (area->browse_pixbuf == NULL)
@@ -655,11 +673,12 @@ cc_crop_area_button_release_event (GtkWidget      *widget,
         area->last_press_y = -1;
         area->active_region = OUTSIDE;
 
-        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
@@ -693,21 +712,29 @@ 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;
 }
 
 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);
+        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 (gesture, "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;
@@ -775,7 +802,8 @@ cc_crop_area_set_picture (CcCropArea *area,
         area->image.width = 0;
         area->image.height = 0;
 
-        gtk_widget_queue_draw (GTK_WIDGET (area));
+               // XXX
+        /* gtk_widget_queue_draw (GTK_WIDGET (area)); */
 }
 
 void
@@ -804,4 +832,3 @@ cc_crop_area_set_constrain_aspect (CcCropArea *area,
                 area->aspect = -1;
         }
 }
-
diff --git a/src/contacts-accounts-list.vala b/src/contacts-accounts-list.vala
index 9690e917..a9842c37 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,55 @@ 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);
       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);
+
+      var checkmark = new Gtk.Image.from_icon_name ("object-select-symbolic");
       checkmark.set ("margin-end", 6,
                      "valign", Gtk.Align.CENTER,
                      "halign", Gtk.Align.END,
                      "vexpand", true,
                      "hexpand", true);
-      row.add (checkmark);
+      row.set_child (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);
       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;
+      local_row.set_child (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..91b7625e 100644
--- a/src/contacts-addressbook-dialog.vala
+++ b/src/contacts-addressbook-dialog.vala
@@ -32,35 +32,36 @@ public class Contacts.AddressbookDialog : Gtk.Dialog {
                  _("Cancel"), Gtk.ResponseType.CANCEL);
 
     var content_area = get_content_area () as Gtk.Box;
-    content_area.border_width = 0;
+    // content_area.border_width = 0; XXX
 
     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);
+    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 +76,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..74cfbafd 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,24 @@ 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);
+    this.window = win;
 
     show_contact_list ();
   }
@@ -244,7 +245,7 @@ public class Contacts.App : Gtk.Application {
     this.contacts_store = new Store ();
     base.startup ();
 
-    Hdy.init ();
+    Adw.init ();
 
     load_styling ();
     create_actions ();
@@ -261,9 +262,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..5fe10160 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);
@@ -66,8 +72,6 @@ private class Contacts.Thumbnail : Gtk.FlowBoxChild {
 public class Contacts.AvatarSelector : Gtk.Window {
   const string AVATAR_BUTTON_CSS_NAME = "avatar-button";
 
-  // This will provide the default thumbnails
-  private Gnome.DesktopThumbnailFactory thumbnail_factory;
   private Individual individual;
 
   [GtkChild]
@@ -82,15 +86,14 @@ public class Contacts.AvatarSelector : Gtk.Window {
 
   public AvatarSelector (Individual? individual, Gtk.Window? window = null) {
     Object (transient_for: window);
-    this.thumbnail_factory = new Gnome.DesktopThumbnailFactory (Gnome.ThumbnailSize.NORMAL);
     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);
+    // XXX
+    // get_class ().add_binding (Gdk.Key.Escape, 0,
+    //                           (dialog, variant) => {
+    //                             this.close();
+    //                           },
+    //                           null);
 
     update_thumbnail_grid ();
 
@@ -121,11 +124,6 @@ public class Contacts.AvatarSelector : Gtk.Window {
     base.close ();
   }
 
-  [GtkCallback]
-  public bool on_delete_event () {
-    return hide_on_delete ();
-  }
-
   private Gdk.Pixbuf scale_pixbuf_for_avatar_use (Gdk.Pixbuf pixbuf) {
     int w = pixbuf.get_width ();
     int h = pixbuf.get_height ();
@@ -156,13 +154,13 @@ public class Contacts.AvatarSelector : Gtk.Window {
         } 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 +168,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,19 +176,18 @@ 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) => {
+    var dialog = new CropCheeseDialog.for_cheese (get_root() as Gtk.Window);
+    dialog.picture_selected.connect ((pix) => {
       selected_pixbuf (scale_pixbuf_for_avatar_use (pix));
       this.close ();
     });
+    dialog.show();
   }
 
   [GtkCallback]
@@ -213,88 +210,46 @@ 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,
+                                             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,
+            var dialog = new CropCheeseDialog.for_crop (get_root () as Gtk.Window,
                                                         pixbuf);
             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 ();
   }
-
-  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..efb9b719 100644
--- a/src/contacts-contact-sheet.vala
+++ b/src/contacts-contact-sheet.vala
@@ -63,7 +63,7 @@ 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);
+    var button = new Gtk.Button.from_icon_name (icon);
     button.set_halign (Gtk.Align.END);
     button.get_style_context ().add_class ("flatten");
 
@@ -84,7 +84,7 @@ public class Contacts.ContactSheet : Gtk.Grid {
     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.wrap = true;
     value_label.xalign = 0.0f;
     value_label.set_halign (Gtk.Align.START);
     value_label.set_ellipsize (Pango.EllipsizeMode.END);
@@ -94,12 +94,12 @@ public class Contacts.ContactSheet : Gtk.Grid {
 
     if (btn1 != null || btn2 !=null) {
       var value_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12);
-      value_box.pack_start (value_label, false, false, 0);
+      value_box.append (value_label);
 
       if (btn1 != null)
-        value_box.pack_end (btn1, false, false, 0);
+        value_box.append (btn1);
       if (btn2 != null)
-        value_box.pack_end (btn2, false, false, 0);
+        value_box.append (btn2);
       this.attach (value_box, 1, this.last_row, 1, 1);
     } else {
       this.attach (value_label, 1, this.last_row, 1, 1);
@@ -109,7 +109,14 @@ public class Contacts.ContactSheet : Gtk.Grid {
 
   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 +148,6 @@ public class Contacts.ContactSheet : Gtk.Grid {
         this.last_row--;
       }
     }
-
-    show_all ();
   }
 
   private void update_name_label (Gtk.Label name_label) {
@@ -266,14 +271,14 @@ public class Contacts.ContactSheet : Gtk.Grid {
       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;
+          unowned var window = button.get_root () as MainWindow;
           if (window == null)
             return;
 
           try {
-            Gtk.show_uri_on_window (window,
-                                    fallback_to_https (url.value),
-                                    Gdk.CURRENT_TIME);
+            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);
 
diff --git a/src/contacts-crop-cheese-dialog.vala b/src/contacts-crop-cheese-dialog.vala
index 1904d8a4..bb4f678d 100644
--- a/src/contacts-crop-cheese-dialog.vala
+++ b/src/contacts-crop-cheese-dialog.vala
@@ -33,6 +33,10 @@ public class Contacts.CropCheeseDialog : Gtk.Window {
 
   public signal void picture_selected (Gdk.Pixbuf buf);
 
+  construct {
+    this.close_request.connect(on_close_request);
+  }
+
   public CropCheeseDialog.for_cheese (Gtk.Window parent) {
 #if HAVE_CHEESE
     setup_widget (parent);
@@ -97,8 +101,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 +109,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..1f5da079 100644
--- a/src/contacts-editor-persona.vala
+++ b/src/contacts-editor-persona.vala
@@ -45,11 +45,11 @@ public class Contacts.EditorPersona : Gtk.Box {
 
   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);
+    append (this.content);
   }
 
   public EditorPersona (Persona persona, IndividualAggregator aggregator) {
@@ -66,7 +66,7 @@ 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
@@ -80,18 +80,17 @@ public class Contacts.EditorPersona : Gtk.Box {
           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 ();
       }
     });
-    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);
+    Gtk.Image show_all = new Gtk.Image.from_icon_name ("view-more-symbolic");
+    // show_all.margin = 12; XXX
+    show_all_row.set_child (show_all);
+    this.content.append (show_all_row);
   }
 
   private void connect_row (EditorPropertyRow row) {
@@ -117,8 +116,8 @@ 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 = get_first_child (); child != null; child = child.get_next_sibling ()) {
+      var prop = (child as EditorPropertyRow);
       if (prop != null && !prop.is_removed && prop.is_empty && prop.ptype == type) {
         count++;
       }
@@ -127,12 +126,13 @@ public class Contacts.EditorPersona : Gtk.Box {
   }
 
   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 ();
-        }
+    for (unowned Gtk.Widget? child = 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 +147,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..edcd0c24 100644
--- a/src/contacts-editor-property.vala
+++ b/src/contacts-editor-property.vala
@@ -19,41 +19,39 @@
 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 {
+    add_css_class ("birthday-editor");
 
-  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);
@@ -72,18 +70,20 @@ 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);
+    box.append (grid);
+
+    // box.margin = 12; XXX
 
     var content = this.get_content_area ();
     content.set_valign (Gtk.Align.CENTER);
-    content.add (box);
+    content.append (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 +95,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 +147,14 @@ public class Contacts.AddressEditor : Gtk.Box {
 
   public signal void changed ();
 
-  public AddressEditor (PostalAddressFieldDetails details) {
+  construct {
     set_hexpand (true);
     set_orientation (Gtk.Orientation.VERTICAL);
 
+    add_css_class ("address-editor");
+  }
+
+  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);
@@ -154,7 +167,7 @@ public class Contacts.AddressEditor : Gtk.Box {
         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];
@@ -174,9 +187,10 @@ public class Contacts.AddressEditor : Gtk.Box {
     return true;
   }
 
-  public override void grab_focus () {
-    entries[0].grab_focus ();
-  }
+  //XXX)
+  // public override void grab_focus () {
+  //   entries[0].grab_focus ();
+  // }
 }
 
 public class Contacts.EditorPropertyRow : Gtk.ListBoxRow {
@@ -197,15 +211,15 @@ public class Contacts.EditorPropertyRow : Gtk.ListBoxRow {
     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");
+    // box.margin = 12; XXX
+    this.revealer.set_child (box);
+    this.set_child (this.revealer);
+    this.add_css_class ("editor-property-row");
     this.revealer.bind_property ("reveal-child", this, "is-removed", BindingFlags.INVERT_BOOLEAN);
   }
 
@@ -232,9 +246,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 +256,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 +265,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 +288,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 +309,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 +331,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 +348,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 +518,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 +543,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 +583,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 +597,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 +634,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..e64a29ff 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,71 @@ 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);
-  }
+  // // ...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);
+  // }
 
-  // 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);
-  });
+  // // 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);
+  // });
 
-  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));
-  }
-}
-
-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_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));
+//   }
+// }
+
+// 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 +189,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..96245680 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,12 @@ 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;
+    this.revealer.reveal_child = true;
 
     Timeout.add_seconds (DEFAULT_KEEPALIVE, () => {
         dismiss ();
@@ -60,18 +64,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..7b914b36 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]
@@ -43,7 +44,7 @@ public class Contacts.LinkSuggestionGrid : Gtk.Grid {
 
     var image_frame = new Avatar (AVATAR_SIZE, individual);
     image_frame.hexpand = false;
-    image_frame.margin = 12;
+    // image_frame.margin = 12; XXX
     image_frame.show ();
     attach (image_frame, 0, 0, 1, 2);
 
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..8c62b701 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) {
@@ -112,8 +113,8 @@ public class Contacts.ListPane : Gtk.Frame {
     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;
-  }
+  /* Limiting width hack XXX */
+  // 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..45876e28 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-surname", null, "b", "false", sort_on_surname_state_change }, // XXX Fix
   };
 
   [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;
   [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,25 +84,18 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
   }
 
   construct {
-    SimpleActionGroup actions = new SimpleActionGroup ();
-    actions.add_action_entries (action_entries, this);
-    insert_action_group ("window", actions);
+    this.actions.add_action_entries (ACTION_ENTRIES, this);
+    insert_action_group ("window", this.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 ();
+    var sort_action = (SimpleAction) this.actions.lookup_action ("sort-on-surname");
+    sort_action.set_state (new Variant.boolean (this.settings.sort_on_surname));
 
     this.notify["state"].connect (on_ui_state_changed);
 
     create_contact_pane ();
     connect_button_signals ();
     restore_window_state ();
+    this.close_request.connect(on_close_request);
 
     if (Config.PROFILE == "development")
         get_style_context ().add_class ("devel");
@@ -122,60 +111,30 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
     );
   }
 
-  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;
+  private void sort_on_surname_state_change (SimpleAction action,
+                                             GLib.Variant variant) {
+    this.settings.sort_on_surname = variant.get_boolean ();
   }
 
   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 +155,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)
@@ -228,7 +186,7 @@ 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
@@ -270,10 +228,6 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
     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 +235,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 +254,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 () {
@@ -351,9 +305,9 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
     this.list_pane.scroll_to_contact ();
 
     if (this.contact_pane.individual != null) {
-      this.right_header.title = this.contact_pane.individual.display_name;
+      update_header_titles (null, this.contact_pane.individual.display_name);
     } else {
-      this.right_header.title = "";
+      update_header_titles (null, "");
     }
   }
 
@@ -377,10 +331,10 @@ public class Contacts.MainWindow : Hdy.ApplicationWindow {
       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;
+                                                          : _("Mark as favorite");
+      update_header_titles (null, i.display_name);
     } else {
-      this.right_header.title = "";
+      update_header_titles (null, "");
     }
   }
 
@@ -393,7 +347,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 +377,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 ();
@@ -452,46 +420,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 +569,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..f4404b36 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -24,7 +24,7 @@ contacts_vala_args = [
 
 contacts_c_args = [
   '-include', 'config.h',
-  '-DGNOME_DESKTOP_USE_UNSTABLE_API',
+  # '-DGNOME_DESKTOP_USE_UNSTABLE_API',
   '-DLOCALEDIR="@0@"'.format(locale_dir),
 ]
 
@@ -34,13 +34,13 @@ contacts_deps = [
   gee,
   gio_unix,
   glib,
-  gnome_desktop,
+  # gnome_desktop,
   goa,
-  gtk,
+  gtk4_dep,
+  libadwaita_dep,
   libebook,
   libedataserver,
-  libedataserverui,
-  libhandy,
+  # libedataserverui,
   math,
 ]
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]