From 694c343bf4e149040ba93e9feabd0c1b8b004ba9 Mon Sep 17 00:00:00 2001
From: Paolo Stivanin <info@paolostivanin.com>
Date: Mon, 4 Mar 2024 15:17:34 +0100
Subject: [PATCH 1/4] Refactor code and improve menus

* add back button to all popover menus
* split popovers into their own UI files
* remove upgrade msg from v2.6
---
 CMakeLists.txt             |   2 +-
 src/app.c                  | 111 +------
 src/data.h                 |   2 +
 src/get-builder.h          |   2 +
 src/ui/add_popover.ui      | 116 +++++++
 src/ui/otpclient.ui        | 654 -------------------------------------
 src/ui/settings_popover.ui | 548 +++++++++++++++++++++++++++++++
 7 files changed, 682 insertions(+), 753 deletions(-)
 create mode 100644 src/ui/add_popover.ui
 create mode 100644 src/ui/settings_popover.ui

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7bdcf854..d8df1714 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 3.16)
-project(OTPClient VERSION "3.5.0" LANGUAGES "C")
+project(OTPClient VERSION "3.5.1" LANGUAGES "C")
 include(GNUInstallDirs)
 
 configure_file("src/common/version.h.in" "version.h")
diff --git a/src/app.c b/src/app.c
index 33ec1aed..e304fa87 100644
--- a/src/app.c
+++ b/src/app.c
@@ -46,18 +46,6 @@ static void       create_main_window        (gint                width,
                                              gint                height,
                                              AppData            *app_data);
 
-static gboolean   show_upgrade_msg          (void);
-
-static void       set_info_bar              (AppData            *app_data,
-                                             const gchar        *msg);
-
-static void       on_bar_response           (GtkInfoBar         *ib,
-                                             gint                response_id,
-                                             gpointer            user_data);
-
-static gboolean   set_action_group          (GtkBuilder         *builder,
-                                             AppData            *app_data);
-
 static void       get_window_size_cb        (GtkWidget          *window,
                                              GtkAllocation      *allocation,
                                              gpointer            user_data);
@@ -116,6 +104,8 @@ activate (GtkApplication    *app,
     // open_db_file_action is set only on first startup and not when the db is deleted but the cfg file is there, therefore we need a default action
     app_data->open_db_file_action = GTK_FILE_CHOOSER_ACTION_SAVE;
     app_data->builder = get_builder_from_partial_path (UI_PARTIAL_PATH);
+    app_data->add_popover_builder = get_builder_from_partial_path (AP_PARTIAL_PATH);
+    app_data->settings_popover_builder = get_builder_from_partial_path (SP_PARTIAL_PATH);
 
     set_config_data (&width, &height, app_data);
 
@@ -285,13 +275,6 @@ activate (GtkApplication    *app,
     app_data->source_id_last_activity = g_timeout_add_seconds (1, check_inactivity, app_data);
 
     gtk_widget_show_all (app_data->main_window);
-
-    app_data->info_bar = GTK_WIDGET(gtk_builder_get_object (app_data->builder, "info_bar_id"));
-    if (show_upgrade_msg ()) {
-        set_info_bar (app_data, _("Not asking for password? Please check the 'Secret Service Integration' new feature <a href=\"https://github.com/paolostivanin/OTPClient/wiki/How-to-use-OTPClient#secret-service-integration\">HERE</a>"));
-    } else {
-        gtk_widget_hide (app_data->info_bar);
-    }
 }
 
 
@@ -444,9 +427,9 @@ set_warn_data (gboolean show_warning)
 
 
 static void
-create_main_window (gint             width,
-                    gint             height,
-                    AppData         *app_data)
+create_main_window (gint     width,
+                    gint     height,
+                    AppData *app_data)
 {
     app_data->main_window = GTK_WIDGET(gtk_builder_get_object (app_data->builder, "appwindow_id"));
     gtk_window_set_icon_name (GTK_WINDOW(app_data->main_window), "otpclient");
@@ -460,76 +443,6 @@ create_main_window (gint             width,
         gtk_widget_set_sensitive (lock_btn, FALSE);
     }
 
-    set_action_group (app_data->builder, app_data);
-}
-
-
-static gboolean
-show_upgrade_msg (void)
-{
-    gboolean show_msg = TRUE;
-    GKeyFile *kf = get_kf_ptr ();
-    if (kf != NULL) {
-        gchar *up_msg = g_key_file_get_string (kf, "config", "upgrade_msg", NULL);
-        if (up_msg == NULL) {
-            show_msg = TRUE;
-        } else {
-            show_msg = (g_strcmp0 (up_msg, "v2_6") == 0) ? FALSE : TRUE;
-        }
-    }
-
-    g_key_file_free (kf);
-
-    return show_msg;
-}
-
-
-static void
-set_info_bar (AppData     *app_data,
-              const gchar *msg)
-{
-    GtkWidget *label = GTK_WIDGET(gtk_builder_get_object (app_data->builder, "info_bar_label_id"));
-
-    g_signal_connect (app_data->info_bar, "response", G_CALLBACK(on_bar_response), NULL);
-
-    gtk_label_set_markup (GTK_LABEL(label), msg);
-    gtk_info_bar_set_message_type (GTK_INFO_BAR(app_data->info_bar), GTK_MESSAGE_INFO);
-    gtk_widget_show (app_data->info_bar);
-}
-
-
-static void
-on_bar_response (GtkInfoBar *ib,
-                 gint        response_id __attribute__((unused)),
-                 gpointer    user_data   __attribute__((unused)))
-{
-    GError *err = NULL;
-    GKeyFile *kf = get_kf_ptr ();
-    if (kf != NULL) {
-        g_key_file_set_string (kf, "config", "upgrade_msg", "v2_6");
-        gchar *cfg_file_path;
-#ifndef USE_FLATPAK_APP_FOLDER
-        cfg_file_path = g_build_filename (g_get_user_config_dir (), "otpclient.cfg", NULL);
-#else
-        cfg_file_path = g_build_filename (g_get_user_data_dir (), "otpclient.cfg", NULL);
-#endif
-        if (!g_key_file_save_to_file (kf, cfg_file_path, &err)) {
-            g_printerr ("%s\n", err->message);
-            g_clear_error (&err);
-        }
-        g_free (cfg_file_path);
-    }
-
-    g_key_file_free (kf);
-
-    gtk_widget_hide (GTK_WIDGET(ib));
-}
-
-
-static gboolean
-set_action_group (GtkBuilder *builder,
-                  AppData    *app_data)
-{
     static GActionEntry settings_menu_entries[] = {
             { .name = ANDOTP_IMPORT_ACTION_NAME, .activate = select_file_cb },
             { .name = ANDOTP_IMPORT_PLAIN_ACTION_NAME, .activate = select_file_cb },
@@ -569,20 +482,20 @@ set_action_group (GtkBuilder *builder,
             { .name = "manual", .activate = manual_add_cb }
     };
 
-    GtkWidget *settings_popover = GTK_WIDGET (gtk_builder_get_object (builder, "settings_pop_id"));
+    GtkWidget *settings_popover = GTK_WIDGET(gtk_builder_get_object (app_data->settings_popover_builder, "settings_pop_id"));
+    gtk_menu_button_set_popover (GTK_MENU_BUTTON(gtk_builder_get_object (app_data->builder, "settings_btn_id")), settings_popover);
     GActionGroup *settings_actions = (GActionGroup *)g_simple_action_group_new ();
-    g_action_map_add_action_entries (G_ACTION_MAP (settings_actions), settings_menu_entries, G_N_ELEMENTS (settings_menu_entries), app_data);
+    g_action_map_add_action_entries (G_ACTION_MAP(settings_actions), settings_menu_entries, G_N_ELEMENTS (settings_menu_entries), app_data);
     gtk_widget_insert_action_group (settings_popover, "settings_menu", settings_actions);
 
-    GtkWidget *add_popover = GTK_WIDGET (gtk_builder_get_object (builder, "add_pop_id"));
+    GtkWidget *add_popover = GTK_WIDGET(gtk_builder_get_object (app_data->add_popover_builder, "add_pop_id"));
+    gtk_menu_button_set_popover (GTK_MENU_BUTTON(gtk_builder_get_object (app_data->builder, "add_btn_main_id")), add_popover);
     GActionGroup *add_actions = (GActionGroup *)g_simple_action_group_new ();
-    g_action_map_add_action_entries (G_ACTION_MAP (add_actions), add_menu_entries, G_N_ELEMENTS (add_menu_entries), app_data);
+    g_action_map_add_action_entries (G_ACTION_MAP(add_actions), add_menu_entries, G_N_ELEMENTS (add_menu_entries), app_data);
     gtk_widget_insert_action_group (add_popover, "add_menu", add_actions);
 
     gtk_popover_set_constrain_to (GTK_POPOVER(add_popover), GTK_POPOVER_CONSTRAINT_NONE);
     gtk_popover_set_constrain_to (GTK_POPOVER(settings_popover), GTK_POPOVER_CONSTRAINT_NONE);
-
-    return TRUE;
 }
 
 
@@ -765,6 +678,8 @@ destroy_cb (GtkWidget   *window,
 #pragma GCC diagnostic pop
     save_window_size (w, h);
     g_object_unref (app_data->builder);
+    g_object_unref (app_data->add_popover_builder);
+    g_object_unref (app_data->settings_popover_builder);
     g_free (app_data);
     gcry_control (GCRYCTL_TERM_SECMEM);
 }
diff --git a/src/data.h b/src/data.h
index 6d3d33a9..5aa60aa8 100644
--- a/src/data.h
+++ b/src/data.h
@@ -29,6 +29,8 @@ typedef struct db_data_t {
 
 typedef struct app_data_t {
     GtkBuilder *builder;
+    GtkBuilder *add_popover_builder;
+    GtkBuilder *settings_popover_builder;
 
     GtkWidget *main_window;
     GtkWidget *info_bar;
diff --git a/src/get-builder.h b/src/get-builder.h
index b3c55258..c301c857 100644
--- a/src/get-builder.h
+++ b/src/get-builder.h
@@ -3,6 +3,8 @@
 G_BEGIN_DECLS
 
 #define UI_PARTIAL_PATH         "share/otpclient/otpclient.ui"
+#define AP_PARTIAL_PATH         "share/otpclient/add_popover.ui"
+#define SP_PARTIAL_PATH         "share/otpclient/settings_popover.ui"
 
 GtkBuilder *get_builder_from_partial_path (const gchar *partial_path);
 
diff --git a/src/ui/add_popover.ui b/src/ui/add_popover.ui
new file mode 100644
index 00000000..42d29005
--- /dev/null
+++ b/src/ui/add_popover.ui
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.40.0 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkPopoverMenu" id="add_pop_id">
+    <property name="can-focus">False</property>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkModelButton" id="add_qr_back_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="inverted">True</property>
+            <property name="centered">True</property>
+            <property name="menu-name">main</property>
+            <property name="text" translatable="yes">Back</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="add_qr_file_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">add_menu.import_qr_file</property>
+            <property name="text" translatable="yes">From file</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="add_qr_clipboard_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">add_menu.import_qr_clipboard</property>
+            <property name="text" translatable="yes">From clipboard</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="submenu">import_qr_menu</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkModelButton" id="webcam_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">add_menu.webcam</property>
+            <property name="text" translatable="yes">Scan using webcam</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_qr_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="text" translatable="yes">Using a QR Code</property>
+            <property name="menu-name">import_qr_menu</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="manual_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">add_menu.manual</property>
+            <property name="text" translatable="yes">Manually</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="submenu">main</property>
+        <property name="position">2</property>
+      </packing>
+    </child>
+  </object>
+</interface>
\ No newline at end of file
diff --git a/src/ui/otpclient.ui b/src/ui/otpclient.ui
index 4d2eb7ff..e6458751 100644
--- a/src/ui/otpclient.ui
+++ b/src/ui/otpclient.ui
@@ -2,101 +2,6 @@
 <!-- Generated with glade 3.40.0 -->
 <interface>
   <requires lib="gtk+" version="3.20"/>
-  <object class="GtkPopoverMenu" id="add_pop_id">
-    <property name="can-focus">False</property>
-    <child>
-      <object class="GtkBox">
-        <property name="visible">True</property>
-        <property name="can-focus">False</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkModelButton" id="add_qr_file_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">add_menu.import_qr_file</property>
-            <property name="text" translatable="yes">From file</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="add_qr_clipboard_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">add_menu.import_qr_clipboard</property>
-            <property name="text" translatable="yes">From clipboard</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">2</property>
-          </packing>
-        </child>
-      </object>
-      <packing>
-        <property name="submenu">import_qr_menu</property>
-        <property name="position">1</property>
-      </packing>
-    </child>
-    <child>
-      <object class="GtkBox">
-        <property name="visible">True</property>
-        <property name="can-focus">False</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkModelButton" id="webcam_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">add_menu.webcam</property>
-            <property name="text" translatable="yes">Scan using webcam</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="import_qr_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="text" translatable="yes">Using a QR Code</property>
-            <property name="menu-name">import_qr_menu</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">2</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="manual_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">add_menu.manual</property>
-            <property name="text" translatable="yes">Manually</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">3</property>
-          </packing>
-        </child>
-      </object>
-      <packing>
-        <property name="submenu">main</property>
-        <property name="position">2</property>
-      </packing>
-    </child>
-  </object>
   <object class="GtkDialog" id="changedb_diag_id">
     <property name="can-focus">False</property>
     <property name="border-width">5</property>
@@ -2134,502 +2039,6 @@ but not the number of digits and/or the period/counter.</property>
       <action-widget response="-5">settings_diag_ok_btn_id</action-widget>
     </action-widgets>
   </object>
-  <object class="GtkPopoverMenu" id="settings_pop_id">
-    <property name="can-focus">False</property>
-    <child>
-      <object class="GtkBox">
-        <property name="visible">True</property>
-        <property name="can-focus">False</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkModelButton" id="import_andotp_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.import_andotp</property>
-            <property name="text" translatable="yes">andOTP (encrypted)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="import_andotp_plain_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.import_andotp_plain</property>
-            <property name="text" translatable="yes">andOTP (plain)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="import_freeotpplus_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.import_freeotpplus</property>
-            <property name="text" translatable="yes">FreeOTP+ (key URI)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">2</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="import_aegis_enc_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.import_aegis_enc</property>
-            <property name="text" translatable="yes">Aegis (encrypted json)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">3</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="import_aegis_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.import_aegis</property>
-            <property name="text" translatable="yes">Aegis (plain json)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">4</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="import_authpro_enc_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.import_authpro_enc</property>
-            <property name="text" translatable="yes">Authenticator Pro (encrypted)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">5</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="import_authpro_plain_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.import_authpro_plain</property>
-            <property name="text" translatable="yes">Authenticator Pro (plain json)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">6</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="import_twofas_enc_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.import_twofas_enc</property>
-            <property name="text" translatable="yes">2FAS (encrypted json)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">7</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="import_twofas_plain_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.import_twofas_plain</property>
-            <property name="text" translatable="yes">2FAS (plain json)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">8</property>
-          </packing>
-        </child>
-
-        <child>
-          <object class="GtkModelButton" id="import_google_qr_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="text" translatable="yes">Google Migration QR</property>
-            <property name="menu-name">import_google_qr_menu</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">9</property>
-          </packing>
-        </child>
-      </object>
-      <packing>
-        <property name="submenu">import_menu</property>
-        <property name="position">1</property>
-      </packing>
-    </child>
-    <child>
-      <object class="GtkBox">
-        <property name="visible">True</property>
-        <property name="can-focus">False</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkModelButton" id="export_andotp_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.export_andotp</property>
-            <property name="text" translatable="yes">andOTP (encrypted)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="export_andotp_plain_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.export_andotp_plain</property>
-            <property name="text" translatable="yes">andOTP (plain)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="export_freeotpplus_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.export_freeotpplus</property>
-            <property name="text" translatable="yes">FreeOTP+ (key URI)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">2</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="export_aegis_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.export_aegis</property>
-            <property name="text" translatable="yes">Aegis (encrypted json)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">3</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="export_aegis_plain_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.export_aegis_plain</property>
-            <property name="text" translatable="yes">Aegis (plain json)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">4</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="export_authpro_enc_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.export_authpro_enc</property>
-            <property name="text" translatable="yes">Authenticator Pro (encrypted)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">5</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="export_authpro_plain_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.export_authpro_plain</property>
-            <property name="text" translatable="yes">Authenticator Pro (plain json)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">6</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="export_twofas_enc_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.export_twofas_enc</property>
-            <property name="text" translatable="yes">2FAS (encrypted json)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">7</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="export_twofas_plain_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.export_twofas_plain</property>
-            <property name="text" translatable="yes">2FAS (plain json)</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">8</property>
-          </packing>
-        </child>
-      </object>
-      <packing>
-        <property name="submenu">export_menu</property>
-        <property name="position">2</property>
-      </packing>
-    </child>
-    <child>
-      <object class="GtkBox">
-        <property name="visible">True</property>
-        <property name="can-focus">False</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkModelButton" id="import_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="text" translatable="yes">Import</property>
-            <property name="menu-name">import_menu</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="export_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="text" translatable="yes">Export</property>
-            <property name="menu-name">export_menu</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="newdb_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.create_newdb</property>
-            <property name="text" translatable="yes">New database</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">2</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="change_db_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.change_db</property>
-            <property name="text" translatable="yes">Change database</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">3</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="change_pwd_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.change_pwd</property>
-            <property name="text" translatable="yes">Change password</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">4</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="edit_row_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.edit_row</property>
-            <property name="text" translatable="yes">Edit row</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">5</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="show_qr_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.show_qr</property>
-            <property name="text" translatable="yes">Show QR-Code</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">6</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="settings_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.settings</property>
-            <property name="text" translatable="yes">Settings</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">7</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="shortcuts_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.shortcuts</property>
-            <property name="text" translatable="yes">Keyboard shortcuts</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">8</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="dbinfo_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.dbinfo</property>
-            <property name="text" translatable="yes">Database info</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">9</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="about_model_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.about</property>
-            <property name="text" translatable="yes">About</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">10</property>
-          </packing>
-        </child>
-      </object>
-      <packing>
-        <property name="submenu">main</property>
-        <property name="position">3</property>
-      </packing>
-    </child>
-    <child>
-      <object class="GtkBox">
-        <property name="visible">True</property>
-        <property name="can-focus">False</property>
-        <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkModelButton" id="import_google_qr_file_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.import_google_qr_file</property>
-            <property name="text" translatable="yes">From file</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
-        <child>
-          <object class="GtkModelButton" id="import_google_qr_webcam_btn_id">
-            <property name="visible">True</property>
-            <property name="can-focus">True</property>
-            <property name="receives-default">True</property>
-            <property name="action-name">settings_menu.import_google_qr_webcam</property>
-            <property name="text" translatable="yes">From webcam</property>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">True</property>
-            <property name="position">1</property>
-          </packing>
-        </child>
-      </object>
-      <packing>
-        <property name="submenu">import_google_qr_menu</property>
-        <property name="position">4</property>
-      </packing>
-    </child>
-  </object>
   <object class="GtkApplicationWindow" id="appwindow_id">
     <property name="can-focus">False</property>
     <property name="window-position">center</property>
@@ -2641,67 +2050,6 @@ but not the number of digits and/or the period/counter.</property>
         <property name="visible">True</property>
         <property name="can-focus">False</property>
         <property name="orientation">vertical</property>
-        <child>
-          <object class="GtkInfoBar" id="info_bar_id">
-            <property name="can-focus">False</property>
-            <property name="orientation">vertical</property>
-            <child internal-child="action_area">
-              <object class="GtkButtonBox">
-                <property name="can-focus">False</property>
-                <property name="spacing">6</property>
-                <property name="layout-style">end</property>
-                <child>
-                  <object class="GtkButton" id="info_bar_ok_btn_id">
-                    <property name="label" translatable="yes">OK</property>
-                    <property name="visible">True</property>
-                    <property name="can-focus">True</property>
-                    <property name="receives-default">True</property>
-                  </object>
-                  <packing>
-                    <property name="expand">True</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <child internal-child="content_area">
-              <object class="GtkBox">
-                <property name="can-focus">False</property>
-                <property name="spacing">16</property>
-                <child>
-                  <object class="GtkLabel" id="info_bar_label_id">
-                    <property name="visible">True</property>
-                    <property name="can-focus">False</property>
-                  </object>
-                  <packing>
-                    <property name="expand">False</property>
-                    <property name="fill">True</property>
-                    <property name="position">0</property>
-                  </packing>
-                </child>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">0</property>
-              </packing>
-            </child>
-            <action-widgets>
-              <action-widget response="-5">info_bar_ok_btn_id</action-widget>
-            </action-widgets>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="fill">False</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
         <child>
           <object class="GtkScrolledWindow" id="scrolledwin_id">
             <property name="visible">True</property>
@@ -2750,7 +2098,6 @@ but not the number of digits and/or the period/counter.</property>
                 <property name="can-focus">True</property>
                 <property name="receives-default">True</property>
                 <property name="tooltip-text" translatable="yes">Add token</property>
-                <property name="popover">add_pop_id</property>
                 <child>
                   <object class="GtkImage">
                     <property name="visible">True</property>
@@ -2805,7 +2152,6 @@ but not the number of digits and/or the period/counter.</property>
             <property name="can-focus">True</property>
             <property name="receives-default">True</property>
             <property name="tooltip-text" translatable="yes">Settings</property>
-            <property name="popover">settings_pop_id</property>
             <child>
               <object class="GtkImage">
                 <property name="visible">True</property>
diff --git a/src/ui/settings_popover.ui b/src/ui/settings_popover.ui
new file mode 100644
index 00000000..729e320b
--- /dev/null
+++ b/src/ui/settings_popover.ui
@@ -0,0 +1,548 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.40.0 -->
+<interface>
+  <requires lib="gtk+" version="3.20"/>
+  <object class="GtkPopoverMenu" id="settings_pop_id">
+    <property name="can-focus">False</property>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkModelButton" id="import_submenu_back_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="inverted">True</property>
+            <property name="centered">True</property>
+            <property name="menu-name">main</property>
+            <property name="text" translatable="yes">Back</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_andotp_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.import_andotp</property>
+            <property name="text" translatable="yes">andOTP (encrypted)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_andotp_plain_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.import_andotp_plain</property>
+            <property name="text" translatable="yes">andOTP (plain)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_freeotpplus_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.import_freeotpplus</property>
+            <property name="text" translatable="yes">FreeOTP+ (key URI)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_aegis_enc_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.import_aegis_enc</property>
+            <property name="text" translatable="yes">Aegis (encrypted json)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_aegis_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.import_aegis</property>
+            <property name="text" translatable="yes">Aegis (plain json)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">5</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_authpro_enc_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.import_authpro_enc</property>
+            <property name="text" translatable="yes">Authenticator Pro (encrypted)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">6</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_authpro_plain_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.import_authpro_plain</property>
+            <property name="text" translatable="yes">Authenticator Pro (plain json)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">7</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_twofas_enc_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.import_twofas_enc</property>
+            <property name="text" translatable="yes">2FAS (encrypted json)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">8</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_twofas_plain_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.import_twofas_plain</property>
+            <property name="text" translatable="yes">2FAS (plain json)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">9</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_google_qr_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="text" translatable="yes">Google Migration QR</property>
+            <property name="menu-name">import_google_qr_menu</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">10</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="submenu">import_menu</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkModelButton" id="export_submenu_back_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="inverted">True</property>
+            <property name="centered">True</property>
+            <property name="menu-name">main</property>
+            <property name="text" translatable="yes">Back</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="export_andotp_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.export_andotp</property>
+            <property name="text" translatable="yes">andOTP (encrypted)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="export_andotp_plain_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.export_andotp_plain</property>
+            <property name="text" translatable="yes">andOTP (plain)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="export_freeotpplus_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.export_freeotpplus</property>
+            <property name="text" translatable="yes">FreeOTP+ (key URI)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="export_aegis_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.export_aegis</property>
+            <property name="text" translatable="yes">Aegis (encrypted json)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="export_aegis_plain_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.export_aegis_plain</property>
+            <property name="text" translatable="yes">Aegis (plain json)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">5</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="export_authpro_enc_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.export_authpro_enc</property>
+            <property name="text" translatable="yes">Authenticator Pro (encrypted)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">6</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="export_authpro_plain_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.export_authpro_plain</property>
+            <property name="text" translatable="yes">Authenticator Pro (plain json)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">7</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="export_twofas_enc_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.export_twofas_enc</property>
+            <property name="text" translatable="yes">2FAS (encrypted json)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">8</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="export_twofas_plain_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.export_twofas_plain</property>
+            <property name="text" translatable="yes">2FAS (plain json)</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">9</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="submenu">export_menu</property>
+        <property name="position">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkModelButton" id="import_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="text" translatable="yes">Import</property>
+            <property name="menu-name">import_menu</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="export_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="text" translatable="yes">Export</property>
+            <property name="menu-name">export_menu</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="newdb_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.create_newdb</property>
+            <property name="text" translatable="yes">New database</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="change_db_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.change_db</property>
+            <property name="text" translatable="yes">Change database</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="change_pwd_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.change_pwd</property>
+            <property name="text" translatable="yes">Change password</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="edit_row_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.edit_row</property>
+            <property name="text" translatable="yes">Edit row</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">5</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="show_qr_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.show_qr</property>
+            <property name="text" translatable="yes">Show QR-Code</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">6</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="settings_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.settings</property>
+            <property name="text" translatable="yes">Settings</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">7</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="shortcuts_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.shortcuts</property>
+            <property name="text" translatable="yes">Keyboard shortcuts</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">8</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="dbinfo_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.dbinfo</property>
+            <property name="text" translatable="yes">Database info</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">9</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="about_model_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.about</property>
+            <property name="text" translatable="yes">About</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">10</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="submenu">main</property>
+        <property name="position">3</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can-focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkModelButton" id="import_submenu_google_back_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="inverted">True</property>
+            <property name="centered">True</property>
+            <property name="menu-name">import_menu</property>
+            <property name="text" translatable="yes">Back</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_google_qr_file_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.import_google_qr_file</property>
+            <property name="text" translatable="yes">From file</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkModelButton" id="import_google_qr_webcam_btn_id">
+            <property name="visible">True</property>
+            <property name="can-focus">True</property>
+            <property name="receives-default">True</property>
+            <property name="action-name">settings_menu.import_google_qr_webcam</property>
+            <property name="text" translatable="yes">From webcam</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="submenu">import_google_qr_menu</property>
+        <property name="position">4</property>
+      </packing>
+    </child>
+  </object>
+</interface>
\ No newline at end of file

From 56739c22cd78131515bdf7b8f4dd120764bebea5 Mon Sep 17 00:00:00 2001
From: Paolo Stivanin <info@paolostivanin.com>
Date: Mon, 4 Mar 2024 15:45:02 +0100
Subject: [PATCH 2/4] Update CI to latest Ubuntu LTS

---
 .circleci/config.yml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/.circleci/config.yml b/.circleci/config.yml
index 09807970..52b0f0de 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -1,9 +1,9 @@
 version: 2.0
 
 jobs:
-  ubuntu2304:
+  ubuntu2404:
     docker:
-      - image: ubuntu:23.04
+      - image: ubuntu:24.04
     steps:
       - checkout
       - run: apt update && DEBIAN_FRONTEND=noninteractive apt -y install git gcc clang cmake libgcrypt20-dev libgtk-3-dev libzip-dev libjansson-dev libpng-dev libzbar-dev libprotobuf-c-dev libsecret-1-dev uuid-dev libprotobuf-dev libqrencode-dev
@@ -50,7 +50,7 @@ workflows:
   version: 2
   build:
     jobs:
-      - ubuntu2304
+      - ubuntu2404
       - ubuntuLatestRolling
       - debianLatestStable
       - fedoraLatestStable

From 64235ab1100f919a14b4f98eb85026ec080b4304 Mon Sep 17 00:00:00 2001
From: Paolo Stivanin <info@paolostivanin.com>
Date: Tue, 5 Mar 2024 10:44:30 +0100
Subject: [PATCH 3/4] Disable github workflow until Ubuntu 24.04 comes out

---
 .../workflows/codeql-analysis.yml                                 | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename {.github => github_workflow_disabled}/workflows/codeql-analysis.yml (100%)

diff --git a/.github/workflows/codeql-analysis.yml b/github_workflow_disabled/workflows/codeql-analysis.yml
similarity index 100%
rename from .github/workflows/codeql-analysis.yml
rename to github_workflow_disabled/workflows/codeql-analysis.yml

From dd32860eebaf0b68098ed4693259adfd84ce17a4 Mon Sep 17 00:00:00 2001
From: Paolo Stivanin <info@paolostivanin.com>
Date: Tue, 5 Mar 2024 10:51:55 +0100
Subject: [PATCH 4/4] Update appdata and CMakeLists

---
 CMakeLists.txt                                      |  2 ++
 data/com.github.paolostivanin.OTPClient.appdata.xml | 12 +++++++++++-
 2 files changed, 13 insertions(+), 1 deletion(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d8df1714..d846d7ce 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -264,6 +264,8 @@ install(FILES data/com.github.paolostivanin.OTPClient.desktop DESTINATION share/
 install(FILES data/com.github.paolostivanin.OTPClient.appdata.xml DESTINATION share/metainfo)
 
 install(FILES src/ui/otpclient.ui DESTINATION share/otpclient)
+install(FILES src/ui/add_popover.ui DESTINATION share/otpclient)
+install(FILES src/ui/settings_popover.ui DESTINATION share/otpclient)
 install(FILES src/ui/shortcuts.ui DESTINATION share/otpclient)
 
 install(FILES man/otpclient.1.gz DESTINATION share/man/man1)
diff --git a/data/com.github.paolostivanin.OTPClient.appdata.xml b/data/com.github.paolostivanin.OTPClient.appdata.xml
index f851dea6..11f400dc 100644
--- a/data/com.github.paolostivanin.OTPClient.appdata.xml
+++ b/data/com.github.paolostivanin.OTPClient.appdata.xml
@@ -89,7 +89,17 @@
   </content_rating>
 
   <releases>
-    <release version="3.5.0" date="2024-03-01x">
+    <release version="3.5.0" date="2024-03-05">
+      <description>
+        <p>OTPClient 3.5.1 brings a small improvement and some code clean-up:</p>
+        <ul>
+          <li>NEW: add back buttons to the various popover menus</li>
+          <li>FIX: split popovers into their own UI files</li>
+          <li>FIX: remove upgrade message when upgrading from a version older than 2.6.0</li>
+        </ul>
+      </description>
+    </release>
+    <release version="3.5.0" date="2024-03-01">
       <description>
         <p>OTPClient 3.5.0 brings some new features and improvements:</p>
         <ul>