[epiphany/wip/sync: 2/2] [wip] Implement history sync



commit 2255ac9d68526e2ecf121d542b97829e48b61c05
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date:   Wed May 24 00:20:07 2017 +0300

    [wip] Implement history sync

 data/org.gnome.epiphany.gschema.xml |   15 ++
 lib/ephy-prefs.h                    |    3 +
 lib/sync/ephy-history-manager.c     |  216 +++++++++++++++++++++
 lib/sync/ephy-history-manager.h     |   36 ++++
 lib/sync/ephy-history-record.c      |  365 +++++++++++++++++++++++++++++++++++
 lib/sync/ephy-history-record.h      |   41 ++++
 lib/sync/meson.build                |    2 +
 7 files changed, 678 insertions(+), 0 deletions(-)
---
diff --git a/data/org.gnome.epiphany.gschema.xml b/data/org.gnome.epiphany.gschema.xml
index 3635eed..e354664 100644
--- a/data/org.gnome.epiphany.gschema.xml
+++ b/data/org.gnome.epiphany.gschema.xml
@@ -322,6 +322,21 @@
                        <summary>Initial sync or normal sync</summary>
                        <description>TRUE if passwords collection needs to be synced for the first time, 
FALSE otherwise.</description>
                </key>
+               <key type="b" name="sync-history-enabled">
+                       <default>false</default>
+                       <summary>Enable history sync</summary>
+                       <description>TRUE if history collection should be synced, FALSE 
otherwise.</description>
+               </key>
+               <key type="d" name="sync-history-time">
+                       <default>0</default>
+                       <summary>History sync timestamp</summary>
+                       <description>The timestamp at which last history sync was made.</description>
+               </key>
+               <key type="b" name="sync-history-initial">
+                       <default>true</default>
+                       <summary>Initial sync or normal sync</summary>
+                       <description>TRUE if history collection needs to be synced for the first time, FALSE 
otherwise.</description>
+               </key>
        </schema>
        <enum id="org.gnome.Epiphany.Permission">
                <value nick="undecided" value="-1"/>
diff --git a/lib/ephy-prefs.h b/lib/ephy-prefs.h
index b6be084..fde68f9 100644
--- a/lib/ephy-prefs.h
+++ b/lib/ephy-prefs.h
@@ -162,6 +162,9 @@ static const char * const ephy_prefs_web_schema[] = {
 #define EPHY_PREFS_SYNC_PASSWORDS_ENABLED "sync-passwords-enabled"
 #define EPHY_PREFS_SYNC_PASSWORDS_TIME    "sync-passwords-time"
 #define EPHY_PREFS_SYNC_PASSWORDS_INITIAL "sync-passwords-initial"
+#define EPHY_PREFS_SYNC_HISTORY_ENABLED   "sync-history-enabled"
+#define EPHY_PREFS_SYNC_HISTORY_TIME      "sync-history-time"
+#define EPHY_PREFS_SYNC_HISTORY_INITIAL   "sync-history-initial"
 
 static struct {
   const char *schema;
diff --git a/lib/sync/ephy-history-manager.c b/lib/sync/ephy-history-manager.c
new file mode 100644
index 0000000..646f5c1
--- /dev/null
+++ b/lib/sync/ephy-history-manager.c
@@ -0,0 +1,216 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2017 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  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 "config.h"
+#include "ephy-history-manager.h"
+
+#include "ephy-settings.h"
+#include "ephy-synchronizable-manager.h"
+
+struct _EphyHistoryManager {
+  GObject parent_instance;
+
+  EphyHistoryService *service;
+};
+
+static void ephy_synchronizable_manager_iface_init (EphySynchronizableManagerInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EphyHistoryManager, ephy_history_manager, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (EPHY_TYPE_SYNCHRONIZABLE_MANAGER,
+                                                ephy_synchronizable_manager_iface_init))
+
+enum {
+  PROP_0,
+  PROP_HISTORY_SERVICE,
+  LAST_PROP
+};
+
+static GParamSpec *obj_properties[LAST_PROP];
+
+static void
+ephy_history_manager_set_property (GObject      *object,
+                                   guint         prop_id,
+                                   const GValue *value,
+                                   GParamSpec   *pspec)
+{
+  EphyHistoryManager *self = EPHY_HISTORY_MANAGER (object);
+
+  switch (prop_id) {
+    case PROP_HISTORY_SERVICE:
+      g_clear_object (&self->service);
+      self->service = g_object_ref (g_value_get_object (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+ephy_history_manager_get_property (GObject    *object,
+                                   guint       prop_id,
+                                   GValue     *value,
+                                   GParamSpec *pspec)
+{
+  EphyHistoryManager *self = EPHY_HISTORY_MANAGER (object);
+
+  switch (prop_id) {
+    case PROP_HISTORY_SERVICE:
+      g_value_set_object (value, self->service);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+ephy_history_manager_dispose (GObject *object)
+{
+  EphyHistoryManager *self = EPHY_HISTORY_MANAGER (object);
+
+  g_clear_object (&self->service);
+
+  G_OBJECT_CLASS (ephy_history_manager_parent_class)->dispose (object);
+}
+
+static void
+ephy_history_manager_class_init (EphyHistoryManagerClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = ephy_history_manager_set_property;
+  object_class->get_property = ephy_history_manager_get_property;
+  object_class->dispose = ephy_history_manager_dispose;
+
+  obj_properties[PROP_HISTORY_SERVICE] =
+    g_param_spec_object ("history-service",
+                         "History service",
+                         "History Service",
+                         EPHY_TYPE_HISTORY_SERVICE,
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, LAST_PROP, obj_properties);
+}
+
+static void
+ephy_history_manager_init (EphyHistoryManager *self)
+{
+}
+
+EphyHistoryManager *
+ephy_history_manager_new (EphyHistoryService *service)
+{
+  return EPHY_HISTORY_MANAGER (g_object_new (EPHY_TYPE_HISTORY_MANAGER,
+                                             "history-service", service,
+                                             NULL));
+}
+
+static const char *
+synchronizable_manager_get_collection_name (EphySynchronizableManager *manager)
+{
+  gboolean sync_with_firefox = g_settings_get_boolean (EPHY_SETTINGS_SYNC,
+                                                       EPHY_PREFS_SYNC_WITH_FIREFOX);
+
+  return sync_with_firefox ? "history" : "ephy-history";
+}
+
+static GType
+synchronizable_manager_get_synchronizable_type (EphySynchronizableManager *manager)
+{
+  return EPHY_TYPE_HISTORY_RECORD;
+}
+
+static gboolean
+synchronizable_manager_is_initial_sync (EphySynchronizableManager *manager)
+{
+  return g_settings_get_boolean (EPHY_SETTINGS_SYNC,
+                                 EPHY_PREFS_SYNC_HISTORY_INITIAL);
+}
+
+static void
+synchronizable_manager_set_is_initial_sync (EphySynchronizableManager *manager,
+                                            gboolean                   is_initial)
+{
+  g_settings_set_boolean (EPHY_SETTINGS_SYNC,
+                          EPHY_PREFS_SYNC_HISTORY_INITIAL,
+                          is_initial);
+}
+
+static double
+synchronizable_manager_get_sync_time (EphySynchronizableManager *manager)
+{
+  return g_settings_get_double (EPHY_SETTINGS_SYNC,
+                                EPHY_PREFS_SYNC_HISTORY_TIME);
+}
+
+static void
+synchronizable_manager_set_sync_time (EphySynchronizableManager *manager,
+                                      double                     sync_time)
+{
+  g_settings_set_double (EPHY_SETTINGS_SYNC,
+                         EPHY_PREFS_SYNC_HISTORY_TIME,
+                         sync_time);
+}
+
+static void
+synchronizable_manager_add (EphySynchronizableManager *manager,
+                            EphySynchronizable        *synchronizable)
+{
+  /* TODO: Implement this. */
+}
+
+static void
+synchronizable_manager_remove (EphySynchronizableManager *manager,
+                               EphySynchronizable        *synchronizable)
+{
+  /* TODO: Implement this. */
+}
+
+static void
+synchronizable_manager_save (EphySynchronizableManager *manager,
+                             EphySynchronizable        *synchronizable)
+{
+  /* TODO: Implement this. */
+}
+
+static void
+synchronizable_manager_merge (EphySynchronizableManager              *manager,
+                              gboolean                                is_initial,
+                              GSList                                 *remotes_deleted,
+                              GSList                                 *remotes_updated,
+                              EphySynchronizableManagerMergeCallback  callback,
+                              gpointer                                user_data)
+{
+  /* TODO: Implement this. */
+}
+
+static void
+ephy_synchronizable_manager_iface_init (EphySynchronizableManagerInterface *iface)
+{
+  iface->get_collection_name = synchronizable_manager_get_collection_name;
+  iface->get_synchronizable_type = synchronizable_manager_get_synchronizable_type;
+  iface->is_initial_sync = synchronizable_manager_is_initial_sync;
+  iface->set_is_initial_sync = synchronizable_manager_set_is_initial_sync;
+  iface->get_sync_time = synchronizable_manager_get_sync_time;
+  iface->set_sync_time = synchronizable_manager_set_sync_time;
+  iface->add = synchronizable_manager_add;
+  iface->remove = synchronizable_manager_remove;
+  iface->save = synchronizable_manager_save;
+  iface->merge = synchronizable_manager_merge;
+}
diff --git a/lib/sync/ephy-history-manager.h b/lib/sync/ephy-history-manager.h
new file mode 100644
index 0000000..30f688c
--- /dev/null
+++ b/lib/sync/ephy-history-manager.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2017 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  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 "ephy-history-record.h"
+#include "ephy-history-service.h"
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_HISTORY_MANAGER (ephy_history_manager_get_type ())
+
+G_DECLARE_FINAL_TYPE (EphyHistoryManager, ephy_history_manager, EPHY, HISTORY_MANAGER, GObject)
+
+EphyHistoryManager *ephy_history_manager_new (EphyHistoryService *service);
+
+G_END_DECLS
diff --git a/lib/sync/ephy-history-record.c b/lib/sync/ephy-history-record.c
new file mode 100644
index 0000000..5ba00ab
--- /dev/null
+++ b/lib/sync/ephy-history-record.c
@@ -0,0 +1,365 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2017 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  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 "config.h"
+#include "ephy-history-record.h"
+
+#include "ephy-synchronizable.h"
+
+struct _EphyHistoryRecord {
+  GObject parent_instance;
+
+  char      *id;
+  char      *title;
+  char      *uri;
+  GSequence *visits;
+};
+
+static void json_serializable_iface_init (JsonSerializableIface *iface);
+static void ephy_synchronizable_iface_init (EphySynchronizableInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EphyHistoryRecord, ephy_history_record, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (JSON_TYPE_SERIALIZABLE,
+                                                json_serializable_iface_init)
+                         G_IMPLEMENT_INTERFACE (EPHY_TYPE_SYNCHRONIZABLE,
+                                                ephy_synchronizable_iface_init))
+
+enum {
+  PROP_0,
+  PROP_ID,
+  PROP_TITLE,
+  PROP_URI,
+  PROP_VISITS,
+  LAST_PROP
+};
+
+static GParamSpec *obj_properties[LAST_PROP];
+
+typedef struct {
+  gint64 timestamp; /* UNIX time in microseconds. */
+  guint type;       /* Transition type.*/
+} EphyHistoryRecordVisit;
+
+static EphyHistoryRecordVisit *
+ephy_history_record_visit_new (gint64 timestamp,
+                               guint  type)
+{
+  EphyHistoryRecordVisit *visit;
+
+  visit = g_slice_new (EphyHistoryRecordVisit);
+  visit->timestamp = timestamp;
+  visit->type = type;
+
+  return visit;
+}
+
+static void
+ephy_history_record_visit_free (EphyHistoryRecordVisit *visit)
+{
+  g_assert (visit);
+
+  g_slice_free (EphyHistoryRecordVisit, visit);
+}
+
+static int
+ephy_history_record_visit_compare (EphyHistoryRecordVisit *visit1,
+                                   EphyHistoryRecordVisit *visit2,
+                                   gpointer                user_data)
+{
+  g_assert (visit1);
+  g_assert (visit2);
+
+  /* We keep visits sorted in descending order by timestamp. */
+  return visit2->timestamp - visit1->timestamp;
+}
+
+static void
+ephy_history_record_set_property (GObject      *object,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+  EphyHistoryRecord *self = EPHY_HISTORY_RECORD (object);
+
+  switch (prop_id) {
+    case PROP_ID:
+      g_free (self->id);
+      self->id = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_TITLE:
+      g_free (self->title);
+      self->title = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_URI:
+      g_free (self->uri);
+      self->uri = g_strdup (g_value_get_string (value));
+      break;
+    case PROP_VISITS:
+      if (self->visits)
+        g_sequence_free (self->visits);
+      self->visits = g_value_get_pointer (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+ephy_history_record_get_property (GObject    *object,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+  EphyHistoryRecord *self = EPHY_HISTORY_RECORD (object);
+
+  switch (prop_id) {
+    case PROP_ID:
+      g_value_set_string (value, self->id);
+      break;
+    case PROP_TITLE:
+      g_value_set_string (value, self->title);
+      break;
+    case PROP_URI:
+      g_value_set_string (value, self->uri);
+      break;
+    case PROP_VISITS:
+      g_value_set_pointer (value, self->visits);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+ephy_history_record_dispose (GObject *object)
+{
+  EphyHistoryRecord *self = EPHY_HISTORY_RECORD (object);
+
+  g_clear_pointer (&self->id, g_free);
+  g_clear_pointer (&self->title, g_free);
+  g_clear_pointer (&self->uri, g_free);
+  g_clear_pointer (&self->visits, g_sequence_free);
+
+  G_OBJECT_CLASS (ephy_history_record_parent_class)->dispose (object);
+}
+
+static void
+ephy_history_record_class_init (EphyHistoryRecordClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = ephy_history_record_set_property;
+  object_class->get_property = ephy_history_record_get_property;
+  object_class->dispose = ephy_history_record_dispose;
+
+  obj_properties[PROP_ID] =
+    g_param_spec_string ("id",
+                         "Id",
+                         "Id of the history record",
+                         "Default id",
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+  obj_properties[PROP_TITLE] =
+    g_param_spec_string ("title",
+                         "Title",
+                         "Title of the history record",
+                         "Default title",
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+  obj_properties[PROP_URI] =
+    g_param_spec_string ("histUri",
+                         "History URI",
+                         "URI of the history record",
+                         "Default history uri",
+                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+  obj_properties[PROP_VISITS] =
+    g_param_spec_pointer ("visits",
+                          "Visits",
+                          "An array of how and when URI of the history record was visited",
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, LAST_PROP, obj_properties);
+}
+
+static void
+ephy_history_record_init (EphyHistoryRecord *self)
+{
+}
+
+EphyHistoryRecord *
+ephy_history_record_new (const char *id,
+                         const char *title,
+                         const char *uri,
+                         gint64      last_visit_time)
+{
+  EphyHistoryRecordVisit *visit;
+  GSequence *visits;
+
+  /* We only use TRANSITION_LINK for now. */
+  visit = ephy_history_record_visit_new (last_visit_time, 1);
+  visits = g_sequence_new ((GDestroyNotify)ephy_history_record_visit_free);
+  g_sequence_prepend (visits, visit);
+
+  return EPHY_HISTORY_RECORD (g_object_new (EPHY_TYPE_HISTORY_RECORD,
+                                            "id", id,
+                                            "title", title,
+                                            "histUri", uri,
+                                            "visits", visits,
+                                            NULL));
+}
+
+const char *
+ephy_history_record_get_id (EphyHistoryRecord *self)
+{
+  g_return_val_if_fail (EPHY_IS_HISTORY_RECORD (self), NULL);
+
+  return self->id;
+}
+
+const char *
+ephy_history_record_get_title (EphyHistoryRecord *self)
+{
+  g_return_val_if_fail (EPHY_IS_HISTORY_RECORD (self), NULL);
+
+  return self->title;
+}
+
+const char *
+ephy_history_record_get_uri (EphyHistoryRecord *self)
+{
+  g_return_val_if_fail (EPHY_IS_HISTORY_RECORD (self), NULL);
+
+  return self->uri;
+}
+
+gint64
+ephy_history_record_get_last_visit_time (EphyHistoryRecord *self)
+{
+  EphyHistoryRecordVisit *visit;
+
+  g_return_val_if_fail (EPHY_IS_HISTORY_RECORD (self), -1);
+  g_return_val_if_fail (self->visits, -1);
+
+  if (g_sequence_is_empty (self->visits))
+    return -1;
+
+  /* Visits are sorted in descending order by date. */
+  visit = (EphyHistoryRecordVisit *)g_sequence_get (g_sequence_get_begin_iter (self->visits));
+
+  return visit->timestamp;
+}
+
+static JsonNode *
+serializable_serialize_property (JsonSerializable *serializable,
+                                 const char       *name,
+                                 const GValue     *value,
+                                 GParamSpec       *pspec)
+{
+  if (!g_strcmp0 (name, "visits")) {
+    JsonNode *node;
+    JsonArray *array;
+    GSequence *visits;
+    GSequenceIter *it;
+
+    node = json_node_new (JSON_NODE_ARRAY);
+    array = json_array_new ();
+    visits = g_value_get_pointer (value);
+
+    if (visits != NULL) {
+      for (it = g_sequence_get_begin_iter (visits); !g_sequence_iter_is_end (it); it = g_sequence_iter_next 
(it)) {
+        EphyHistoryRecordVisit *visit = g_sequence_get (it);
+        JsonObject *object = json_object_new ();
+        json_object_set_int_member (object, "date", visit->timestamp);
+        json_object_set_int_member (object, "type", visit->type);
+        json_array_add_object_element (array, object);
+      }
+    }
+
+    json_node_set_array (node, array);
+
+    return node;
+  }
+
+  return json_serializable_default_serialize_property (serializable, name, value, pspec);;
+}
+
+static gboolean
+serializable_deserialize_property (JsonSerializable *serializable,
+                                   const char       *name,
+                                   GValue           *value,
+                                   GParamSpec       *pspec,
+                                   JsonNode         *node)
+{
+  if (!g_strcmp0 (name, "visits")) {
+    JsonArray *array;
+    GSequence *visits;
+
+    array = json_node_get_array (node);
+    visits = g_sequence_new ((GDestroyNotify)ephy_history_record_visit_free);
+
+    for (guint i = 0; i < json_array_get_length (array); i++) {
+      JsonObject *object = json_node_get_object (json_array_get_element (array, i));
+      gint64 timestamp = json_object_get_int_member (object, "date");
+      guint type = json_object_get_int_member (object, "type");
+      EphyHistoryRecordVisit *visit = ephy_history_record_visit_new (timestamp, type);
+      g_sequence_insert_sorted (visits, visit, (GCompareDataFunc)ephy_history_record_visit_compare, NULL);
+    }
+
+    g_value_set_pointer (value, visits);
+
+    return TRUE;
+  }
+
+  return json_serializable_default_deserialize_property (serializable, name, value, pspec, node);
+}
+
+static void
+json_serializable_iface_init (JsonSerializableIface *iface)
+{
+  iface->serialize_property = serializable_serialize_property;
+  iface->deserialize_property = serializable_deserialize_property;
+}
+
+static const char *
+synchronizable_get_id (EphySynchronizable *synchronizable)
+{
+  return ephy_history_record_get_id (EPHY_HISTORY_RECORD (synchronizable));
+}
+
+static double
+synchronizable_get_server_time_modified (EphySynchronizable *synchronizable)
+{
+  /* TODO: Implement this. */
+  return 0;
+}
+
+static void
+synchronizable_set_server_time_modified (EphySynchronizable *synchronizable,
+                                         double              server_time_modified)
+{
+  /* TODO: Implement this. */
+}
+
+static void
+ephy_synchronizable_iface_init (EphySynchronizableInterface *iface)
+{
+  iface->get_id = synchronizable_get_id;
+  iface->get_server_time_modified = synchronizable_get_server_time_modified;
+  iface->set_server_time_modified = synchronizable_set_server_time_modified;
+  iface->to_bso = ephy_synchronizable_default_to_bso;
+}
diff --git a/lib/sync/ephy-history-record.h b/lib/sync/ephy-history-record.h
new file mode 100644
index 0000000..25ebcff
--- /dev/null
+++ b/lib/sync/ephy-history-record.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright © 2017 Gabriel Ivascu <ivascu gabriel59 gmail com>
+ *
+ *  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 <json-glib/json-glib.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_HISTORY_RECORD (ephy_history_record_get_type ())
+
+G_DECLARE_FINAL_TYPE (EphyHistoryRecord, ephy_history_record, EPHY, HISTORY_RECORD, GObject)
+
+EphyHistoryRecord *ephy_history_record_new          (const char *id,
+                                                     const char *title,
+                                                     const char *history_uri,
+                                                     gint64      last_visit_time);
+const char *ephy_history_record_get_id              (EphyHistoryRecord *self);
+const char *ephy_history_record_get_title           (EphyHistoryRecord *self);
+const char *ephy_history_record_get_uri             (EphyHistoryRecord *self);
+gint64      ephy_history_record_get_last_visit_time (EphyHistoryRecord *self);
+
+G_END_DECLS
diff --git a/lib/sync/meson.build b/lib/sync/meson.build
index 658c17c..b728c39 100644
--- a/lib/sync/meson.build
+++ b/lib/sync/meson.build
@@ -1,4 +1,6 @@
 libephysync_sources = [
+  'ephy-history-manager.c',
+  'ephy-history-record.c',
   'ephy-password-manager.c',
   'ephy-password-record.c',
   'ephy-sync-crypto.c',


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