[gnome-contacts] Add first run dialog



commit b0b19005abc37900f7e8b8d002aa2c0e5ffaab7f
Author: Alexander Larsson <alexl redhat com>
Date:   Fri Jan 27 16:21:21 2012 +0100

    Add first run dialog

 configure.ac                          |    2 +
 src/Makefile.am                       |   15 ++-
 src/contacts-app.vala                 |   42 +++++++-
 src/contacts-esd-setup.c              |   45 +++++++-
 src/contacts-esd-setup.h              |    5 +
 src/contacts-list-pane.vala           |   54 +--------
 src/contacts-setup-window.vala        |  213 +++++++++++++++++++++++++++++++++
 src/contacts-store.vala               |   13 ++
 src/org.gnome.Contacts.gschema.xml.in |   10 ++
 vapi/custom.vapi                      |    6 +
 10 files changed, 347 insertions(+), 58 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 315386b..06faef1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,6 +20,8 @@ AC_PROG_CC
 AM_PROG_VALAC([0.14.0])
 AC_PROG_INSTALL
 
+GLIB_GSETTINGS
+
 # i18n stuff
 IT_PROG_INTLTOOL([0.40])
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 18b1e9f..d6ff529 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,10 +35,19 @@ vala_sources = \
 	contacts-avatar-menu.vala \
 	contacts-contact-frame.vala \
 	contacts-revealer.vala \
+	contacts-setup-window.vala \
 	contacts-window.vala \
 	main.vala \
 	$(NULL)
 
+gsettingsschema_in_files = org.gnome.Contacts.gschema.xml.in
+gsettings_SCHEMAS = $(gsettingsschema_in_files:.xml.in=.xml)
+.PRECIOUS: $(gsettings_SCHEMAS)
+
+ INTLTOOL_XML_NOMERGE_RULE@
+
+ GSETTINGS_RULES@
+
 contact-resources.c: contacts.gresource.xml app-menu.ui
 	$(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $(srcdir)/contacts.gresource.xml \
 		--target=$@ --sourcedir=$(srcdir) --c-name contacts --generate-source
@@ -52,9 +61,13 @@ gnome_contacts_SOURCES = \
 
 gnome_contacts_LDADD = $(CONTACTS_LIBS) -lm
 
-CLEANFILES = $(vala_sources:.vala=.c) *.vapi *.stamp
+CLEANFILES = \
+	$(vala_sources:.vala=.c) \
+	$(gsettings_SCHEMAS) \
+	*.vapi *.stamp
 
 EXTRA_DIST = \
 	gtk-notification.h   \
+	$(gsettingsschema_in_files)     \
 	contacts-esd-setup.h \
 	$(NULL)
diff --git a/src/contacts-app.vala b/src/contacts-app.vala
index 2a7bbad..e0588e8 100644
--- a/src/contacts-app.vala
+++ b/src/contacts-app.vala
@@ -20,6 +20,7 @@ using Gtk;
 using Folks;
 
 public class Contacts.App : Gtk.Application {
+  public GLib.Settings settings;
   public Contacts.Window window;
   public static App app;
   public Store contacts_store;
@@ -304,8 +305,46 @@ public class Contacts.App : Gtk.Application {
     base.startup ();
   }
 
+  private void show_setup () {
+    avoid_goa_workaround = true;
+    var setup = new SetupWindow ();
+    setup.set_application (this);
+    setup.destroy.connect ( () => {
+	avoid_goa_workaround = false;
+	setup.destroy ();
+	if (setup.succeeded)
+	  this.activate ();
+      });
+    setup.show ();
+  }
+
   public override void activate () {
     if (window == null) {
+      if (!settings.get_boolean ("did-initial-setup")) {
+	if (contacts_store.is_prepared)
+	  show_setup ();
+	else {
+	  hold ();
+	  ulong id = 0;
+	  uint id2 = 0;
+	  id = contacts_store.prepared.connect (() => {
+	      show_setup ();
+	      contacts_store.disconnect (id);
+	      Source.remove (id2);
+	      release ();
+	    });
+	  // Wait at most 0.5 seconds to show the window
+	  id2 = Timeout.add (500, () => {
+	      show_setup ();
+	      contacts_store.disconnect (id);
+	      release ();
+	      return false;
+	});
+	}
+
+	return;
+      }
+
       create_window ();
 
       // We delay the initial show a tiny bit so most contacts are loaded when we show
@@ -381,7 +420,7 @@ public class Contacts.App : Gtk.Application {
     });
     overlay.add_overlay (notification);
   }
-  
+
   public override int command_line (ApplicationCommandLine command_line) {
     var args = command_line.get_arguments ();
     unowned string[] _args = args;
@@ -413,5 +452,6 @@ public class Contacts.App : Gtk.Application {
   public App () {
     Object (application_id: "org.gnome.Contacts", flags: ApplicationFlags.HANDLES_COMMAND_LINE);
     this.app = this;
+    settings = new GLib.Settings ("org.gnome.Contacts");
   }
 }
diff --git a/src/contacts-esd-setup.c b/src/contacts-esd-setup.c
index 9efeae6..858a654 100644
--- a/src/contacts-esd-setup.c
+++ b/src/contacts-esd-setup.c
@@ -33,7 +33,8 @@ static gboolean created_local = FALSE;
 static GMainLoop *goa_loop;
 static GoaClient *goa_client;
 static GHashTable *accounts;
-static ESourceList *contacts_source_list;
+ESourceList *contacts_source_list;
+gboolean contacts_avoid_goa_workaround = FALSE;
 
 /* This whole file is a gigantic hack that copies and pastes stuff from
  * evolution to create evolution-data-server addressbooks as needed.
@@ -176,7 +177,7 @@ ensure_local_addressbook (void)
 
   client = e_book_client_new_system (NULL);
   if (client != NULL) {
-    contacts_eds_local_store = g_strdup (e_source_peek_uid (e_client_get_source (client)));
+    contacts_eds_local_store = g_strdup (e_source_peek_uid (e_client_get_source (E_CLIENT (client))));
     g_object_unref (client);
     return TRUE;
   }
@@ -345,7 +346,7 @@ online_accounts_account_added_cb (GoaClient *goa_client,
 		// a while to let a running evo instance
 		// create the account, this is a lame
 		// fix for the race condition
-		if (goa_loop == NULL) {
+		if (!contacts_avoid_goa_workaround) {
 		  struct SyncData *data = g_new (struct SyncData, 1);
 		  data->uid = g_strdup (evo_id);
 		  data->goa_object = g_object_ref (goa_object);
@@ -559,6 +560,7 @@ void contacts_ensure_eds_accounts (void)
   created_local = ensure_local_addressbook ();
 
   goa_loop = g_main_loop_new (NULL, TRUE);
+  contacts_avoid_goa_workaround = TRUE;
 
   online_accounts_connect ();
 
@@ -567,11 +569,48 @@ void contacts_ensure_eds_accounts (void)
 
   g_main_loop_unref (goa_loop);
   goa_loop = NULL;
+  contacts_avoid_goa_workaround = FALSE;
 
   contacts_source_list = NULL;
   e_book_get_addressbooks (&contacts_source_list, NULL);
 }
 
+gboolean contacts_has_goa_account (void)
+{
+  GSList *list_a;
+
+  list_a = e_source_list_peek_groups (contacts_source_list);
+  while (list_a != NULL) {
+    ESourceGroup *source_group;
+    GSList *list_b;
+
+    source_group = E_SOURCE_GROUP (list_a->data);
+    list_a = g_slist_next (list_a);
+
+    list_b = e_source_group_peek_sources (source_group);
+
+    while (list_b != NULL) {
+      ESource *source;
+      const gchar *property;
+      const gchar *uid;
+      GList *match;
+
+      source = E_SOURCE (list_b->data);
+      list_b = g_slist_next (list_b);
+
+      uid = e_source_peek_uid (source);
+      property = e_source_get_property (source, GOA_KEY);
+
+      if (property == NULL)
+	continue;
+
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
 
 /* This is an enourmous hack to find google eds contacts that are
    in the "My Contacts" system group. */
diff --git a/src/contacts-esd-setup.h b/src/contacts-esd-setup.h
index 83ed38c..8b4f8e4 100644
--- a/src/contacts-esd-setup.h
+++ b/src/contacts-esd-setup.h
@@ -1,6 +1,11 @@
+#include <libedataserver/e-source-list.h>
+
 void contacts_ensure_eds_accounts (void);
 extern char *contacts_eds_local_store;
 const char *contacts_lookup_esource_name_by_uid (const char *uid);
 const char *contacts_lookup_esource_name_by_uid_for_contact (const char *uid);
 gboolean contacts_esource_uid_is_google (const char *uid);
 char *eds_personal_google_group_name (void);
+gboolean contacts_has_goa_account (void);
+extern ESourceList *contacts_source_list;
+extern gboolean contacts_avoid_goa_workaround;
diff --git a/src/contacts-list-pane.vala b/src/contacts-list-pane.vala
index 0fa2249..4620602 100644
--- a/src/contacts-list-pane.vala
+++ b/src/contacts-list-pane.vala
@@ -25,8 +25,6 @@ public class Contacts.ListPane : Frame {
   private ViewWidget list;
   public Entry filter_entry;
   private uint filter_entry_changed_id;
-  private ulong non_empty_id;
-  private EventBox empty_box;
   private bool ignore_selection_change;
   private Revealer search_revealer;
   private bool search_visible;
@@ -156,64 +154,14 @@ public class Contacts.ListPane : Frame {
     list.show_all ();
     scrolled.set_no_show_all (true);
 
-    empty_box = new EventBox ();
-    empty_box.set_hexpand (false);
-    empty_box.set_vexpand (true);
-    empty_box.set_halign (Align.FILL);
-    Gdk.RGBA white = {1, 1, 1, 1};
-    empty_box.override_background_color (StateFlags.NORMAL, white);
-
-    var empty_grid = new Grid ();
-    empty_grid.set_row_spacing (8);
-    empty_grid.set_orientation (Orientation.VERTICAL);
-    empty_grid.set_valign (Align.CENTER);
-
-    var image = new Image.from_icon_name ("avatar-default-symbolic", IconSize.DIALOG);
-    image.get_style_context ().add_class ("dim-label");
-    empty_grid.add (image);
-
-    var label = new Label (_("Connect to an account,\nimport or add contacts"));
-    label.xalign = 0.5f;
-    label.set_hexpand (true);
-    label.set_halign (Align.CENTER);
-    empty_grid.add (label);
-
-    var button = new Button.with_label (_("Online Accounts"));
-    button.set_halign (Align.CENTER);
-    empty_grid.add (button);
-    button.clicked.connect ( (button) => {
-	try {
-	  Process.spawn_command_line_async ("gnome-control-center online-accounts");
-	}
-	catch (Error e) {
-	  // TODO: Show error dialog
-	}
-      });
-
-    empty_box.add (empty_grid);
-    empty_box.show_all ();
-    empty_box.set_no_show_all (true);
-
     grid.add (search_revealer);
     grid.add (scrolled);
-    grid.add (empty_box);
 
     this.show_all ();
     search_revealer.set_no_show_all (true);
     search_revealer.hide ();
 
-    if (contacts_store.is_empty ()) {
-      empty_box.show ();
-      non_empty_id = contacts_store.added.connect ( (c) => {
-	  empty_box.hide ();
-	  scrolled.show ();
-	  contacts_store.disconnect (non_empty_id);
-	  non_empty_id = 0;
-	});
-    } else {
-      scrolled.show ();
-    }
-
+    scrolled.show ();
   }
 
   public void select_contact (Contact contact, bool ignore_change = false) {
diff --git a/src/contacts-setup-window.vala b/src/contacts-setup-window.vala
new file mode 100644
index 0000000..9f494cc
--- /dev/null
+++ b/src/contacts-setup-window.vala
@@ -0,0 +1,213 @@
+/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2011 Alexander Larsson <alexl redhat com>
+ *
+ * This program 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Gtk;
+using Folks;
+
+public class Contacts.SetupWindow : Gtk.Window {
+  public bool succeeded;
+  private ulong source_list_changed_id;
+  public Label title_label;
+  public Grid content_grid;
+  ToolButton select_button;
+  ListStore list_store;
+  TreeView tree_view;
+
+  public void update_content () {
+    foreach (var w in content_grid.get_children ())
+      w.destroy ();
+
+    var l = new Label ("");
+    l.set_markup ("<b>%s</b>".printf (_("Welcome to Contacts!")));
+    content_grid.add (l);
+
+    Button goa_button;
+
+    if (has_goa_account ()) {
+      select_button.show ();
+
+      tree_view = new TreeView ();
+      var store = new ListStore (2, typeof (string), typeof (Folks.PersonaStore));
+      list_store = store;
+      tree_view.set_model (store);
+      tree_view.set_headers_visible (false);
+      tree_view.get_selection ().set_mode (SelectionMode.BROWSE);
+
+      var column = new Gtk.TreeViewColumn ();
+      tree_view.append_column (column);
+
+      var renderer = new Gtk.CellRendererText ();
+      column.pack_start (renderer, false);
+      column.add_attribute (renderer, "text", 0);
+
+      var scrolled = new ScrolledWindow(null, null);
+      scrolled.set_size_request (340, 240);
+      scrolled.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
+      scrolled.set_vexpand (true);
+      scrolled.set_shadow_type (ShadowType.IN);
+      scrolled.add (tree_view);
+
+      content_grid.add (scrolled);
+
+      TreeIter iter;
+      foreach (var persona_store in Contact.get_eds_address_books ()) {
+	var name = Contact.format_persona_store_name (persona_store);
+	store.append (out iter);
+	store.set (iter, 0, name, 1, persona_store);
+	if (persona_store == App.app.contacts_store.aggregator.primary_store) {
+	  tree_view.get_selection ().select_iter (iter);
+	}
+      }
+
+      goa_button = new Button.with_label (_("Online Account Settings"));
+      content_grid.add (goa_button);
+
+    } else {
+      select_button.hide ();
+      l = new Label (_("Setup an online account or use a local address book"));
+      content_grid.add (l);
+
+      goa_button = new Button.with_label (_("Online Accounts"));
+      content_grid.add (goa_button);
+
+      var b = new Button.with_label (_("Use Local Address Book"));
+      content_grid.add (b);
+
+      b.clicked.connect ( () => {
+	  var source = eds_source_list.peek_source_by_uid (eds_local_store);
+	  select_source (source);
+	});
+    }
+
+    goa_button.clicked.connect ( (button) => {
+	try {
+	  update_content ();
+	  Process.spawn_command_line_async ("gnome-control-center online-accounts");
+	}
+	catch (Error e) {
+	  // TODO: Show error dialog
+	}
+      });
+
+    content_grid.show_all ();
+  }
+
+  private void select_source (E.Source source) {
+    try {
+      E.BookClient.set_default_source (source);
+    } catch {
+      warning ("Failed to set address book");
+    }
+    succeeded = true;
+    App.app.settings.set_boolean ("did-initial-setup", true);
+    destroy ();
+  }
+
+
+  public SetupWindow () {
+    var grid = new Grid ();
+    this.add (grid);
+    this.set_title (_("Contacts Setup"));
+    this.set_default_size (640, 480);
+
+    this.hide_titlebar_when_maximized = true;
+
+    var toolbar = new Toolbar ();
+    toolbar.set_icon_size (IconSize.MENU);
+    toolbar.get_style_context ().add_class (STYLE_CLASS_MENUBAR);
+    toolbar.set_vexpand (false);
+    toolbar.set_hexpand (true);
+    grid.attach (toolbar, 0, 0, 1, 1);
+
+    var cancel_button = new ToolButton (null, _("Cancel"));
+    cancel_button.is_important = true;
+    toolbar.add (cancel_button);
+    cancel_button.clicked.connect ( (button) => {
+	this.destroy ();
+      });
+
+    var item = new ToolItem ();
+    title_label = new Label ("");
+    title_label.set_markup ("<b>%s</b>".printf (_("Contacts Setup")));
+    title_label.set_no_show_all (true);
+    item.add (title_label);
+    item.set_expand (true);
+    toolbar.add (item);
+
+    select_button = new ToolButton (null, _("Select"));
+    select_button.is_important = true;
+    select_button.set_no_show_all (true);
+    toolbar.add (select_button);
+    select_button.clicked.connect ( (button) => {
+	PersonaStore selected_store;
+	TreeIter iter;
+
+	if (tree_view.get_selection() .get_selected (null, out iter)) {
+	  list_store.get (iter, 1, out selected_store);
+
+	  var e_store = selected_store as Edsf.PersonaStore;
+	  select_source (e_store.source);
+	}
+      });
+
+    var frame = new Frame (null);
+    frame.get_style_context ().add_class ("contacts-content");
+
+    var box = new EventBox ();
+    box.set_hexpand (true);
+    box.set_vexpand (true);
+    box.get_style_context ().add_class ("contacts-main-view");
+    box.get_style_context ().add_class ("view");
+
+    frame.add (box);
+    grid.attach (frame, 0, 1, 1, 1);
+
+    content_grid = new Grid ();
+    content_grid.set_orientation (Orientation.VERTICAL);
+    content_grid.set_halign (Align.CENTER);
+    content_grid.set_row_spacing (8);
+    box.add (content_grid);
+
+    update_content ();
+
+    source_list_changed_id = eds_source_list.changed.connect ( () => {
+	update_content ();
+      });
+
+    grid.show_all ();
+  }
+
+  public override void destroy () {
+    if (source_list_changed_id != 0) {
+      eds_source_list.disconnect (source_list_changed_id);
+      source_list_changed_id = 0;
+    }
+    base.destroy ();
+  }
+
+  public override bool window_state_event (Gdk.EventWindowState e) {
+    base.window_state_event (e);
+
+    if ((e.new_window_state & Gdk.WindowState.MAXIMIZED) != 0)
+      title_label.show ();
+    else
+      title_label.hide ();
+
+    return false;
+  }
+}
diff --git a/src/contacts-store.vala b/src/contacts-store.vala
index 45b8d83..f66ae3b 100644
--- a/src/contacts-store.vala
+++ b/src/contacts-store.vala
@@ -26,6 +26,7 @@ public class Contacts.Store : GLib.Object {
   public signal void added (Contact c);
   public signal void removed (Contact c);
   public signal void quiescent ();
+  public signal void prepared ();
 
   public IndividualAggregator aggregator { get; private set; }
   public BackendStore backend_store { get; private set; }
@@ -45,6 +46,10 @@ public class Contacts.Store : GLib.Object {
     get { return this.aggregator.is_quiescent; }
   }
 
+  public bool is_prepared {
+    get { return this.aggregator.is_prepared; }
+  }
+
   public void refresh () {
     foreach (var c in contacts) {
       c.queue_changed (true);
@@ -144,6 +149,14 @@ public class Contacts.Store : GLib.Object {
 	    return false;
 	  });
       });
+
+    aggregator.notify["is-prepared"].connect ( (obj, pspec) => {
+	Idle.add( () => {
+	    this.prepared ();
+	    return false;
+	  });
+      });
+
     aggregator.individuals_changed_detailed.connect ( (changes) =>   {
 	// Note: Apparently the current implementation doesn't necessarily pick
 	// up unlinked individual as replacements.
diff --git a/src/org.gnome.Contacts.gschema.xml.in b/src/org.gnome.Contacts.gschema.xml.in
new file mode 100644
index 0000000..3987072
--- /dev/null
+++ b/src/org.gnome.Contacts.gschema.xml.in
@@ -0,0 +1,10 @@
+<schemalist>
+  <schema id="org.gnome.Contacts" path="/org/gnome/Contacts/" gettext-domain="gnome-contacts">
+    <key name="did-initial-setup" type="b">
+      <default>false</default>
+      <_summary>First-time setup done.</_summary>
+      <_description>Set to true when the user ran the first-time setup wizard.</_description>
+    </key>
+  </schema>
+
+</schemalist>
diff --git a/vapi/custom.vapi b/vapi/custom.vapi
index eace183..d947f9b 100644
--- a/vapi/custom.vapi
+++ b/vapi/custom.vapi
@@ -37,6 +37,12 @@ namespace Contacts {
 	public static bool esource_uid_is_google (string uid);
 	[CCode (cname = "eds_personal_google_group_name")]
 	public static unowned string? eds_personal_google_group_name ();
+	[CCode (cname = "contacts_has_goa_account")]
+	public static bool has_goa_account ();
+	[CCode (cname = "contacts_source_list")]
+	public static E.SourceList eds_source_list;
+	[CCode (cname = "contacts_avoid_goa_workaround")]
+	public static bool avoid_goa_workaround;
 }
 
 [CCode (cprefix = "Gtk", lower_case_cprefix = "gtk_", cheader_filename = "gtk-notification.h")]



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