From 9a11f29b8751341fb2965e4efd5586b6e8d9af92 Mon Sep 17 00:00:00 2001
From: Teemu Ikonen <tpikonen@mailbox.org>
Date: Fri, 10 Nov 2023 17:43:41 +0200
Subject: [PATCH] Port file chooser to phones

By Adrien Plazas
---
 gtk/gtkfilechooserdialog.c     |   2 +-
 gtk/gtkfilechooserwidget.c     | 165 +++++++++++++++++++++++++++------
 gtk/gtkplacesview.c            |  24 +++++
 gtk/ui/gtkfilechooserwidget.ui |  87 ++++++++++++-----
 gtk/ui/gtkplacesview.ui        |   3 +-
 5 files changed, 226 insertions(+), 55 deletions(-)

diff --git a/gtk/gtkfilechooserdialog.c b/gtk/gtkfilechooserdialog.c
index db1d8f6de7..cf4229afa3 100644
--- a/gtk/gtkfilechooserdialog.c
+++ b/gtk/gtkfilechooserdialog.c
@@ -532,7 +532,7 @@ setup_save_entry (GtkFileChooserDialog *dialog)
   need_entry = action == GTK_FILE_CHOOSER_ACTION_SAVE ||
                action == GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
 
-  if (need_entry && !dialog->priv->has_entry)
+  if (need_entry && !dialog->priv->has_entry && FALSE)
     {
       GtkWidget *box;
       GtkWidget *label;
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index 0496fd2f35..32a32aac62 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -31,6 +31,7 @@
 #include "gtkcheckmenuitem.h"
 #include "gtkclipboard.h"
 #include "gtkcomboboxtext.h"
+#include "gtkcssprovider.h"
 #include "gtkdragsource.h"
 #include "gtkdragdest.h"
 #include "gtkentry.h"
@@ -80,6 +81,8 @@
 #include "gtkseparator.h"
 #include "gtkmodelbutton.h"
 #include "gtkgesturelongpress.h"
+#include "hdy-clamp-private.h"
+#include "hdy-flap-private.h"
 
 #include <cairo-gobject.h>
 
@@ -225,7 +228,8 @@ struct _GtkFileChooserWidgetPrivate {
   GtkWidget *save_widgets_table;
 
   /* The file browsing widgets */
-  GtkWidget *browse_widgets_hpaned;
+  GtkWidget *flap;
+  GtkWidget *browse_box;
   GtkWidget *browse_header_revealer;
   GtkWidget *browse_header_stack;
   GtkWidget *browse_files_stack;
@@ -379,6 +383,7 @@ struct _GtkFileChooserWidgetPrivate {
   guint create_folders : 1;
   guint auto_selecting_first_row : 1;
   guint browse_files_interaction_frozen : 1;
+  guint location_visible : 1;
 };
 
 #define MAX_LOADING_TIME 500
@@ -426,6 +431,7 @@ enum {
   MODEL_COL_TIME_TEXT,
   MODEL_COL_LOCATION_TEXT,
   MODEL_COL_ELLIPSIZE,
+  MODEL_COL_DISPLAY,
   MODEL_COL_NUM_COLUMNS
 };
 
@@ -445,7 +451,8 @@ enum {
         G_TYPE_STRING,            /* MODEL_COL_DATE_TEXT */     \
         G_TYPE_STRING,            /* MODEL_COL_TIME_TEXT */     \
         G_TYPE_STRING,            /* MODEL_COL_LOCATION_TEXT */ \
-        PANGO_TYPE_ELLIPSIZE_MODE /* MODEL_COL_ELLIPSIZE */
+        PANGO_TYPE_ELLIPSIZE_MODE, /* MODEL_COL_ELLIPSIZE */    \
+        G_TYPE_STRING             /* MODEL_COL_DISPLAY */
 
 #define DEFAULT_RECENT_FILES_LIMIT 50
 
@@ -1289,6 +1296,9 @@ places_sidebar_open_location_cb (GtkPlacesSidebar     *sidebar,
     operation_mode_set (impl, OPERATION_MODE_RECENT);
   else
     change_folder_and_display_error (impl, location, clear_entry);
+
+  if (gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap)))
+    gtk_hdy_flap_set_reveal_flap (GTK_HDY_FLAP (priv->flap), FALSE);
 }
 
 /* Callback used when the places sidebar needs us to display an error message */
@@ -1846,6 +1856,24 @@ open_folder_cb (GSimpleAction *action,
 }
 G_GNUC_END_IGNORE_DEPRECATIONS
 
+static void
+update_show_columns (GtkFileChooserWidget *impl)
+{
+  GtkFileChooserWidgetPrivate *priv = impl->priv;
+  gboolean folded = gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap));
+
+  gtk_tree_view_column_set_visible (priv->list_size_column,
+                                    priv->show_size_column && !folded);
+  gtk_tree_view_column_set_visible (priv->list_type_column,
+                                    priv->show_type_column && !folded);
+  gtk_tree_view_column_set_visible (priv->list_time_column, !folded);
+  g_object_set (priv->list_time_renderer,
+                "visible", priv->show_time && !folded,
+                NULL);
+
+  clear_model_cache (impl, MODEL_COL_DISPLAY);
+}
+
 /* callback used when the "Show Hidden Files" menu item is toggled */
 static void
 change_show_hidden_state (GSimpleAction *action,
@@ -1870,8 +1898,7 @@ change_show_size_state (GSimpleAction *action,
   g_simple_action_set_state (action, state);
   priv->show_size_column = g_variant_get_boolean (state);
 
-  gtk_tree_view_column_set_visible (priv->list_size_column,
-                                    priv->show_size_column);
+  update_show_columns (impl);
 }
 
 /* Callback used when the "Show Type Column" menu item is toggled */
@@ -1886,8 +1913,8 @@ change_show_type_state (GSimpleAction *action,
   g_simple_action_set_state (action, state);
   priv->show_type_column = g_variant_get_boolean (state);
 
-  gtk_tree_view_column_set_visible (priv->list_type_column,
-                                    priv->show_type_column);
+  update_show_columns (impl);
+
 }
 
 static void
@@ -1952,11 +1979,9 @@ update_time_renderer_visible (GtkFileChooserWidget *impl)
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
 
-  g_object_set (priv->list_time_renderer,
-                "visible", priv->show_time,
-                NULL);
   clear_model_cache (impl, MODEL_COL_DATE_TEXT);
   clear_model_cache (impl, MODEL_COL_TIME_TEXT);
+  update_show_columns (impl);
   gtk_widget_queue_draw (priv->browse_files_tree_view);
 }
 
@@ -2637,7 +2662,7 @@ location_entry_setup (GtkFileChooserWidget *impl)
   _gtk_file_chooser_entry_set_action (GTK_FILE_CHOOSER_ENTRY (priv->location_entry), priv->action);
   _gtk_file_chooser_entry_set_file_filter (GTK_FILE_CHOOSER_ENTRY (priv->location_entry),
                                            priv->current_filter);
-  gtk_entry_set_width_chars (GTK_ENTRY (priv->location_entry), 45);
+
   gtk_entry_set_activates_default (GTK_ENTRY (priv->location_entry), TRUE);
 }
 
@@ -2684,6 +2709,8 @@ save_widgets_create (GtkFileChooserWidget *impl)
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
   GtkWidget *vbox;
+  GtkWidget *clamp;
+  GtkWidget *separator;
   GtkWidget *widget;
 
   if (priv->save_widgets != NULL ||
@@ -2705,14 +2732,19 @@ save_widgets_create (GtkFileChooserWidget *impl)
       return;
     }
 
-  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
-  gtk_style_context_add_class (gtk_widget_get_style_context (vbox), "search-bar");
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
 
-  gtk_container_set_border_width (GTK_CONTAINER (vbox), 0);
+  clamp = gtk_hdy_clamp_new ();
+  gtk_widget_show (clamp);
+  gtk_container_add (GTK_CONTAINER (vbox), clamp);
+
+  separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+  gtk_widget_show (separator);
+  gtk_container_add (GTK_CONTAINER (vbox), separator);
 
   priv->save_widgets_table = gtk_grid_new ();
-  gtk_container_set_border_width (GTK_CONTAINER (priv->save_widgets_table), 10);
-  gtk_box_pack_start (GTK_BOX (vbox), priv->save_widgets_table, FALSE, FALSE, 0);
+  gtk_container_set_border_width (GTK_CONTAINER (priv->save_widgets_table), 6);
+  gtk_container_add (GTK_CONTAINER (clamp), priv->save_widgets_table);
   gtk_widget_show (priv->save_widgets_table);
   gtk_grid_set_row_spacing (GTK_GRID (priv->save_widgets_table), 12);
   gtk_grid_set_column_spacing (GTK_GRID (priv->save_widgets_table), 12);
@@ -2878,6 +2910,9 @@ places_sidebar_show_other_locations_with_flags_cb (GtkPlacesSidebar     *sidebar
   update_preview_widget_visibility (impl);
 
   operation_mode_set (impl, OPERATION_MODE_OTHER_LOCATIONS);
+
+  if (gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap)))
+    gtk_hdy_flap_set_reveal_flap (GTK_HDY_FLAP (priv->flap), FALSE);
 }
 
 static void
@@ -2940,7 +2975,8 @@ update_extra_and_filters (GtkFileChooserWidget *impl)
 {
   gtk_widget_set_visible (impl->priv->extra_and_filters,
                           gtk_widget_get_visible (impl->priv->extra_align) ||
-                          gtk_widget_get_visible (impl->priv->filter_combo_hbox));
+                          gtk_widget_get_visible (impl->priv->filter_combo_hbox) ||
+                          gtk_hdy_flap_get_folded (GTK_HDY_FLAP (impl->priv->flap)));
 }
 
 /* Sets the extra_widget by packing it in the appropriate place */
@@ -3755,7 +3791,7 @@ change_icon_theme (GtkFileChooserWidget *impl)
 
   profile_start ("start", NULL);
 
-  if (gtk_icon_size_lookup (GTK_ICON_SIZE_MENU, &width, &height))
+  if (gtk_icon_size_lookup (GTK_ICON_SIZE_DND, &width, &height))
     priv->icon_size = MAX (width, height);
   else
     priv->icon_size = FALLBACK_ICON_SIZE;
@@ -3888,7 +3924,6 @@ settings_load (GtkFileChooserWidget *impl)
   gint sort_column;
   GtkSortType sort_order;
   StartupMode startup_mode;
-  gint sidebar_width;
   GSettings *settings;
 
   settings = _gtk_file_chooser_get_settings_for_widget (GTK_WIDGET (impl));
@@ -3898,7 +3933,6 @@ settings_load (GtkFileChooserWidget *impl)
   show_type_column = g_settings_get_boolean (settings, SETTINGS_KEY_SHOW_TYPE_COLUMN);
   sort_column = g_settings_get_enum (settings, SETTINGS_KEY_SORT_COLUMN);
   sort_order = g_settings_get_enum (settings, SETTINGS_KEY_SORT_ORDER);
-  sidebar_width = g_settings_get_int (settings, SETTINGS_KEY_SIDEBAR_WIDTH);
   startup_mode = g_settings_get_enum (settings, SETTINGS_KEY_STARTUP_MODE);
   sort_directories_first = g_settings_get_boolean (settings, SETTINGS_KEY_SORT_DIRECTORIES_FIRST);
   date_format = g_settings_get_enum (settings, SETTINGS_KEY_DATE_FORMAT);
@@ -3907,9 +3941,8 @@ settings_load (GtkFileChooserWidget *impl)
   if (!priv->show_hidden_set)
     set_show_hidden (impl, show_hidden);
   priv->show_size_column = show_size_column;
-  gtk_tree_view_column_set_visible (priv->list_size_column, show_size_column);
   priv->show_type_column = show_type_column;
-  gtk_tree_view_column_set_visible (priv->list_type_column, show_type_column);
+  update_show_columns (impl);
 
   priv->sort_column = sort_column;
   priv->sort_order = sort_order;
@@ -3924,7 +3957,6 @@ settings_load (GtkFileChooserWidget *impl)
    */
 
   update_time_renderer_visible (impl);
-  gtk_paned_set_position (GTK_PANED (priv->browse_widgets_hpaned), sidebar_width);
 }
 
 static void
@@ -3945,8 +3977,6 @@ settings_save (GtkFileChooserWidget *impl)
   g_settings_set_boolean (settings, SETTINGS_KEY_SORT_DIRECTORIES_FIRST, priv->sort_directories_first);
   g_settings_set_enum (settings, SETTINGS_KEY_SORT_COLUMN, priv->sort_column);
   g_settings_set_enum (settings, SETTINGS_KEY_SORT_ORDER, priv->sort_order);
-  g_settings_set_int (settings, SETTINGS_KEY_SIDEBAR_WIDTH,
-                      gtk_paned_get_position (GTK_PANED (priv->browse_widgets_hpaned)));
   g_settings_set_enum (settings, SETTINGS_KEY_DATE_FORMAT, priv->show_time ? DATE_FORMAT_WITH_TIME : DATE_FORMAT_REGULAR);
   g_settings_set_enum (settings, SETTINGS_KEY_TYPE_FORMAT, priv->type_format);
 
@@ -4416,13 +4446,18 @@ update_columns (GtkFileChooserWidget *impl,
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
   gboolean need_resize = FALSE;
+  gboolean folded = gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap));
+
+  priv->location_visible = location_visible;
 
-  if (gtk_tree_view_column_get_visible (priv->list_location_column) != location_visible)
+  if (gtk_tree_view_column_get_visible (priv->list_location_column) != (location_visible && !folded))
     {
-      gtk_tree_view_column_set_visible (priv->list_location_column, location_visible);
+      gtk_tree_view_column_set_visible (priv->list_location_column, location_visible && !folded);
       need_resize = TRUE;
     }
 
+  clear_model_cache (impl, MODEL_COL_DISPLAY);
+
   if (g_strcmp0 (gtk_tree_view_column_get_title (priv->list_time_column), time_title) != 0)
     {
       gtk_tree_view_column_set_title (priv->list_time_column, time_title);
@@ -5303,6 +5338,47 @@ file_system_model_set (GtkFileSystemModel *model,
         g_object_unref (home_location);
       }
       break;
+    case MODEL_COL_DISPLAY:
+      {
+        gchar *metadata_str;
+        gchar* metadata[7];
+        int i = 0;
+
+        #define APPEND_COLUMN(column) {\
+          GValue val = { 0, }; \
+          gchar *ret; \
+          g_value_init (&val, G_TYPE_STRING); \
+          file_system_model_set (model, file, info, column, &val, data); \
+          ret = g_value_get_string (&val); \
+          if (ret && *ret) \
+            metadata[i++] = g_markup_escape_text (ret, -1); \
+          g_value_unset (&val); \
+        }
+
+        APPEND_COLUMN(MODEL_COL_NAME)
+        APPEND_COLUMN(MODEL_COL_DATE_TEXT)
+
+        if (priv->show_time)
+          APPEND_COLUMN(MODEL_COL_TIME_TEXT)
+
+        if (priv->show_type_column)
+          APPEND_COLUMN(MODEL_COL_TYPE)
+
+        if (priv->show_size_column)
+          APPEND_COLUMN(MODEL_COL_SIZE_TEXT)
+
+        if (priv->operation_mode == OPERATION_MODE_RECENT)
+          APPEND_COLUMN(MODEL_COL_LOCATION_TEXT)
+
+        metadata[i] = NULL;
+        metadata_str = g_strjoinv (" · ", &metadata[1]);
+        g_value_take_string (value, g_strdup_printf ("%s\n<span size=\"smaller\" alpha=\"55%%\">%s</span>", metadata[0], metadata_str));
+
+        while (i > 0)
+          g_free (metadata[--i]);
+        g_free (metadata_str);
+      }
+      break;
     default:
       g_assert_not_reached ();
       break;
@@ -8106,6 +8182,7 @@ static void
 update_cell_renderer_attributes (GtkFileChooserWidget *impl)
 {
   GtkFileChooserWidgetPrivate *priv = impl->priv;
+  gboolean folded = gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap));
 
   gtk_tree_view_column_set_attributes (priv->list_name_column,
                                        priv->list_pixbuf_renderer,
@@ -8114,7 +8191,8 @@ update_cell_renderer_attributes (GtkFileChooserWidget *impl)
                                        NULL);
   gtk_tree_view_column_set_attributes (priv->list_name_column,
                                        priv->list_name_renderer,
-                                       "text", MODEL_COL_NAME,
+                                       folded ? "markup" : "text",
+                                       folded ? MODEL_COL_DISPLAY : MODEL_COL_NAME,
                                        "ellipsize", MODEL_COL_ELLIPSIZE,
                                        "sensitive", MODEL_COL_IS_SENSITIVE,
                                        NULL);
@@ -8152,6 +8230,20 @@ update_cell_renderer_attributes (GtkFileChooserWidget *impl)
   update_time_renderer_visible (impl);
 }
 
+static void
+flap_folded_cb (GtkFileChooserWidget *impl)
+{
+  GtkFileChooserWidgetPrivate *priv = impl->priv;
+  gboolean folded = gtk_hdy_flap_get_folded (GTK_HDY_FLAP (priv->flap));
+
+  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (priv->browse_files_tree_view), !folded);
+
+  update_show_columns (impl);
+  update_cell_renderer_attributes (impl);
+  update_extra_and_filters (impl);
+  update_columns (impl, priv->location_visible, gtk_tree_view_column_get_title (priv->list_time_column));
+}
+
 static void
 location_set_user_text (GtkFileChooserWidget *impl,
                         const gchar          *path)
@@ -8688,12 +8780,13 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
                                                "/org/gtk/libgtk/ui/gtkfilechooserwidget.ui");
 
   /* A *lot* of widgets that we need to handle .... */
-  gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_widgets_hpaned);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_stack);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, places_sidebar);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, places_view);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_tree_view);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_files_swin);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, flap);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_box);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_header_revealer);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_header_stack);
   gtk_widget_class_bind_template_child_private (widget_class, GtkFileChooserWidget, browse_new_folder_button);
@@ -8755,6 +8848,7 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
   gtk_widget_class_bind_template_callback (widget_class, rename_file_name_changed);
   gtk_widget_class_bind_template_callback (widget_class, rename_file_rename_clicked);
   gtk_widget_class_bind_template_callback (widget_class, rename_file_end);
+  gtk_widget_class_bind_template_callback (widget_class, flap_folded_cb);
 
   gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_FILE_CHOOSER_WIDGET_ACCESSIBLE);
   gtk_widget_class_set_css_name (widget_class, "filechooser");
@@ -8831,6 +8925,19 @@ post_process_ui (GtkFileChooserWidget *impl)
   gtk_popover_set_relative_to (GTK_POPOVER (impl->priv->rename_file_popover), impl->priv->browse_files_tree_view);
 
   add_actions (impl);
+
+  {
+    GtkCssProvider *provider;
+
+    provider = gtk_css_provider_new ();
+    gtk_css_provider_load_from_data (provider, "placessidebar { border: none; }", -1, NULL);
+
+    gtk_style_context_add_provider (gtk_widget_get_style_context (impl->priv->places_sidebar),
+                                    GTK_STYLE_PROVIDER (provider),
+                                    GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+  }
+
+  update_extra_and_filters (impl);
 }
 
 void
@@ -8888,6 +8995,8 @@ gtk_file_chooser_widget_init (GtkFileChooserWidget *impl)
   /* Ensure GTK+ private types used by the template
    * definition before calling gtk_widget_init_template()
    */
+  g_type_ensure (GTK_TYPE_HDY_CLAMP);
+  g_type_ensure (GTK_TYPE_HDY_FLAP);
   g_type_ensure (GTK_TYPE_PATH_BAR);
   g_type_ensure (GTK_TYPE_PLACES_VIEW);
 
diff --git a/gtk/gtkplacesview.c b/gtk/gtkplacesview.c
index 89f7acef2c..fd17820016 100644
--- a/gtk/gtkplacesview.c
+++ b/gtk/gtkplacesview.c
@@ -26,6 +26,7 @@
 #include "gtkmarshalers.h"
 #include "gtkplacesviewprivate.h"
 #include "gtkplacesviewrowprivate.h"
+#include "gtkprivate.h"
 #include "gtktypebuiltins.h"
 
 /**
@@ -94,6 +95,9 @@ struct _GtkPlacesViewPrivate
   guint                          fetching_networks : 1;
   guint                          loading : 1;
   guint                          destroyed : 1;
+
+  GtkWidget                     *connect_label;
+  GSettings                     *settings;
 };
 
 static void        mount_volume                                  (GtkPlacesView *view,
@@ -409,6 +413,8 @@ gtk_places_view_destroy (GtkWidget *widget)
   g_cancellable_cancel (priv->cancellable);
   g_cancellable_cancel (priv->networks_fetching_cancellable);
 
+  g_clear_object (&priv->settings);
+
   GTK_WIDGET_CLASS (gtk_places_view_parent_class)->destroy (widget);
 }
 
@@ -2211,6 +2217,14 @@ listbox_sort_func (GtkListBoxRow *row1,
   return retval;
 }
 
+static void
+update_connect_label (GtkPlacesView *self)
+{
+  GtkPlacesViewPrivate *priv = gtk_places_view_get_instance_private (self);
+
+  gtk_widget_set_visible (priv->connect_label, !_gtk_get_is_phone ());
+}
+
 static void
 gtk_places_view_constructed (GObject *object)
 {
@@ -2260,6 +2274,15 @@ gtk_places_view_constructed (GObject *object)
                             "volume-removed",
                             G_CALLBACK (update_places),
                             object);
+
+  priv->settings = _gtk_get_purism_settings ();
+
+  if (priv->settings)
+    g_signal_connect_object (priv->settings, "changed::is-phone",
+                             G_CALLBACK (update_connect_label), object,
+                             G_CONNECT_SWAPPED);
+
+  update_connect_label (GTK_PLACES_VIEW (object));
 }
 
 static void
@@ -2386,6 +2409,7 @@ gtk_places_view_class_init (GtkPlacesViewClass *klass)
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, stack);
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, server_adresses_popover);
   gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, available_protocols_grid);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkPlacesView, connect_label);
 
   gtk_widget_class_bind_template_callback (widget_class, on_address_entry_text_changed);
   gtk_widget_class_bind_template_callback (widget_class, on_address_entry_show_help_pressed);
diff --git a/gtk/ui/gtkfilechooserwidget.ui b/gtk/ui/gtkfilechooserwidget.ui
index 6e7c21dcc9..f72edd5de8 100644
--- a/gtk/ui/gtkfilechooserwidget.ui
+++ b/gtk/ui/gtkfilechooserwidget.ui
@@ -9,14 +9,20 @@
         <property name="visible">1</property>
         <property name="orientation">vertical</property>
         <child>
-          <object class="GtkPaned" id="browse_widgets_hpaned">
+          <object class="GtkHdyFlap" id="flap">
             <property name="visible">1</property>
-            <child>
+            <property name="swipe-to-open">0</property>
+            <property name="swipe-to-close" bind-source="flap" bind-property="folded" bind-flags="sync-create"/>
+            <signal name="notify::folded" handler="flap_folded_cb" swapped="yes"/>
+            <child type="flap">
               <object class="GtkPlacesSidebar" id="places_sidebar">
                 <property name="visible">1</property>
+                <property name="hexpand-set">1</property>
                 <property name="hscrollbar-policy">never</property>
                 <property name="local-only">1</property>
                 <property name="show-other-locations">1</property>
+                <property name="propagate-natural-width">1</property>
+                <property name="width-request">200</property>
                 <child internal-child="accessible">
                   <object class="AtkObject">
                     <property name="AtkObject::accessible-name" translatable="yes">Places</property>
@@ -29,13 +35,17 @@
                 <signal name="show-error-message" handler="places_sidebar_show_error_message_cb" swapped="no"/>
                 <signal name="show-other-locations-with-flags" handler="places_sidebar_show_other_locations_with_flags_cb" swapped="no"/>
               </object>
-              <packing>
-                <property name="resize">0</property>
-                <property name="shrink">0</property>
-              </packing>
+            </child>
+            <child type="separator">
+              <object class="GtkSeparator">
+                <property name="visible">1</property>
+                <style>
+                  <class name="sidebar"/>
+                </style>
+              </object>
             </child>
             <child>
-              <object class="GtkBox">
+              <object class="GtkBox" id="browse_box">
                 <property name="visible">1</property>
                 <property name="orientation">vertical</property>
                 <child>
@@ -110,6 +120,9 @@
                                 <property name="name">pathbar</property>
                               </packing>
                             </child>
+                            <child>
+                              <object class="GtkHdyClamp">
+                                <property name="visible">1</property>
                             <child>
                               <object class="GtkBox" id="location_entry_box">
                                 <property name="visible">1</property>
@@ -125,7 +138,12 @@
                               <packing>
                                 <property name="name">location</property>
                               </packing>
+                            </child>
+                              </object>
                             </child>
+                            <child>
+                              <object class="GtkHdyClamp">
+                                <property name="visible">1</property>
                             <child>
                               <object class="GtkBox" id="search_entry_box">
                                 <property name="visible">1</property>
@@ -137,10 +155,10 @@
                                     <property name="AtkObject::accessible-name" translatable="yes">Search Layer</property>
                                   </object>
                                 </child>
-                                <child type="center">
+                                <child>
                                   <object class="GtkSearchEntry" id="search_entry">
                                     <property name="visible">1</property>
-                                    <property name="width-chars">45</property>
+                                    <property name="hexpand">True</property>
                                     <signal name="search-changed" handler="search_entry_activate_cb" swapped="yes"/>
                                     <signal name="stop-search" handler="search_entry_stop_cb" swapped="yes"/>
                                   </object>
@@ -158,6 +176,8 @@
                                 <property name="name">search</property>
                               </packing>
                             </child>
+                              </object>
+                            </child>
                           </object>
                           <packing>
                             <property name="fill">0</property>
@@ -171,9 +191,15 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkBox" id="list_and_preview_box">
+                  <object class="GtkHdyFlap" id="list_and_preview_box">
                     <property name="visible">1</property>
-                    <property name="spacing">12</property>
+                    <property name="flap-position">end</property>
+                    <property name="fold-policy">never</property>
+                    <property name="modal">False</property>
+                    <property name="swipe-to-open">False</property>
+                    <property name="swipe-to-close">False</property>
+                    <property name="transition-type">slide</property>
+                    <property name="reveal-flap" bind-source="flap" bind-property="folded" bind-flags="invert-boolean|sync-create"/>
                     <child>
                       <object class="GtkStack" id="browse_files_stack">
                         <property name="visible">1</property>
@@ -223,6 +249,7 @@
                                         <child>
                                           <object class="GtkCellRendererPixbuf" id="list_pixbuf_renderer">
                                             <property name="xpad">6</property>
+                                            <property name="stock-size">5</property>
                                           </object>
                                         </child>
                                         <child>
@@ -351,6 +378,8 @@
                               <object class="GtkLabel">
                                 <property name="visible">1</property>
                                 <property name="label" translatable="yes">No Results Found</property>
+                                <property name="justify">center</property>
+                                <property name="wrap">True</property>
                                 <attributes>
                                   <attribute name="weight" value="bold"/>
                                   <attribute name="scale" value="1.44"/>
@@ -365,6 +394,8 @@
                               <object class="GtkLabel">
                                 <property name="visible">1</property>
                                 <property name="label" translatable="yes">Try a different search</property>
+                                <property name="justify">center</property>
+                                <property name="wrap">True</property>
                                 <style>
                                   <class name="dim-label"/>
                                 </style>
@@ -380,19 +411,15 @@
                           </packing>
                         </child>
                       </object>
-                      <packing>
-                        <property name="expand">1</property>
-                      </packing>
                     </child>
-                    <child>
+                    <child type="flap">
                       <object class="GtkBox" id="preview_box">
                         <property name="orientation">vertical</property>
                         <property name="spacing">12</property>
+                        <style>
+                          <class name="background"/>
+                        </style>
                       </object>
-                      <packing>
-                        <property name="fill">0</property>
-                        <property name="position">1</property>
-                      </packing>
                     </child>
                   </object>
                   <packing>
@@ -401,9 +428,6 @@
                   </packing>
                 </child>
               </object>
-              <packing>
-                <property name="shrink">0</property>
-              </packing>
             </child>
           </object>
           <packing>
@@ -419,15 +443,30 @@
     <child>
       <object class="GtkActionBar" id="extra_and_filters">
         <property name="no-show-all">1</property>
+        <child>
+          <object class="GtkToggleButton" id="reveal_sidebar_button">
+            <property name="visible" bind-source="flap" bind-property="folded" bind-flags="sync-create"/>
+            <property name="active" bind-source="flap" bind-property="reveal-flap" bind-flags="sync-create|bidirectional"/>
+            <property name="tooltip-text" translatable="yes">Show locations</property>
+            <property name="use-underline">1</property>
+            <property name="can-default">1</property>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">1</property>
+                <property name="icon-name">view-sidebar-symbolic</property>
+              </object>
+            </child>
+          </object>
+        </child>
         <child>
           <object class="GtkBox" id="extra_align">
-            <property name="visible">1</property>
+            <property name="no-show-all">1</property>
             <property name="spacing">12</property>
           </object>
         </child>
         <child>
           <object class="GtkBox" id="filter_combo_hbox">
-            <property name="visible">1</property>
+            <property name="no-show-all">1</property>
             <property name="spacing">12</property>
             <child>
               <object class="GtkComboBoxText" id="filter_combo">
diff --git a/gtk/ui/gtkplacesview.ui b/gtk/ui/gtkplacesview.ui
index 5ede5900ba..d68aab0aa9 100644
--- a/gtk/ui/gtkplacesview.ui
+++ b/gtk/ui/gtkplacesview.ui
@@ -300,7 +300,7 @@
           <class name="background"/>
         </style>
         <child>
-          <object class="GtkLabel">
+          <object class="GtkLabel" id="connect_label">
             <property name="visible">1</property>
             <property name="hexpand">1</property>
             <property name="xalign">0</property>
@@ -336,7 +336,6 @@
                 <property name="visible">1</property>
                 <property name="can-focus">1</property>
                 <property name="hexpand">1</property>
-                <property name="width-chars">20</property>
                 <property name="placeholder-text" translatable="yes">Enter server address…</property>
                 <property name="secondary-icon-name">dialog-question-symbolic</property>
                 <property name="completion">address_entry_completion</property>
-- 
2.39.2

