[epiphany] Add the Firefox Sync button in the page menu
- From: Michael Catanzaro <mcatanzaro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany] Add the Firefox Sync button in the page menu
- Date: Fri, 2 Oct 2020 13:00:06 +0000 (UTC)
commit 489e58e9451b399e0fd3d18a68322997f8c0e2b4
Author: Yetizone <andreii lisita gmail com>
Date: Mon Sep 28 17:01:55 2020 +0300
Add the Firefox Sync button in the page menu
src/ephy-firefox-sync-dialog.c | 802 +++++++++++++++++++++++++++++++
src/ephy-firefox-sync-dialog.h | 34 ++
src/ephy-shell.c | 34 ++
src/ephy-shell.h | 99 ++--
src/meson.build | 1 +
src/resources/epiphany.gresource.xml | 1 +
src/resources/gtk/firefox-sync-dialog.ui | 226 +++++++++
src/resources/gtk/page-menu-popover.ui | 16 +
src/window-commands.c | 15 +
src/window-commands.h | 3 +
10 files changed, 1182 insertions(+), 49 deletions(-)
---
diff --git a/src/ephy-firefox-sync-dialog.c b/src/ephy-firefox-sync-dialog.c
new file mode 100644
index 000000000..08c057333
--- /dev/null
+++ b/src/ephy-firefox-sync-dialog.c
@@ -0,0 +1,802 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Copyright © 2000-2003 Marco Pesenti Gritti
+ * Copyright © 2003, 2004, 2005 Christian Persch
+ * Copyright © 2010, 2017 Igalia S.L.
+ *
+ * This file is part of Epiphany.
+ *
+ * Epiphany is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Epiphany is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Epiphany. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ephy-firefox-sync-dialog.h"
+
+#include "ephy-debug.h"
+#include "ephy-embed-prefs.h"
+#include "ephy-embed-shell.h"
+#include "ephy-prefs.h"
+#include "ephy-settings.h"
+#include "ephy-shell.h"
+#include "ephy-sync-service.h"
+#include "ephy-sync-utils.h"
+#include "ephy-time-helpers.h"
+#include "synced-tabs-dialog.h"
+
+#define FXA_IFRAME_URL "https://accounts.firefox.com/signin?service=sync&context=fx_desktop_v3"
+
+struct _EphyFirefoxSyncDialog {
+ HdyWindow parent_instance;
+
+ GtkWidget *sync_page_box;
+ GtkWidget *sync_firefox_iframe_box;
+ GtkWidget *sync_firefox_iframe_label;
+ GtkWidget *sync_firefox_account_box;
+ GtkWidget *sync_firefox_account_row;
+ GtkWidget *sync_options_box;
+ GtkWidget *sync_bookmarks_switch;
+ GtkWidget *sync_passwords_switch;
+ GtkWidget *sync_history_switch;
+ GtkWidget *sync_open_tabs_switch;
+ GtkWidget *sync_frequency_row;
+ GtkWidget *sync_now_button;
+ GtkWidget *synced_tabs_button;
+ GtkWidget *sync_device_name_entry;
+ GtkWidget *sync_device_name_change_button;
+ GtkWidget *sync_device_name_save_button;
+ GtkWidget *sync_device_name_cancel_button;
+
+ WebKitWebView *fxa_web_view;
+ WebKitUserContentManager *fxa_manager;
+ WebKitUserScript *fxa_script;
+};
+
+G_DEFINE_TYPE (EphyFirefoxSyncDialog, ephy_firefox_sync_dialog, HDY_TYPE_WINDOW)
+
+static const guint sync_frequency_minutes[] = { 5, 15, 30, 60 };
+
+static void
+sync_collection_toggled_cb (GtkWidget *sw,
+ gboolean sw_active,
+ EphyFirefoxSyncDialog *sync_dialog)
+{
+ EphySynchronizableManager *manager = NULL;
+ EphyShell *shell = ephy_shell_get_default ();
+ EphySyncService *service = ephy_shell_get_sync_service (shell);
+
+ if (GTK_WIDGET (sw) == sync_dialog->sync_bookmarks_switch) {
+ manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_bookmarks_manager (shell));
+ } else if (GTK_WIDGET (sw) == sync_dialog->sync_passwords_switch) {
+ manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_embed_shell_get_password_manager (EPHY_EMBED_SHELL (shell)));
+ } else if (GTK_WIDGET (sw) == sync_dialog->sync_history_switch) {
+ manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_history_manager (shell));
+ } else if (GTK_WIDGET (sw) == sync_dialog->sync_open_tabs_switch) {
+ manager = EPHY_SYNCHRONIZABLE_MANAGER (ephy_shell_get_open_tabs_manager (shell));
+ ephy_open_tabs_manager_clear_cache (EPHY_OPEN_TABS_MANAGER (manager));
+ } else {
+ g_assert_not_reached ();
+ }
+
+ if (sw_active) {
+ ephy_sync_service_register_manager (service, manager);
+ } else {
+ ephy_sync_service_unregister_manager (service, manager);
+ ephy_synchronizable_manager_set_is_initial_sync (manager, TRUE);
+ }
+}
+
+static void
+sync_set_last_sync_time (EphyFirefoxSyncDialog *sync_dialog)
+{
+ gint64 sync_time = ephy_sync_utils_get_sync_time ();
+
+ if (sync_time) {
+ char *time = ephy_time_helpers_utf_friendly_time (sync_time);
+ /* Translators: the %s refers to the time at which the last sync was made.
+ * For example: Today 04:34 PM, Sun 11:25 AM, May 31 06:41 PM.
+ */
+ char *text = g_strdup_printf (_("Last synchronized: %s"), time);
+
+ hdy_action_row_set_subtitle (HDY_ACTION_ROW (sync_dialog->sync_firefox_account_row), text);
+
+ g_free (text);
+ g_free (time);
+ }
+}
+
+static void
+sync_finished_cb (EphySyncService *service,
+ EphyFirefoxSyncDialog *sync_dialog)
+{
+ g_assert (EPHY_IS_SYNC_SERVICE (service));
+ g_assert (EPHY_IS_FIREFOX_SYNC_DIALOG (sync_dialog));
+
+ gtk_widget_set_sensitive (sync_dialog->sync_now_button, TRUE);
+ sync_set_last_sync_time (sync_dialog);
+}
+
+static void
+sync_sign_in_details_show (EphyFirefoxSyncDialog *sync_dialog,
+ const char *text)
+{
+ char *message;
+
+ g_assert (EPHY_IS_FIREFOX_SYNC_DIALOG (sync_dialog));
+
+ message = g_strdup_printf ("<span fgcolor='#e6780b'>%s</span>", text);
+ gtk_label_set_markup (GTK_LABEL (sync_dialog->sync_firefox_iframe_label), message);
+ gtk_widget_set_visible (sync_dialog->sync_firefox_iframe_label, TRUE);
+
+ g_free (message);
+}
+
+static void
+sync_sign_in_error_cb (EphySyncService *service,
+ const char *error,
+ EphyFirefoxSyncDialog *sync_dialog)
+{
+ g_assert (EPHY_IS_SYNC_SERVICE (service));
+ g_assert (EPHY_IS_FIREFOX_SYNC_DIALOG (sync_dialog));
+
+ /* Display the error message and reload the iframe. */
+ sync_sign_in_details_show (sync_dialog, error);
+ webkit_web_view_load_uri (sync_dialog->fxa_web_view, FXA_IFRAME_URL);
+}
+
+static void
+sync_secrets_store_finished_cb (EphySyncService *service,
+ GError *error,
+ EphyFirefoxSyncDialog *sync_dialog)
+{
+ g_assert (EPHY_IS_SYNC_SERVICE (service));
+ g_assert (EPHY_IS_FIREFOX_SYNC_DIALOG (sync_dialog));
+
+ if (!error) {
+ hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (sync_dialog->sync_firefox_account_row),
+ ephy_sync_utils_get_sync_user ());
+ gtk_widget_hide (sync_dialog->sync_page_box);
+ gtk_widget_show (sync_dialog->sync_firefox_account_box);
+ gtk_widget_show (sync_dialog->sync_options_box);
+ } else {
+ /* Display the error message and reload the iframe. */
+ sync_sign_in_details_show (sync_dialog, error->message);
+ webkit_web_view_load_uri (sync_dialog->fxa_web_view, FXA_IFRAME_URL);
+ }
+}
+
+static void
+sync_message_to_fxa_content (EphyFirefoxSyncDialog *sync_dialog,
+ const char *web_channel_id,
+ const char *command,
+ const char *message_id,
+ JsonObject *data)
+{
+ JsonNode *node;
+ JsonObject *detail;
+ JsonObject *message;
+ char *detail_str;
+ char *script;
+ const char *type;
+
+ g_assert (EPHY_FIREFOX_SYNC_DIALOG (sync_dialog));
+ g_assert (web_channel_id);
+ g_assert (command);
+ g_assert (message_id);
+ g_assert (data);
+
+ message = json_object_new ();
+ json_object_set_string_member (message, "command", command);
+ json_object_set_string_member (message, "messageId", message_id);
+ json_object_set_object_member (message, "data", json_object_ref (data));
+ detail = json_object_new ();
+ json_object_set_string_member (detail, "id", web_channel_id);
+ json_object_set_object_member (detail, "message", message);
+ node = json_node_new (JSON_NODE_OBJECT);
+ json_node_set_object (node, detail);
+
+ type = "WebChannelMessageToContent";
+ detail_str = json_to_string (node, FALSE);
+ script = g_strdup_printf ("let e = new window.CustomEvent(\"%s\", {detail: %s});"
+ "window.dispatchEvent(e);",
+ type, detail_str);
+
+ /* We don't expect any response from the server. */
+ webkit_web_view_run_javascript (sync_dialog->fxa_web_view, script, NULL, NULL, NULL);
+
+ g_free (script);
+ g_free (detail_str);
+ json_object_unref (detail);
+ json_node_unref (node);
+}
+
+static gboolean
+sync_parse_message_from_fxa_content (const char *message,
+ char **web_channel_id,
+ char **message_id,
+ char **command,
+ JsonObject **data,
+ char **error_msg)
+{
+ JsonNode *node;
+ JsonObject *object;
+ JsonObject *detail;
+ JsonObject *msg;
+ JsonObject *msg_data = NULL;
+ const char *type;
+ const char *channel_id;
+ const char *cmd;
+ const char *error = NULL;
+ gboolean success = FALSE;
+
+ g_assert (message);
+ g_assert (web_channel_id);
+ g_assert (message_id);
+ g_assert (command);
+ g_assert (data);
+ g_assert (error_msg);
+
+ /* Expected message format is:
+ * {
+ * type: "WebChannelMessageToChrome",
+ * detail: {
+ * id: <id> (string, the id of the WebChannel),
+ * message: {
+ * messageId: <messageId> (optional string, the message id),
+ * command: <command> (string, the message command),
+ * data: <data> (optional JSON object, the message data)
+ * }
+ * }
+ * }
+ */
+
+ node = json_from_string (message, NULL);
+ if (!node) {
+ error = "Message is not a valid JSON";
+ goto out_error;
+ }
+ object = json_node_get_object (node);
+ if (!object) {
+ error = "Message is not a JSON object";
+ goto out_error;
+ }
+ type = json_object_get_string_member (object, "type");
+ if (!type) {
+ error = "Message has missing or invalid 'type' member";
+ goto out_error;
+ } else if (strcmp (type, "WebChannelMessageToChrome")) {
+ error = "Message type is not WebChannelMessageToChrome";
+ goto out_error;
+ }
+ detail = json_object_get_object_member (object, "detail");
+ if (!detail) {
+ error = "Message has missing or invalid 'detail' member";
+ goto out_error;
+ }
+ channel_id = json_object_get_string_member (detail, "id");
+ if (!channel_id) {
+ error = "'Detail' object has missing or invalid 'id' member";
+ goto out_error;
+ }
+ msg = json_object_get_object_member (detail, "message");
+ if (!msg) {
+ error = "'Detail' object has missing or invalid 'message' member";
+ goto out_error;
+ }
+ cmd = json_object_get_string_member (msg, "command");
+ if (!cmd) {
+ error = "'Message' object has missing or invalid 'command' member";
+ goto out_error;
+ }
+
+ *web_channel_id = g_strdup (channel_id);
+ *command = g_strdup (cmd);
+ *message_id = json_object_has_member (msg, "messageId") ?
+ g_strdup (json_object_get_string_member (msg, "messageId")) :
+ NULL;
+ if (json_object_has_member (msg, "data"))
+ msg_data = json_object_get_object_member (msg, "data");
+ *data = msg_data ? json_object_ref (msg_data) : NULL;
+
+ success = TRUE;
+ *error_msg = NULL;
+ goto out_no_error;
+
+out_error:
+ *web_channel_id = NULL;
+ *command = NULL;
+ *message_id = NULL;
+ *error_msg = g_strdup (error);
+
+out_no_error:
+ json_node_unref (node);
+
+ return success;
+}
+
+static void
+sync_message_from_fxa_content_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *result,
+ EphyFirefoxSyncDialog *sync_dialog)
+{
+ JsonObject *data = NULL;
+ char *message = NULL;
+ char *web_channel_id = NULL;
+ char *message_id = NULL;
+ char *command = NULL;
+ char *error_msg = NULL;
+ gboolean is_error = FALSE;
+
+ message = jsc_value_to_string (webkit_javascript_result_get_js_value (result));
+ if (!message) {
+ g_warning ("Failed to get JavaScript result as string");
+ is_error = TRUE;
+ goto out;
+ }
+
+ if (!sync_parse_message_from_fxa_content (message, &web_channel_id,
+ &message_id, &command,
+ &data, &error_msg)) {
+ g_warning ("Failed to parse message from FxA Content Server: %s", error_msg);
+ is_error = TRUE;
+ goto out;
+ }
+
+ LOG ("WebChannelMessageToChrome: received %s command", command);
+
+ if (!g_strcmp0 (command, "fxaccounts:can_link_account")) {
+ /* Confirm a relink. Respond with {ok: true}. */
+ JsonObject *response = json_object_new ();
+ json_object_set_boolean_member (response, "ok", TRUE);
+ sync_message_to_fxa_content (sync_dialog, web_channel_id, command, message_id, response);
+ json_object_unref (response);
+ } else if (!g_strcmp0 (command, "fxaccounts:login")) {
+ /* Extract sync tokens and pass them to the sync service. */
+ const char *email = json_object_get_string_member (data, "email");
+ const char *uid = json_object_get_string_member (data, "uid");
+ const char *session_token = json_object_get_string_member (data, "sessionToken");
+ const char *key_fetch_token = json_object_get_string_member (data, "keyFetchToken");
+ const char *unwrap_kb = json_object_get_string_member (data, "unwrapBKey");
+
+ if (!email || !uid || !session_token || !key_fetch_token || !unwrap_kb) {
+ g_warning ("Message data has missing or invalid members");
+ is_error = TRUE;
+ goto out;
+ }
+ if (!json_object_has_member (data, "verified") ||
+ !JSON_NODE_HOLDS_VALUE (json_object_get_member (data, "verified"))) {
+ g_warning ("Message data has missing or invalid 'verified' member");
+ is_error = TRUE;
+ goto out;
+ }
+
+ ephy_sync_service_sign_in (ephy_shell_get_sync_service (ephy_shell_get_default ()),
+ email, uid, session_token, key_fetch_token, unwrap_kb);
+ }
+
+out:
+ if (data)
+ json_object_unref (data);
+ g_free (message);
+ g_free (web_channel_id);
+ g_free (message_id);
+ g_free (command);
+ g_free (error_msg);
+
+ if (is_error) {
+ sync_sign_in_details_show (sync_dialog, _("Something went wrong, please try again later."));
+ webkit_web_view_load_uri (sync_dialog->fxa_web_view, FXA_IFRAME_URL);
+ }
+}
+
+static void
+sync_open_webmail_clicked_cb (WebKitUserContentManager *manager,
+ WebKitJavascriptResult *result,
+ EphyFirefoxSyncDialog *sync_page)
+{
+ EphyShell *shell;
+ EphyEmbed *embed;
+ GtkWindow *window;
+ GtkWidget *prefs_dialog;
+ char *url;
+
+ url = jsc_value_to_string (webkit_javascript_result_get_js_value (result));
+ if (url) {
+ /* Open a new tab to the webmail URL. */
+ shell = ephy_shell_get_default ();
+ window = gtk_application_get_active_window (GTK_APPLICATION (shell));
+ embed = ephy_shell_new_tab (shell, EPHY_WINDOW (window),
+ NULL, EPHY_NEW_TAB_JUMP);
+ ephy_web_view_load_url (ephy_embed_get_web_view (embed), url);
+
+ /* Close the preferences dialog. */
+ prefs_dialog = gtk_widget_get_toplevel (GTK_WIDGET (sync_page));
+ gtk_widget_destroy (GTK_WIDGET (prefs_dialog));
+
+ g_free (url);
+ }
+}
+
+static void
+sync_setup_firefox_iframe (EphyFirefoxSyncDialog *sync_dialog)
+{
+ EphyEmbedShell *shell;
+ WebKitWebsiteDataManager *manager;
+ WebKitWebContext *embed_context;
+ WebKitWebContext *sync_context;
+ GtkWidget *frame;
+ const char *script;
+
+ if (!sync_dialog->fxa_web_view) {
+ script =
+ /* Handle sign-in messages from the FxA content server. */
+ "function handleToChromeMessage(event) {"
+ " let e = JSON.stringify({type: event.type, detail: event.detail});"
+ " window.webkit.messageHandlers.toChromeMessageHandler.postMessage(e);"
+ "};"
+ "window.addEventListener('WebChannelMessageToChrome', handleToChromeMessage);"
+ /* Handle open-webmail click event. */
+ "function handleOpenWebmailClick(event) {"
+ " if (event.target.id == 'open-webmail' && event.target.hasAttribute('href'))"
+ "
window.webkit.messageHandlers.openWebmailClickHandler.postMessage(event.target.getAttribute('href'));"
+ "};"
+ "var stage = document.getElementById('stage');"
+ "if (stage)"
+ " stage.addEventListener('click', handleOpenWebmailClick);";
+
+ sync_dialog->fxa_script = webkit_user_script_new (script,
+ WEBKIT_USER_CONTENT_INJECT_TOP_FRAME,
+ WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_END,
+ NULL, NULL);
+ sync_dialog->fxa_manager = webkit_user_content_manager_new ();
+ webkit_user_content_manager_add_script (sync_dialog->fxa_manager, sync_dialog->fxa_script);
+ g_signal_connect (sync_dialog->fxa_manager,
+ "script-message-received::toChromeMessageHandler",
+ G_CALLBACK (sync_message_from_fxa_content_cb),
+ sync_dialog);
+ g_signal_connect (sync_dialog->fxa_manager,
+ "script-message-received::openWebmailClickHandler",
+ G_CALLBACK (sync_open_webmail_clicked_cb),
+ sync_dialog);
+ webkit_user_content_manager_register_script_message_handler (sync_dialog->fxa_manager,
+ "toChromeMessageHandler");
+ webkit_user_content_manager_register_script_message_handler (sync_dialog->fxa_manager,
+ "openWebmailClickHandler");
+
+ shell = ephy_embed_shell_get_default ();
+ embed_context = ephy_embed_shell_get_web_context (shell);
+ manager = webkit_web_context_get_website_data_manager (embed_context);
+ sync_context = webkit_web_context_new_with_website_data_manager (manager);
+ webkit_web_context_set_preferred_languages (sync_context,
+ g_object_get_data (G_OBJECT (embed_context),
"preferred-languages"));
+
+ sync_dialog->fxa_web_view = WEBKIT_WEB_VIEW (g_object_new (WEBKIT_TYPE_WEB_VIEW,
+ "user-content-manager",
sync_dialog->fxa_manager,
+ "settings", ephy_embed_prefs_get_settings (),
+ "web-context", sync_context,
+ NULL));
+ gtk_widget_set_vexpand (GTK_WIDGET (sync_dialog->fxa_web_view), TRUE);
+ gtk_widget_set_visible (GTK_WIDGET (sync_dialog->fxa_web_view), TRUE);
+ frame = gtk_frame_new (NULL);
+ gtk_widget_set_visible (frame, TRUE);
+ gtk_container_add (GTK_CONTAINER (frame),
+ GTK_WIDGET (sync_dialog->fxa_web_view));
+ gtk_box_pack_start (GTK_BOX (sync_dialog->sync_firefox_iframe_box),
+ frame,
+ TRUE, TRUE, 0);
+
+ g_object_unref (sync_context);
+ }
+
+ webkit_web_view_load_uri (sync_dialog->fxa_web_view, FXA_IFRAME_URL);
+ gtk_widget_set_visible (sync_dialog->sync_firefox_iframe_label, FALSE);
+}
+
+static void
+on_sync_sign_out_button_clicked (GtkWidget *button,
+ EphyFirefoxSyncDialog *sync_dialog)
+{
+ EphySyncService *service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+
+ ephy_sync_service_sign_out (service);
+
+ /* Show Firefox Accounts iframe. */
+ sync_setup_firefox_iframe (sync_dialog);
+ gtk_widget_hide (sync_dialog->sync_firefox_account_box);
+ gtk_widget_hide (sync_dialog->sync_options_box);
+ gtk_widget_show (sync_dialog->sync_page_box);
+ hdy_action_row_set_subtitle (HDY_ACTION_ROW (sync_dialog->sync_firefox_account_row), NULL);
+}
+
+static void
+on_sync_sync_now_button_clicked (GtkWidget *button,
+ EphyFirefoxSyncDialog *sync_dialog)
+{
+ EphySyncService *service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+
+ gtk_widget_set_sensitive (button, FALSE);
+ ephy_sync_service_sync (service);
+}
+
+static void
+on_sync_synced_tabs_button_clicked (GtkWidget *button,
+ EphyFirefoxSyncDialog *sync_dialog)
+{
+ EphyOpenTabsManager *manager;
+ SyncedTabsDialog *synced_tabs_dialog;
+
+ manager = ephy_shell_get_open_tabs_manager (ephy_shell_get_default ());
+ synced_tabs_dialog = synced_tabs_dialog_new (manager);
+ gtk_window_set_transient_for (GTK_WINDOW (synced_tabs_dialog), GTK_WINDOW (sync_dialog));
+ gtk_window_set_modal (GTK_WINDOW (synced_tabs_dialog), TRUE);
+ gtk_window_present_with_time (GTK_WINDOW (synced_tabs_dialog), gtk_get_current_event_time ());
+}
+
+static void
+on_sync_device_name_change_button_clicked (GtkWidget *button,
+ EphyFirefoxSyncDialog *sync_dialog)
+{
+ gtk_widget_set_sensitive (GTK_WIDGET (sync_dialog->sync_device_name_entry), TRUE);
+ gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_change_button), FALSE);
+ gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_save_button), TRUE);
+ gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_cancel_button), TRUE);
+}
+
+static void
+on_sync_device_name_save_button_clicked (GtkWidget *button,
+ EphyFirefoxSyncDialog *sync_dialog)
+{
+ EphySyncService *service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+ const char *text;
+
+ text = gtk_entry_get_text (GTK_ENTRY (sync_dialog->sync_device_name_entry));
+ if (!g_strcmp0 (text, "")) {
+ char *name = ephy_sync_utils_get_device_name ();
+ gtk_entry_set_text (GTK_ENTRY (sync_dialog->sync_device_name_entry), name);
+ g_free (name);
+ } else {
+ ephy_sync_service_update_device_name (service, text);
+ }
+
+ gtk_widget_set_sensitive (GTK_WIDGET (sync_dialog->sync_device_name_entry), FALSE);
+ gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_change_button), TRUE);
+ gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_save_button), FALSE);
+ gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_cancel_button), FALSE);
+}
+
+static void
+on_sync_device_name_cancel_button_clicked (GtkWidget *button,
+ EphyFirefoxSyncDialog *sync_dialog)
+{
+ char *name;
+
+ name = ephy_sync_utils_get_device_name ();
+ gtk_entry_set_text (GTK_ENTRY (sync_dialog->sync_device_name_entry), name);
+
+ gtk_widget_set_sensitive (GTK_WIDGET (sync_dialog->sync_device_name_entry), FALSE);
+ gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_change_button), TRUE);
+ gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_save_button), FALSE);
+ gtk_widget_set_visible (GTK_WIDGET (sync_dialog->sync_device_name_cancel_button), FALSE);
+
+ g_free (name);
+}
+
+static void
+prefs_sync_page_finalize (GObject *object)
+{
+ EphyFirefoxSyncDialog *sync_dialog = EPHY_FIREFOX_SYNC_DIALOG (object);
+
+ if (sync_dialog->fxa_web_view != NULL) {
+ webkit_user_content_manager_unregister_script_message_handler (sync_dialog->fxa_manager,
+ "toChromeMessageHandler");
+ webkit_user_content_manager_unregister_script_message_handler (sync_dialog->fxa_manager,
+ "openWebmailClickHandler");
+ webkit_user_script_unref (sync_dialog->fxa_script);
+ g_object_unref (sync_dialog->fxa_manager);
+ }
+
+ G_OBJECT_CLASS (ephy_firefox_sync_dialog_parent_class)->finalize (object);
+}
+
+static void
+ephy_firefox_sync_dialog_class_init (EphyFirefoxSyncDialogClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ "/org/gnome/epiphany/gtk/firefox-sync-dialog.ui");
+
+ object_class->finalize = prefs_sync_page_finalize;
+
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_page_box);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_firefox_iframe_box);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_firefox_iframe_label);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_firefox_account_box);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_firefox_account_row);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_options_box);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_bookmarks_switch);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_passwords_switch);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_history_switch);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_open_tabs_switch);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_frequency_row);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_now_button);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, synced_tabs_button);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_device_name_entry);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_device_name_change_button);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_device_name_save_button);
+ gtk_widget_class_bind_template_child (widget_class, EphyFirefoxSyncDialog, sync_device_name_cancel_button);
+
+ gtk_widget_class_bind_template_callback (widget_class, on_sync_sign_out_button_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, on_sync_sync_now_button_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, on_sync_synced_tabs_button_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, on_sync_device_name_change_button_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, on_sync_device_name_save_button_clicked);
+ gtk_widget_class_bind_template_callback (widget_class, on_sync_device_name_cancel_button_clicked);
+}
+
+static gboolean
+sync_frequency_get_mapping (GValue *value,
+ GVariant *variant,
+ gpointer user_data)
+{
+ uint minutes = g_variant_get_uint32 (variant);
+
+ for (gint i = 0; i < (gint)G_N_ELEMENTS (sync_frequency_minutes); i++) {
+ if (sync_frequency_minutes[i] != minutes)
+ continue;
+
+ g_value_set_int (value, i);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GVariant *
+sync_frequency_set_mapping (const GValue *value,
+ const GVariantType *expected_type,
+ gpointer user_data)
+{
+ gint i = g_value_get_int (value);
+
+ if (i >= (gint)G_N_ELEMENTS (sync_frequency_minutes))
+ return NULL;
+
+ return g_variant_new_uint32 (sync_frequency_minutes[i]);
+}
+
+static GListModel *
+create_sync_frequency_minutes_model ()
+{
+ GListStore *list_store = g_list_store_new (HDY_TYPE_VALUE_OBJECT);
+ HdyValueObject *obj;
+ g_auto (GValue) value = G_VALUE_INIT;
+ guint i;
+
+ g_value_init (&value, G_TYPE_UINT);
+
+ for (i = 0; i < G_N_ELEMENTS (sync_frequency_minutes); i++) {
+ g_value_set_uint (&value, sync_frequency_minutes[i]);
+ obj = hdy_value_object_new (&value);
+ g_list_store_insert (list_store, i, obj);
+ g_clear_object (&obj);
+ }
+
+ return G_LIST_MODEL (list_store);
+}
+
+static gchar *
+get_sync_frequency_minutes_name (HdyValueObject *value)
+{
+ return g_strdup_printf ("%u min", g_value_get_uint (hdy_value_object_get_value (value)));
+}
+
+void
+ephy_firefox_sync_dialog_setup (EphyFirefoxSyncDialog *sync_dialog)
+{
+ EphySyncService *service = ephy_shell_get_sync_service (ephy_shell_get_default ());
+ GSettings *sync_settings = ephy_settings_get (EPHY_PREFS_SYNC_SCHEMA);
+ char *user = ephy_sync_utils_get_sync_user ();
+ char *name = ephy_sync_utils_get_device_name ();
+ g_autoptr (GListModel) sync_frequency_minutes_model = create_sync_frequency_minutes_model ();
+
+ gtk_entry_set_text (GTK_ENTRY (sync_dialog->sync_device_name_entry), name);
+
+ if (!user) {
+ sync_setup_firefox_iframe (sync_dialog);
+ gtk_widget_hide (sync_dialog->sync_firefox_account_box);
+ gtk_widget_hide (sync_dialog->sync_options_box);
+ } else {
+ sync_set_last_sync_time (sync_dialog);
+ hdy_preferences_row_set_title (HDY_PREFERENCES_ROW (sync_dialog->sync_firefox_account_row), user);
+ gtk_widget_hide (sync_dialog->sync_page_box);
+ }
+
+ g_settings_bind (sync_settings,
+ EPHY_PREFS_SYNC_BOOKMARKS_ENABLED,
+ sync_dialog->sync_bookmarks_switch,
+ "active",
+ G_SETTINGS_BIND_DEFAULT);
+ g_settings_bind (sync_settings,
+ EPHY_PREFS_SYNC_PASSWORDS_ENABLED,
+ sync_dialog->sync_passwords_switch,
+ "active",
+ G_SETTINGS_BIND_DEFAULT);
+ g_settings_bind (sync_settings,
+ EPHY_PREFS_SYNC_HISTORY_ENABLED,
+ sync_dialog->sync_history_switch,
+ "active",
+ G_SETTINGS_BIND_DEFAULT);
+ g_settings_bind (sync_settings,
+ EPHY_PREFS_SYNC_OPEN_TABS_ENABLED,
+ sync_dialog->sync_open_tabs_switch,
+ "active",
+ G_SETTINGS_BIND_DEFAULT);
+
+ hdy_combo_row_bind_name_model (HDY_COMBO_ROW (sync_dialog->sync_frequency_row),
+ sync_frequency_minutes_model,
+ (HdyComboRowGetNameFunc)get_sync_frequency_minutes_name,
+ NULL,
+ NULL);
+ g_settings_bind_with_mapping (sync_settings,
+ EPHY_PREFS_SYNC_FREQUENCY,
+ sync_dialog->sync_frequency_row,
+ "selected-index",
+ G_SETTINGS_BIND_DEFAULT,
+ sync_frequency_get_mapping,
+ sync_frequency_set_mapping,
+ NULL, NULL);
+
+ g_object_bind_property (sync_dialog->sync_open_tabs_switch, "active",
+ sync_dialog->synced_tabs_button, "sensitive",
+ G_BINDING_SYNC_CREATE);
+
+ g_signal_connect_object (service, "sync-secrets-store-finished",
+ G_CALLBACK (sync_secrets_store_finished_cb),
+ sync_dialog, 0);
+ g_signal_connect_object (service, "sync-sign-in-error",
+ G_CALLBACK (sync_sign_in_error_cb),
+ sync_dialog, 0);
+ g_signal_connect_object (service, "sync-finished",
+ G_CALLBACK (sync_finished_cb),
+ sync_dialog, 0);
+ g_signal_connect_object (sync_dialog->sync_bookmarks_switch, "notify::active",
+ G_CALLBACK (sync_collection_toggled_cb),
+ sync_dialog, 0);
+ g_signal_connect_object (sync_dialog->sync_passwords_switch, "notify::active",
+ G_CALLBACK (sync_collection_toggled_cb),
+ sync_dialog, 0);
+ g_signal_connect_object (sync_dialog->sync_history_switch, "notify::active",
+ G_CALLBACK (sync_collection_toggled_cb),
+ sync_dialog, 0);
+ g_signal_connect_object (sync_dialog->sync_open_tabs_switch, "notify::active",
+ G_CALLBACK (sync_collection_toggled_cb),
+ sync_dialog, 0);
+
+ g_free (user);
+ g_free (name);
+}
+
+static void
+ephy_firefox_sync_dialog_init (EphyFirefoxSyncDialog *sync_dialog)
+{
+ gtk_widget_init_template (GTK_WIDGET (sync_dialog));
+ ephy_firefox_sync_dialog_setup (sync_dialog);
+}
+
+GtkWidget *
+ephy_firefox_sync_dialog_new ()
+{
+ return GTK_WIDGET (g_object_new (EPHY_TYPE_FIREFOX_SYNC_DIALOG, NULL));
+}
diff --git a/src/ephy-firefox-sync-dialog.h b/src/ephy-firefox-sync-dialog.h
new file mode 100644
index 000000000..9e20ed484
--- /dev/null
+++ b/src/ephy-firefox-sync-dialog.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Copyright © 2020 Epiphany Developers
+ *
+ * This file is part of Epiphany.
+ *
+ * Epiphany is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Epiphany is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Epiphany. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <glib-object.h>
+#include <handy.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_FIREFOX_SYNC_DIALOG (ephy_firefox_sync_dialog_get_type ())
+
+G_DECLARE_FINAL_TYPE (EphyFirefoxSyncDialog, ephy_firefox_sync_dialog, EPHY, FIREFOX_SYNC_DIALOG, HdyWindow)
+
+GtkWidget *ephy_firefox_sync_dialog_new ();
+
+G_END_DECLS
diff --git a/src/ephy-shell.c b/src/ephy-shell.c
index 01854f42b..2ee5684f4 100644
--- a/src/ephy-shell.c
+++ b/src/ephy-shell.c
@@ -28,6 +28,7 @@
#include "ephy-embed-container.h"
#include "ephy-embed-utils.h"
#include "ephy-file-helpers.h"
+#include "ephy-firefox-sync-dialog.h"
#include "ephy-gui.h"
#include "ephy-header-bar.h"
#include "ephy-history-dialog.h"
@@ -62,6 +63,7 @@ struct _EphyShell {
EphyOpenTabsManager *open_tabs_manager;
GNetworkMonitor *network_monitor;
GtkWidget *history_dialog;
+ GtkWidget *firefox_sync_dialog;
GObject *prefs_dialog;
EphyShellStartupContext *local_startup_context;
EphyShellStartupContext *remote_startup_context;
@@ -241,6 +243,18 @@ show_history (GSimpleAction *action,
window_cmd_show_history (NULL, NULL, EPHY_WINDOW (window));
}
+static void
+show_firefox_sync (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GtkWindow *window;
+
+ window = gtk_application_get_active_window (GTK_APPLICATION (ephy_shell));
+
+ window_cmd_show_firefox_sync (NULL, NULL, EPHY_WINDOW (window));
+}
+
static void
show_preferences (GSimpleAction *action,
GVariant *parameter,
@@ -349,6 +363,7 @@ static GActionEntry app_entries[] = {
{ "export-bookmarks", export_bookmarks, NULL, NULL, NULL },
{ "import-passwords", import_passwords, NULL, NULL, NULL },
{ "history", show_history, NULL, NULL, NULL },
+ { "firefox-sync-dialog", show_firefox_sync, NULL, NULL, NULL },
{ "preferences", show_preferences, NULL, NULL, NULL },
{ "shortcuts", show_shortcuts, NULL, NULL, NULL },
{ "help", show_help, NULL, NULL, NULL },
@@ -1216,6 +1231,25 @@ ephy_shell_get_history_dialog (EphyShell *shell)
return shell->history_dialog;
}
+/**
+ * ephy_shell_get_firefox_sync_dialog:
+ *
+ * Return value: (transfer none):
+ **/
+GtkWidget *
+ephy_shell_get_firefox_sync_dialog (EphyShell *shell)
+{
+ if (shell->firefox_sync_dialog == NULL) {
+ shell->firefox_sync_dialog = ephy_firefox_sync_dialog_new ();
+ g_signal_connect (shell->firefox_sync_dialog,
+ "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &shell->firefox_sync_dialog);
+ }
+
+ return shell->firefox_sync_dialog;
+}
+
/**
* ephy_shell_get_prefs_dialog:
*
diff --git a/src/ephy-shell.h b/src/ephy-shell.h
index e7a63f944..ed39f695c 100644
--- a/src/ephy-shell.h
+++ b/src/ephy-shell.h
@@ -79,54 +79,55 @@ typedef struct {
guint32 user_time;
} EphyShellStartupContext;
-EphyShell *ephy_shell_get_default (void);
-
-EphyEmbed *ephy_shell_new_tab (EphyShell *shell,
- EphyWindow *parent_window,
- EphyEmbed *previous_embed,
- EphyNewTabFlags flags);
-
-EphyEmbed *ephy_shell_new_tab_full (EphyShell *shell,
- const char *title,
- WebKitWebView *related_view,
- EphyWindow *parent_window,
- EphyEmbed *previous_embed,
- EphyNewTabFlags flags,
- guint32 user_time);
-
-EphySession *ephy_shell_get_session (EphyShell *shell);
-GNetworkMonitor *ephy_shell_get_net_monitor (EphyShell *shell);
-EphyBookmarksManager *ephy_shell_get_bookmarks_manager (EphyShell *shell);
-EphyHistoryManager *ephy_shell_get_history_manager (EphyShell *shell);
-EphyOpenTabsManager *ephy_shell_get_open_tabs_manager (EphyShell *shell);
-EphySyncService *ephy_shell_get_sync_service (EphyShell *shell);
-
-GtkWidget *ephy_shell_get_history_dialog (EphyShell *shell);
-GObject *ephy_shell_get_prefs_dialog (EphyShell *shell);
-
-guint ephy_shell_get_n_windows (EphyShell *shell);
-gboolean ephy_shell_close_all_windows (EphyShell *shell);
-
-void ephy_shell_try_quit (EphyShell *shell);
-
-void ephy_shell_open_uris (EphyShell *shell,
- const char **uris,
- EphyStartupMode startup_mode,
- guint32 user_time);
-
-void ephy_shell_set_startup_context (EphyShell *shell,
- EphyShellStartupContext *ctx);
-EphyShellStartupContext *ephy_shell_startup_context_new (EphyStartupMode startup_mode,
- char *session_filename,
- char **arguments,
- guint32 user_time);
-
-void _ephy_shell_create_instance (EphyEmbedShellMode mode);
-
-void ephy_shell_send_notification (EphyShell *shell,
- gchar *id,
- GNotification *notification);
-
-gboolean ephy_shell_startup_finished (EphyShell *shell);
+EphyShell *ephy_shell_get_default (void);
+
+EphyEmbed *ephy_shell_new_tab (EphyShell *shell,
+ EphyWindow *parent_window,
+ EphyEmbed *previous_embed,
+ EphyNewTabFlags flags);
+
+EphyEmbed *ephy_shell_new_tab_full (EphyShell *shell,
+ const char *title,
+ WebKitWebView *related_view,
+ EphyWindow *parent_window,
+ EphyEmbed *previous_embed,
+ EphyNewTabFlags flags,
+ guint32 user_time);
+
+EphySession *ephy_shell_get_session (EphyShell *shell);
+GNetworkMonitor *ephy_shell_get_net_monitor (EphyShell *shell);
+EphyBookmarksManager *ephy_shell_get_bookmarks_manager (EphyShell *shell);
+EphyHistoryManager *ephy_shell_get_history_manager (EphyShell *shell);
+EphyOpenTabsManager *ephy_shell_get_open_tabs_manager (EphyShell *shell);
+EphySyncService *ephy_shell_get_sync_service (EphyShell *shell);
+
+GtkWidget *ephy_shell_get_history_dialog (EphyShell *shell);
+GtkWidget *ephy_shell_get_firefox_sync_dialog (EphyShell *shell);
+GObject *ephy_shell_get_prefs_dialog (EphyShell *shell);
+
+guint ephy_shell_get_n_windows (EphyShell *shell);
+gboolean ephy_shell_close_all_windows (EphyShell *shell);
+
+void ephy_shell_try_quit (EphyShell *shell);
+
+void ephy_shell_open_uris (EphyShell *shell,
+ const char **uris,
+ EphyStartupMode startup_mode,
+ guint32 user_time);
+
+void ephy_shell_set_startup_context (EphyShell *shell,
+ EphyShellStartupContext *ctx);
+EphyShellStartupContext *ephy_shell_startup_context_new (EphyStartupMode startup_mode,
+ char *session_filename,
+ char **arguments,
+ guint32 user_time);
+
+void _ephy_shell_create_instance (EphyEmbedShellMode mode);
+
+void ephy_shell_send_notification (EphyShell *shell,
+ gchar *id,
+ GNotification *notification);
+
+gboolean ephy_shell_startup_finished (EphyShell *shell);
G_END_DECLS
diff --git a/src/meson.build b/src/meson.build
index c2a63ff2e..09697cafa 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -26,6 +26,7 @@ libephymain_sources = [
'ephy-desktop-utils.c',
'ephy-encoding-dialog.c',
'ephy-encoding-row.c',
+ 'ephy-firefox-sync-dialog.c',
'ephy-header-bar.c',
'ephy-history-dialog.c',
'ephy-link.c',
diff --git a/src/resources/epiphany.gresource.xml b/src/resources/epiphany.gresource.xml
index d65cdc58d..1a2466c16 100644
--- a/src/resources/epiphany.gresource.xml
+++ b/src/resources/epiphany.gresource.xml
@@ -22,6 +22,7 @@
<file preprocess="xml-stripblanks" compressed="true">gtk/data-view.ui</file>
<file preprocess="xml-stripblanks" compressed="true">gtk/encoding-dialog.ui</file>
<file preprocess="xml-stripblanks" compressed="true">gtk/encoding-row.ui</file>
+ <file preprocess="xml-stripblanks" compressed="true">gtk/firefox-sync-dialog.ui</file>
<file preprocess="xml-stripblanks" compressed="true">gtk/history-dialog.ui</file>
<file preprocess="xml-stripblanks" compressed="true">gtk/lang-row.ui</file>
<file preprocess="xml-stripblanks" compressed="true">gtk/notebook-context-menu.ui</file>
diff --git a/src/resources/gtk/firefox-sync-dialog.ui b/src/resources/gtk/firefox-sync-dialog.ui
new file mode 100644
index 000000000..1227113fc
--- /dev/null
+++ b/src/resources/gtk/firefox-sync-dialog.ui
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.0"/>
+ <template class="EphyFirefoxSyncDialog" parent="HdyWindow">
+ <property name="visible">True</property>
+ <property name="modal">True</property>
+ <property name="window_position">center-on-parent</property>
+ <property name="default-width">640</property>
+ <property name="default-height">800</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">dialog</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="HdyHeaderBar">
+ <property name="visible">True</property>
+ <property name="decoration-layout">:close</property>
+ <property name="show-close-button">True</property>
+ <property name="title" translatable="yes">Firefox Sync</property>
+ </object>
+ </child>
+ <child>
+ <object class="HdyClamp">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="HdyPreferencesGroup" id="sync_page_box">
+ <property name="description" translatable="yes">Sign in with your Firefox account to
sync your data with Web and Firefox on other computers. Web is not Firefox and is not produced or endorsed by
Mozilla.</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkBox" id="sync_firefox_iframe_box">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkLabel" id="sync_firefox_iframe_label">
+ <property name="visible">False</property>
+ <property name="halign">start</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="HdyPreferencesGroup" id="sync_firefox_account_box">
+ <property name="title" translatable="yes">Firefox Account</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="HdyActionRow" id="sync_firefox_account_row">
+ <property name="subtitle" translatable="yes">Logged in</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkButton" id="sync_sign_out_button">
+ <property name="label" translatable="yes">Sign _out</property>
+ <property name="use-underline">True</property>
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ <signal name="clicked" handler="on_sync_sign_out_button_clicked"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="HdyPreferencesGroup" id="sync_options_box">
+ <property name="title" translatable="yes">Sync Options</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="HdyActionRow">
+ <property name="activatable_widget">sync_bookmarks_switch</property>
+ <property name="title" translatable="yes">Sync _Bookmarks</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkSwitch" id="sync_bookmarks_switch">
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="HdyActionRow">
+ <property name="activatable_widget">sync_passwords_switch</property>
+ <property name="title" translatable="yes">Sync _Passwords</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkSwitch" id="sync_passwords_switch">
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="HdyActionRow">
+ <property name="activatable_widget">sync_history_switch</property>
+ <property name="title" translatable="yes">Sync _History</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkSwitch" id="sync_history_switch">
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="HdyActionRow">
+ <property name="activatable_widget">sync_open_tabs_switch</property>
+ <property name="title" translatable="yes">Sync Open _Tabs</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkSwitch" id="sync_open_tabs_switch">
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="synced_tabs_button">
+ <property name="label" translatable="yes">S_ynced tabs</property>
+ <property name="use-underline">True</property>
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ <signal name="clicked" handler="on_sync_synced_tabs_button_clicked"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="HdyComboRow" id="sync_frequency_row">
+ <property name="title" translatable="yes">Frequency</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkSeparator">
+ <property name="margin_bottom">8</property>
+ <property name="margin_top">8</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="sync_now_button">
+ <property name="label" translatable="yes">Sync _now</property>
+ <property name="use-underline">True</property>
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ <signal name="clicked" handler="on_sync_sync_now_button_clicked"/>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="HdyActionRow">
+ <property name="activatable">False</property>
+ <property name="title" translatable="yes">Device name</property>
+ <property name="use_underline">True</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkButton" id="sync_device_name_cancel_button">
+ <property name="label" translatable="yes">_Cancel</property>
+ <property name="use-underline">True</property>
+ <property name="valign">center</property>
+ <property name="visible">False</property>
+ <signal name="clicked" handler="on_sync_device_name_cancel_button_clicked"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="sync_device_name_save_button">
+ <property name="label" translatable="yes">_Save</property>
+ <property name="use-underline">True</property>
+ <property name="valign">center</property>
+ <property name="visible">False</property>
+ <signal name="clicked" handler="on_sync_device_name_save_button_clicked"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="sync_device_name_change_button">
+ <property name="label" translatable="yes">_Change</property>
+ <property name="use-underline">True</property>
+ <property name="valign">center</property>
+ <property name="visible">True</property>
+ <signal name="clicked" handler="on_sync_device_name_change_button_clicked"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkEntry" id="sync_device_name_entry">
+ <property name="sensitive">False</property>
+ <property name="margin-start">12</property>
+ <property name="margin-end">12</property>
+ <property name="margin-top">8</property>
+ <property name="margin-bottom">8</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+ <object class="GtkSizeGroup">
+ <property name="mode">horizontal</property>
+ <widgets>
+ <widget name="sync_sign_out_button"/>
+ <widget name="synced_tabs_button"/>
+ <widget name="sync_now_button"/>
+ <widget name="sync_device_name_change_button"/>
+ </widgets>
+ </object>
+</interface>
diff --git a/src/resources/gtk/page-menu-popover.ui b/src/resources/gtk/page-menu-popover.ui
index 6942c99a2..366b2ddc5 100644
--- a/src/resources/gtk/page-menu-popover.ui
+++ b/src/resources/gtk/page-menu-popover.ui
@@ -386,6 +386,22 @@
<property name="visible">True</property>
</object>
</child>
+ <child>
+ <object class="GtkSeparator">
+ <property name="orientation">horizontal</property>
+ <property name="margin-top">6</property>
+ <property name="margin-bottom">6</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkModelButton">
+ <property name="can_focus">True</property>
+ <property name="text" translatable="yes">Firefox _Sync</property>
+ <property name="action-name">app.firefox-sync-dialog</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
</object>
<packing>
<property name="submenu">import_export</property>
diff --git a/src/window-commands.c b/src/window-commands.c
index 31460d0a7..c4ed583d5 100644
--- a/src/window-commands.c
+++ b/src/window-commands.c
@@ -870,6 +870,21 @@ window_cmd_show_history (GSimpleAction *action,
gtk_window_present_with_time (GTK_WINDOW (dialog), gtk_get_current_event_time ());
}
+void
+window_cmd_show_firefox_sync (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GtkWidget *dialog;
+
+ dialog = ephy_shell_get_firefox_sync_dialog (ephy_shell_get_default ());
+
+ if (GTK_WINDOW (user_data) != gtk_window_get_transient_for (GTK_WINDOW (dialog)))
+ gtk_window_set_transient_for (GTK_WINDOW (dialog),
+ GTK_WINDOW (user_data));
+ gtk_window_present_with_time (GTK_WINDOW (dialog), gtk_get_current_event_time ());
+}
+
void
window_cmd_show_preferences (GSimpleAction *action,
GVariant *parameter,
diff --git a/src/window-commands.h b/src/window-commands.h
index cab9e75f9..353251e7f 100644
--- a/src/window-commands.h
+++ b/src/window-commands.h
@@ -41,6 +41,9 @@ void window_cmd_export_bookmarks (GSimpleAction *action,
void window_cmd_show_history (GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
+void window_cmd_show_firefox_sync (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
void window_cmd_show_preferences (GSimpleAction *action,
GVariant *parameter,
gpointer user_data);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]