[gitg] Rework the dash view implementation



commit 8786f4f068526ac8c62b5c164c15c95b58ace1eb
Author: Jesse van den Kieboom <jessevdk gnome org>
Date:   Tue Aug 4 17:35:16 2015 +0200

    Rework the dash view implementation
    
    - Make the dash view more self contained
    - Move the open and clone menu options in an action bar
    - Add cloning authentication/credentials

 gitg/gitg-dash-view.vala                           |  229 ++++++++++++++++++--
 gitg/gitg-remote-manager.vala                      |    9 +-
 gitg/gitg-window.vala                              |   66 +------
 gitg/resources/gitg-resources.xml                  |    1 +
 gitg/resources/ui/gitg-dash-view.ui                |   63 ++++++
 gitg/resources/ui/gitg-menus.ui                    |   10 -
 gitg/resources/ui/gitg-window.ui                   |   19 +--
 libgitg-ext/gitg-ext-application.vala              |    2 +
 libgitg/gitg-credentials-manager.vala              |  100 ++++++----
 libgitg/gitg-remote.vala                           |    9 -
 libgitg/gitg-repository-list-box.vala              |  147 +++----------
 .../resources/ui/gitg-repository-list-box-row.ui   |    1 +
 po/POTFILES.in                                     |    2 +
 po/POTFILES.skip                                   |    1 +
 14 files changed, 394 insertions(+), 265 deletions(-)
---
diff --git a/gitg/gitg-dash-view.vala b/gitg/gitg-dash-view.vala
index 91d239c..07c8e1d 100644
--- a/gitg/gitg-dash-view.vala
+++ b/gitg/gitg-dash-view.vala
@@ -20,7 +20,8 @@
 namespace Gitg
 {
 
-class DashView : RepositoryListBox, GitgExt.UIElement, GitgExt.Activity, GitgExt.Selectable, 
GitgExt.Searchable
+[GtkTemplate (ui = "/org/gnome/gitg/ui/gitg-dash-view.ui")]
+class DashView : Gtk.Grid, GitgExt.UIElement, GitgExt.Activity, GitgExt.Selectable, GitgExt.Searchable
 {
        private const string version = Config.VERSION;
 
@@ -29,11 +30,17 @@ class DashView : RepositoryListBox, GitgExt.UIElement, GitgExt.Activity, GitgExt
        private bool d_search_enabled;
        private bool d_setting_mode;
 
+       [GtkChild( name = "repository_list_box" )]
+       private RepositoryListBox d_repository_list_box;
+
+       [GtkChild( name = "action_bar" )]
+       private Gtk.ActionBar d_action_bar;
+
        public GitgExt.SelectionMode selectable_mode
        {
                get
                {
-                       switch (mode)
+                       switch (d_repository_list_box.mode)
                        {
                        case Gitg.SelectionMode.NORMAL:
                                return GitgExt.SelectionMode.NORMAL;
@@ -56,10 +63,12 @@ class DashView : RepositoryListBox, GitgExt.UIElement, GitgExt.Activity, GitgExt
                        switch (value)
                        {
                        case GitgExt.SelectionMode.NORMAL:
-                               mode = Gitg.SelectionMode.NORMAL;
+                               d_repository_list_box.mode = Gitg.SelectionMode.NORMAL;
+                               d_action_bar.visible = true;
                                break;
                        case GitgExt.SelectionMode.SELECTION:
-                               mode = Gitg.SelectionMode.SELECTION;
+                               d_repository_list_box.mode = Gitg.SelectionMode.SELECTION;
+                               d_action_bar.visible = false;
                                break;
                        }
 
@@ -103,7 +112,7 @@ class DashView : RepositoryListBox, GitgExt.UIElement, GitgExt.Activity, GitgExt
                        if (d_search_text != value)
                        {
                                d_search_text = value;
-                               filter_text(d_search_text);
+                               update_search_text();
                        }
                }
 
@@ -125,15 +134,22 @@ class DashView : RepositoryListBox, GitgExt.UIElement, GitgExt.Activity, GitgExt
                        if (d_search_enabled != value)
                        {
                                d_search_enabled = value;
+                               update_search_text();
+                       }
+               }
+       }
 
-                               if (d_search_enabled)
-                               {
-                                       filter_text(d_search_text);
-                               }
-                               else
-                               {
-                                       filter_text(null);
-                               }
+       private void update_search_text()
+       {
+               if (d_repository_list_box != null)
+               {
+                       if (d_search_enabled && d_search_text != "")
+                       {
+                               d_repository_list_box.filter_text(d_search_text);
+                       }
+                       else
+                       {
+                               d_repository_list_box.filter_text(null);
                        }
                }
        }
@@ -151,7 +167,7 @@ class DashView : RepositoryListBox, GitgExt.UIElement, GitgExt.Activity, GitgExt
                        del.show();
 
                        del.clicked.connect(() => {
-                               foreach (var sel in selection)
+                               foreach (var sel in d_repository_list_box.selection)
                                {
                                        sel.request_remove();
                                }
@@ -159,7 +175,7 @@ class DashView : RepositoryListBox, GitgExt.UIElement, GitgExt.Activity, GitgExt
                                selectable_mode = GitgExt.SelectionMode.NORMAL;
                        });
 
-                       bind_property("has-selection", del, "sensitive");
+                       d_repository_list_box.bind_property("has-selection", del, "sensitive");
 
                        ab.pack_end(del);
 
@@ -170,12 +186,193 @@ class DashView : RepositoryListBox, GitgExt.UIElement, GitgExt.Activity, GitgExt
 
        construct
        {
-               notify["mode"].connect(() => {
+               d_repository_list_box.notify["mode"].connect(() => {
                        if (!d_setting_mode)
                        {
+                               d_action_bar.visible = (selectable_mode == GitgExt.SelectionMode.NORMAL);
                                notify_property("selectable-mode");
                        }
                });
+
+               d_repository_list_box.repository_activated.connect((repository) => {
+                       application.repository = repository;
+               });
+
+               d_repository_list_box.show_error.connect((primary_message, secondary_message) => {
+                       application.show_infobar(primary_message, secondary_message, Gtk.MessageType.ERROR);
+               });
+       }
+
+       public RepositoryListBox.Row? add_repository(Repository repository)
+       {
+               return d_repository_list_box.add_repository(repository);
+       }
+
+       class CloneCallbacks : Ggit.RemoteCallbacks
+       {
+               private RepositoryListBox.Row d_row;
+               private CredentialsManager d_credentials;
+
+               public CloneCallbacks(GitgExt.Application application, Ggit.Config? config, 
RepositoryListBox.Row row)
+               {
+                       d_row = row;
+                       d_credentials = new CredentialsManager(config, application as Gtk.Window, false);
+               }
+
+               protected override void transfer_progress(Ggit.TransferProgress stats)
+               {
+                       var recvobj = stats.get_received_objects();
+                       var indxobj = stats.get_indexed_objects();
+                       var totaobj = stats.get_total_objects();
+
+                       Idle.add(() => {
+                               d_row.fraction = (recvobj + indxobj) / (double)(2 * totaobj);
+                               return false;
+                       });
+               }
+
+               protected override Ggit.Cred? credentials(string url, string? username_from_url, 
Ggit.Credtype allowed_types) throws Error
+               {
+                       return d_credentials.credentials(url, username_from_url, allowed_types);
+               }
+       }
+
+       private async Repository? clone(RepositoryListBox.Row row, string url, File location, bool is_bare) 
throws Error
+       {
+               Repository? repository = null;
+
+               yield Async.thread(() => {
+                       var clone_options = new Ggit.CloneOptions();
+                       var fetch_options = new Ggit.FetchOptions();
+                       Ggit.Config? config = null;
+
+                       try
+                       {
+                               config = new Ggit.Config.default();
+                       } catch {}
+
+                       fetch_options.set_remote_callbacks(new CloneCallbacks(application, config, row));
+
+                       clone_options.set_is_bare(is_bare);
+                       clone_options.set_fetch_options(fetch_options);
+
+                       repository = (Repository)Ggit.Repository.clone(url, location, clone_options);
+               });
+
+               return repository;
+       }
+
+       private void clone_repository(string url, File location, bool is_bare)
+       {
+               // create subfolder
+               var pos = url.last_index_of_char('/');
+
+               if (pos == -1)
+               {
+                       pos = url.last_index_of_char(':');
+               }
+
+               var dot_git_suffix = ".git";
+               var subfolder_name = url.substring(pos + 1);
+               var has_dot_git = subfolder_name.has_suffix(dot_git_suffix);
+
+               if (has_dot_git && !is_bare)
+               {
+                       subfolder_name = subfolder_name.slice(0, - dot_git_suffix.length);
+               }
+               else if (!has_dot_git && is_bare)
+               {
+                       subfolder_name += dot_git_suffix;
+               }
+
+               var subfolder = location.resolve_relative_path(subfolder_name);
+
+               // Clone
+               var row = d_repository_list_box.begin_cloning(subfolder_name);
+
+               clone.begin(row, url, subfolder, is_bare, (obj, res) => {
+                       Gitg.Repository? repository = null;
+
+                       try
+                       {
+                               repository = clone.end(res);
+                       }
+                       catch (Error e)
+                       {
+                               application.show_infobar(_("Failed to clone repository"), e.message, 
Gtk.MessageType.ERROR);
+                       }
+
+                       d_repository_list_box.end_cloning(row, repository);
+               });
+       }
+
+       [GtkCallback]
+       private void clone_repository_clicked()
+       {
+               var dlg = new CloneDialog(application as Gtk.Window);
+
+               dlg.response.connect((d, id) => {
+                       if (id == Gtk.ResponseType.OK)
+                       {
+                               clone_repository(dlg.url, dlg.location, dlg.is_bare);
+                       }
+
+                       d.destroy();
+               });
+
+               dlg.show();
+       }
+
+       [GtkCallback]
+       private void open_repository_clicked()
+       {
+               var chooser = new Gtk.FileChooserDialog(_("Add Repository"),
+                                                       application as Gtk.Window,
+                                                       Gtk.FileChooserAction.SELECT_FOLDER,
+                                                       _("_Cancel"), Gtk.ResponseType.CANCEL,
+                                                       _("_Add"), Gtk.ResponseType.OK);
+
+               chooser.modal = true;
+               chooser.set_default_response(Gtk.ResponseType.OK);
+
+               chooser.response.connect((c, id) => {
+                       if (id == Gtk.ResponseType.OK)
+                       {
+                               var file = chooser.get_file();
+
+                               if (file == null)
+                               {
+                                       file = chooser.get_current_folder_file();
+                               }
+
+                               Repository? repo = null;
+
+                               try
+                               {
+                                       repo = new Repository(file, null);
+                               }
+                               catch (Error err)
+                               {
+                                       application.show_infobar(_("Failed to add repository"), err.message, 
Gtk.MessageType.ERROR);
+                               }
+
+                               if (repo != null)
+                               {
+                                       var row = add_repository(repo);
+
+                                       if (row != null)
+                                       {
+                                               row.grab_focus();
+                                               d_repository_list_box.grab_focus();
+                                               row.grab_focus();
+                                       }
+                               }
+                       }
+
+                       c.destroy();
+               });
+
+               chooser.show();
        }
 }
 
diff --git a/gitg/gitg-remote-manager.vala b/gitg/gitg-remote-manager.vala
index 8e04ca1..0349361 100644
--- a/gitg/gitg-remote-manager.vala
+++ b/gitg/gitg-remote-manager.vala
@@ -28,7 +28,14 @@ class RemoteManager : Object, GitgExt.RemoteLookup
 
                public UICredentialsProvider(Gitg.Remote remote, Gtk.Window window)
                {
-                       d_credentials = new CredentialsManager(remote, window);
+                       Ggit.Config? config = null;
+
+                       try
+                       {
+                               config = remote.get_owner().get_config();
+                       } catch {}
+
+                       d_credentials = new CredentialsManager(config, window, true);
                }
 
                public Ggit.Cred? credentials(string        url,
diff --git a/gitg/gitg-window.vala b/gitg/gitg-window.vala
index 61f313e..f775251 100644
--- a/gitg/gitg-window.vala
+++ b/gitg/gitg-window.vala
@@ -75,8 +75,6 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
        private Gtk.Stack d_main_stack;
 
        [GtkChild]
-       private Gtk.ScrolledWindow d_dash_scrolled_window;
-       [GtkChild]
        private DashView d_dash_view;
 
        [GtkChild]
@@ -141,8 +139,6 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
        private static const ActionEntry[] win_entries = {
                {"search", on_search_activated, null, "false", null},
                {"gear-menu", on_gear_menu_activated, null, "false", null},
-               {"open-repository", on_open_repository},
-               {"clone-repository", on_clone_repository},
                {"close", on_close_activated},
                {"reload", on_reload_activated},
                {"author-details-global", on_global_author_details_activated},
@@ -188,18 +184,6 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
                }
        }
 
-       [GtkCallback]
-       private void dash_view_repository_activated(Repository r)
-       {
-               repository = r;
-       }
-
-       [GtkCallback]
-       private void dash_view_show_error(string title, string message)
-       {
-               show_infobar(title, message, Gtk.MessageType.ERROR);
-       }
-
        construct
        {
                add_action_entries(win_entries, this);
@@ -234,6 +218,8 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
                        menuname = "app-win-menu";
                }
 
+               d_dash_view.application = this;
+
                d_dash_model = Resource.load_object<MenuModel>("ui/gitg-menus.ui", menuname + "-dash");
                d_activities_model = Resource.load_object<MenuModel>("ui/gitg-menus.ui", menuname + "-views");
 
@@ -426,7 +412,7 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
                        d_mode = Mode.DASH;
 
                        d_main_stack.transition_type = Gtk.StackTransitionType.SLIDE_RIGHT;
-                       d_main_stack.set_visible_child(d_dash_scrolled_window);
+                       d_main_stack.set_visible_child(d_dash_view);
                        d_activities_switcher.hide();
                        d_dash_button.hide();
                        d_gear_menu.menu_model = d_dash_model;
@@ -461,34 +447,6 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
                return base.configure_event(event);
        }
 
-       private void on_open_repository()
-       {
-               var chooser = new Gtk.FileChooserDialog (_("Open Repository"), this,
-                                                        Gtk.FileChooserAction.SELECT_FOLDER,
-                                                        _("_Cancel"), Gtk.ResponseType.CANCEL,
-                                                        _("_Open"), Gtk.ResponseType.OK);
-
-               chooser.modal = true;
-
-               chooser.response.connect((c, id) => {
-                       if (id == Gtk.ResponseType.OK)
-                       {
-                               var file = chooser.get_file();
-
-                               if (file == null)
-                               {
-                                       file = chooser.get_current_folder_file();
-                               }
-
-                               open_repository(file);
-                       }
-
-                       c.destroy();
-               });
-
-               chooser.show();
-       }
-
        private void on_reload_activated()
        {
                try
@@ -504,22 +462,6 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
                catch {}
        }
 
-       private void on_clone_repository()
-       {
-               var dlg = new CloneDialog(this);
-
-               dlg.response.connect((d, id) => {
-                       if (id == Gtk.ResponseType.OK)
-                       {
-                               d_dash_view.clone_repository(dlg.url, dlg.location, dlg.is_bare);
-                       }
-
-                       d.destroy();
-               });
-
-               dlg.show();
-       }
-
        private void on_global_author_details_activated()
        {
                Ggit.Config global_config = null;
@@ -742,7 +684,7 @@ public class Window : Gtk.ApplicationWindow, GitgExt.Application, Initable
                }
        }
 
-       private void open_repository(File path)
+       public void open_repository(File path)
        {
                File repo;
                Gitg.Repository? repository = null;
diff --git a/gitg/resources/gitg-resources.xml b/gitg/resources/gitg-resources.xml
index a20d66a..a3d9d97 100644
--- a/gitg/resources/gitg-resources.xml
+++ b/gitg/resources/gitg-resources.xml
@@ -20,6 +20,7 @@
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-commit-dialog.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-create-branch-dialog.ui</file>
     <file compressed="true" preprocess="xml-stripblanks">ui/gitg-create-tag-dialog.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks">ui/gitg-dash-view.ui</file>
     <file compressed="true">ui/style.css</file>
   </gresource>
 </gresources>
diff --git a/gitg/resources/ui/gitg-dash-view.ui b/gitg/resources/ui/gitg-dash-view.ui
new file mode 100644
index 0000000..5d41e39
--- /dev/null
+++ b/gitg/resources/ui/gitg-dash-view.ui
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <template class="GitgDashView" parent="GtkGrid">
+    <child>
+      <object class="GtkScrolledWindow" id="scrolled_window">
+        <property name="visible">True</property>
+        <property name="vexpand">True</property>
+        <property name="hexpand">True</property>
+        <style>
+          <class name="view"/>
+        </style>
+        <child>
+          <object class="GitgRepositoryListBox" id="repository_list_box">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <style>
+              <class name="view"/>
+            </style>
+          </object>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">0</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkActionBar" id="action_bar">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <child>
+          <object class="GtkButton" id="open_repository">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Add repository</property>
+            <signal name="clicked" handler="open_repository_clicked" swapped="no"/>
+          </object>
+          <packing>
+            <property name="pack_type">end</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkButton" id="clone_repository">
+            <property name="visible">True</property>
+            <property name="label" translatable="yes">Clone repository</property>
+            <signal name="clicked" handler="clone_repository_clicked" swapped="no"/>
+          </object>
+          <packing>
+            <property name="pack_type">end</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">0</property>
+        <property name="top_attach">1</property>
+        <property name="width">1</property>
+        <property name="height">1</property>
+      </packing>
+    </child>
+  </template>
+</interface>
diff --git a/gitg/resources/ui/gitg-menus.ui b/gitg/resources/ui/gitg-menus.ui
index 097147e..7f5beeb 100644
--- a/gitg/resources/ui/gitg-menus.ui
+++ b/gitg/resources/ui/gitg-menus.ui
@@ -32,16 +32,6 @@
   <menu id="win-menu-dash">
     <section>
       <item>
-        <attribute name="label" translatable="yes">_Open Repository…</attribute>
-        <attribute name="action">win.open-repository</attribute>
-      </item>
-      <item>
-        <attribute name="label" translatable="yes">_Clone Repository…</attribute>
-        <attribute name="action">win.clone-repository</attribute>
-      </item>
-    </section>
-    <section>
-      <item>
         <attribute name="label" translatable="yes">_Author Details</attribute>
         <attribute name="action">win.author-details-global</attribute>
       </item>
diff --git a/gitg/resources/ui/gitg-window.ui b/gitg/resources/ui/gitg-window.ui
index 69b2afe..98e8ac0 100644
--- a/gitg/resources/ui/gitg-window.ui
+++ b/gitg/resources/ui/gitg-window.ui
@@ -234,24 +234,9 @@
                 <property name="hexpand">True</property>
                 <property name="vexpand">True</property>
                 <child>
-                  <object class="GtkScrolledWindow" id="d_dash_scrolled_window">
+                  <object class="GitgDashView" id="d_dash_view">
                     <property name="visible">True</property>
-                    <property name="vexpand">True</property>
-                    <property name="hexpand">True</property>
-                    <style>
-                      <class name="view"/>
-                    </style>
-                    <child>
-                      <object class="GitgDashView" id="d_dash_view">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <signal name="repository_activated" handler="dash_view_repository_activated" 
swapped="no"/>
-                        <signal name="show_error" handler="dash_view_show_error" swapped="no"/>
-                        <style>
-                          <class name="view"/>
-                        </style>
-                      </object>
-                    </child>
+                    <property name="can_focus">True</property>
                   </object>
                 </child>
                 <child>
diff --git a/libgitg-ext/gitg-ext-application.vala b/libgitg-ext/gitg-ext-application.vala
index 30e6027..8a3120d 100644
--- a/libgitg-ext/gitg-ext-application.vala
+++ b/libgitg-ext/gitg-ext-application.vala
@@ -76,6 +76,8 @@ public interface Application : Object
        public abstract Application open_new(Ggit.Repository repository, string? hint = null);
 
        public abstract RemoteLookup remote_lookup { owned get; }
+
+       public abstract void open_repository(File path);
 }
 
 }
diff --git a/libgitg/gitg-credentials-manager.vala b/libgitg/gitg-credentials-manager.vala
index d913bd6..67a26c4 100644
--- a/libgitg/gitg-credentials-manager.vala
+++ b/libgitg/gitg-credentials-manager.vala
@@ -27,9 +27,12 @@ public errordomain CredentialsError
 
 public class CredentialsManager
 {
-       private weak Remote d_remote;
+       private Ggit.Config? d_config;
        private Gtk.Window d_window;
        private Gee.HashMap<string, string>? d_usermap;
+       private bool d_save_user_in_config;
+       private string d_last_user;
+       private Gee.HashMap<string, Ggit.Credtype> d_auth_tried;
        private static Secret.Schema s_secret_schema;
 
        static construct
@@ -41,9 +44,11 @@ public class CredentialsManager
                                                    "user", Secret.SchemaAttributeType.STRING);
        }
 
-       public CredentialsManager(Remote remote, Gtk.Window window)
+       public CredentialsManager(Ggit.Config? config, Gtk.Window window, bool save_user_in_config)
        {
-               d_remote = remote;
+               d_config = config;
+               d_save_user_in_config = save_user_in_config;
+               d_auth_tried = new Gee.HashMap<string, Ggit.Credtype>();
                d_window = window;
        }
 
@@ -53,19 +58,21 @@ public class CredentialsManager
                {
                        d_usermap = new Gee.HashMap<string, string?>();
 
-                       try
+                       if (d_config != null)
                        {
-                               var config = d_remote.get_owner().get_config().snapshot();
-                               var r = new Regex("credential\\.(.*)\\.username");
+                               try
+                               {
+                                       var r = new Regex("credential\\.(.*)\\.username");
 
-                               config.match_foreach(r, (info, value) => {
-                                       d_usermap[info.fetch(1)] = value;
-                                       return 0;
-                               });
-                       }
-                       catch (Error e)
-                       {
-                               stderr.printf("Could not get username from git config: %s\n", e.message);
+                                       d_config.snapshot().match_foreach(r, (info, value) => {
+                                               d_usermap[info.fetch(1)] = value;
+                                               return 0;
+                                       });
+                               }
+                               catch (Error e)
+                               {
+                                       stderr.printf("Could not get username from git config: %s\n", 
e.message);
+                               }
                        }
                }
 
@@ -86,7 +93,7 @@ public class CredentialsManager
                AuthenticationLifeTime lifetime = AuthenticationLifeTime.FORGET;
 
                Idle.add(() => {
-                       var d = new AuthenticationDialog(url, username, d_remote.authentication_error != 
null);
+                       var d = new AuthenticationDialog(url, username, d_auth_tried[username] != 0);
                        d.set_transient_for(d_window);
 
                        response = (Gtk.ResponseType)d.run();
@@ -115,8 +122,10 @@ public class CredentialsManager
                        throw new CredentialsError.CANCELLED("cancelled by user");
                }
 
+               d_last_user = newusername;
+
                // Save username in config
-               if (username == null || newusername != username)
+               if (username == null || newusername != username && d_config != null && d_save_user_in_config)
                {
                        if (d_usermap == null)
                        {
@@ -125,12 +134,9 @@ public class CredentialsManager
 
                        try
                        {
-                               var repo = d_remote.get_owner();
-                               var config = repo.get_config();
                                var hid = @"$(scheme)://$(host)";
 
-                               config.set_string(@"credential.$(hid).username", newusername);
-
+                               d_config.set_string(@"credential.$(hid).username", newusername);
                                d_usermap[hid] = newusername;
                        }
                        catch (Error e)
@@ -185,6 +191,7 @@ public class CredentialsManager
                        });
                }
 
+               d_auth_tried[newusername] |= Ggit.Credtype.USERPASS_PLAINTEXT;
                return new Ggit.CredPlaintext(newusername, password);
        }
 
@@ -212,29 +219,40 @@ public class CredentialsManager
                        user = username;
                }
 
-               if (user != null && d_remote.authentication_error == null)
+               if (user != null)
                {
-                       string? secret = null;
+                       var tried = d_auth_tried[user];
 
-                       try
+                       if ((tried & Ggit.Credtype.USERPASS_PLAINTEXT) == 0)
                        {
-                               secret = Secret.password_lookup_sync(s_secret_schema, null,
-                                                                    "scheme", scheme,
-                                                                    "host", host,
-                                                                    "user", user);
-                       }
-                       catch {}
+                               string? secret = null;
 
-                       if (secret == null)
-                       {
-                               return user_pass_dialog(url, scheme, host, user);
-                       }
+                               try
+                               {
+                                       secret = Secret.password_lookup_sync(s_secret_schema, null,
+                                                                            "scheme", scheme,
+                                                                            "host", host,
+                                                                            "user", user);
+                               }
+                               catch {}
 
-                       try
-                       {
-                               return new Ggit.CredPlaintext(user, secret);
+                               if (secret == null)
+                               {
+                                       return user_pass_dialog(url, scheme, host, user);
+                               }
+
+                               d_auth_tried[user] |= Ggit.Credtype.USERPASS_PLAINTEXT;
+
+                               try
+                               {
+                                       return new Ggit.CredPlaintext(user, secret);
+                               }
+                               catch (Error e)
+                               {
+                                       return user_pass_dialog(url, scheme, host, user);
+                               }
                        }
-                       catch (Error e)
+                       else
                        {
                                return user_pass_dialog(url, scheme, host, user);
                        }
@@ -249,8 +267,14 @@ public class CredentialsManager
                                      string?       username,
                                      Ggit.Credtype allowed_types) throws Error
        {
-               if (d_remote.authentication_error == null && (allowed_types & Ggit.Credtype.SSH_KEY) != 0)
+               var uslookup = username != null ? username : "";
+               var tried = d_auth_tried[uslookup];
+               
+               var untried_allowed_types = allowed_types & ~tried;
+
+               if ((untried_allowed_types & Ggit.Credtype.SSH_KEY) != 0)
                {
+                       d_auth_tried[uslookup] = tried | Ggit.Credtype.SSH_KEY;
                        return new Ggit.CredSshKeyFromAgent(username);
                }
                else if ((allowed_types & Ggit.Credtype.USERPASS_PLAINTEXT) != 0)
diff --git a/libgitg/gitg-remote.vala b/libgitg/gitg-remote.vala
index 50e176e..991d4cf 100644
--- a/libgitg/gitg-remote.vala
+++ b/libgitg/gitg-remote.vala
@@ -118,7 +118,6 @@ public class Remote : Ggit.Remote
        }
 
        private RemoteState d_state;
-       private Error? d_authentication_error;
        private string[]? d_fetch_specs;
        private string[]? d_push_specs;
        private uint d_reset_transfer_progress_timeout;
@@ -142,11 +141,6 @@ public class Remote : Ggit.Remote
                get { return d_transfer_progress; }
        }
 
-       public Error authentication_error
-       {
-               get { return d_authentication_error; }
-       }
-
        public RemoteState state
        {
                get { return d_state; }
@@ -218,7 +212,6 @@ public class Remote : Ggit.Remote
                        else
                        {
                                state = RemoteState.CONNECTED;
-                               d_authentication_error = null;
                        }
                }
                else
@@ -265,7 +258,6 @@ public class Remote : Ggit.Remote
                                if (e.message == "Unexpected HTTP status code: 401" ||
                                    e.message == "error authenticating: Username/PublicKey combination 
invalid")
                                {
-                                       d_authentication_error = e;
                                        continue;
                                }
                                else
@@ -275,7 +267,6 @@ public class Remote : Ggit.Remote
                                }
                        }
 
-                       d_authentication_error = null;
                        break;
                }
 
diff --git a/libgitg/gitg-repository-list-box.vala b/libgitg/gitg-repository-list-box.vala
index 7da7cb3..b5a9620 100644
--- a/libgitg/gitg-repository-list-box.vala
+++ b/libgitg/gitg-repository-list-box.vala
@@ -365,14 +365,46 @@ namespace Gitg
                {
                        var recent_manager = Gtk.RecentManager.get_default();
                        var item = Gtk.RecentData();
+
                        item.app_name = Environment.get_application_name();
                        item.mime_type = "inode/directory";
                        item.app_exec = string.join(" ", Environment.get_prgname(), "%f");
                        item.groups = { "gitg", null };
+
                        recent_manager.add_full(uri, item);
                }
 
-               public void add_repository(Repository repository)
+               public void end_cloning(Row row, Repository? repository)
+               {
+                       if (repository != null)
+                       {
+                               File? workdir = repository.get_workdir();
+                               File? repo_file = repository.get_location();
+
+                               var uri = (workdir != null) ? workdir.get_uri() : repo_file.get_uri();
+                               add_repository_to_recent_manager(uri);
+
+                               row.repository = repository;
+                               row.loading = false;
+                       }
+                       else
+                       {
+                               remove(row);
+                       }
+               }
+
+               public Row? begin_cloning(string name)
+               {
+                       var row = new Row(name, _("Cloning..."), true);
+
+                       row.loading = true;
+                       row.show();
+
+                       add(row);
+                       return row;
+               }
+
+               public Row? add_repository(Repository repository)
                {
                        Row? row = get_row_for_repository(repository);
 
@@ -451,6 +483,8 @@ namespace Gitg
                        {
                                add_repository_to_recent_manager(f.get_uri());
                        }
+
+                       return row;
                }
 
                public Row[] selection
@@ -491,117 +525,6 @@ namespace Gitg
                        }
                }
 
-               class CloneProgress : Ggit.RemoteCallbacks
-               {
-                       private Row d_row;
-
-                       public CloneProgress(Row row)
-                       {
-                               d_row = row;
-                       }
-
-                       protected override void transfer_progress(Ggit.TransferProgress stats)
-                       {
-                               var recvobj = stats.get_received_objects();
-                               var indxobj = stats.get_indexed_objects();
-                               var totaobj = stats.get_total_objects();
-
-                               Idle.add(() => {
-                                       d_row.fraction = (recvobj + indxobj) / (double)(2 * totaobj);
-                                       return false;
-                               });
-                       }
-               }
-
-               private async Repository? clone(Row row, string url, File location, bool is_bare)
-               {
-                       SourceFunc callback = clone.callback;
-                       Repository? repository = null;
-
-                       ThreadFunc<void*> run = () => {
-                               try
-                               {
-                                       var clone_options = new Ggit.CloneOptions();
-                                       var fetch_options = new Ggit.FetchOptions();
-
-                                       fetch_options.set_remote_callbacks(new CloneProgress(row));
-
-                                       clone_options.set_is_bare(is_bare);
-                                       clone_options.set_fetch_options(fetch_options);
-
-                                       repository = (Repository)Ggit.Repository.clone(url, location, 
clone_options);
-                               }
-                               catch (Ggit.Error e)
-                               {
-                                       show_error("Gitg could not clone the git repository.", e.message);
-                               }
-                               catch (GLib.Error e)
-                               {
-                                       show_error("Gitg could not clone the git repository.", e.message);
-                               }
-
-                               Idle.add((owned) callback);
-                               return null;
-                       };
-
-                       try
-                       {
-                               new Thread<void*>.try("gitg-clone-thread", (owned)run);
-                               yield;
-                       }
-                       catch {}
-
-                       return repository;
-               }
-
-               public void clone_repository(string url, File location, bool is_bare)
-               {
-                       // create subfolder
-                       var subfolder_name = url.substring(url.last_index_of_char('/') + 1);
-                       if (subfolder_name.has_suffix(".git") && !is_bare)
-                       {
-                               subfolder_name = subfolder_name.slice(0, - ".git".length);
-                       }
-                       else if (is_bare)
-                       {
-                               subfolder_name += ".git";
-                       }
-
-                       var subfolder = location.resolve_relative_path(subfolder_name);
-
-                       try
-                       {
-                               subfolder.make_directory_with_parents(null);
-                       }
-                       catch (GLib.Error e)
-                       {
-                               show_error("Gitg could not clone the git repository.", e.message);
-                               return;
-                       }
-
-                       // Clone
-                       var row = new Row(subfolder_name, "Cloning...", true);
-                       row.loading = true;
-                       row.show();
-                       add(row);
-
-                       clone.begin(row, url, subfolder, is_bare, (obj, res) => {
-                               Gitg.Repository? repository = clone.end(res);
-
-                               // FIXME: show an error
-                               if (repository != null)
-                               {
-                                       File? workdir = repository.get_workdir();
-                                       File? repo_file = repository.get_location();
-                                       var uri = (workdir != null) ? workdir.get_uri() : repo_file.get_uri();
-                                       add_repository_to_recent_manager(uri);
-                               }
-
-                               row.repository = repository;
-                               row.loading = false;
-                       });
-               }
-
                public void filter_text(string? text)
                {
                        d_filter_text = text;
diff --git a/libgitg/resources/ui/gitg-repository-list-box-row.ui 
b/libgitg/resources/ui/gitg-repository-list-box-row.ui
index b9e15c7..4f06a5e 100644
--- a/libgitg/resources/ui/gitg-repository-list-box-row.ui
+++ b/libgitg/resources/ui/gitg-repository-list-box-row.ui
@@ -2,6 +2,7 @@
 <interface>
   <!-- interface-requires gtk+ 3.8 -->
   <template class="GitgRepositoryListBoxRow" parent="GtkListBoxRow">
+    <property name="can_focus">True</property>
     <child>
       <object class="GitgProgressBin" id="d_progress_bin">
         <property name="visible">True</property>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3e49ed9..0dd1925 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -27,6 +27,7 @@ gitg/preferences/gitg-preferences-interface.vala
 libgitg/gitg-date.vala
 libgitg/gitg-diff-view.vala
 libgitg/gitg-remote-notification.vala
+libgitg/gitg-repository-list-box.vala
 libgitg/gitg-stage.vala
 plugins/diff/gitg-diff.vala
 plugins/files/gitg-files.vala
@@ -39,6 +40,7 @@ plugins/files/gitg-files.vala
 [type: gettext/glade]gitg/resources/ui/gitg-commit-submodule-info.ui
 [type: gettext/glade]gitg/resources/ui/gitg-create-branch-dialog.ui
 [type: gettext/glade]gitg/resources/ui/gitg-create-tag-dialog.ui
+[type: gettext/glade]gitg/resources/ui/gitg-dash-view.ui
 [type: gettext/glade]gitg/resources/ui/gitg-history-paned.ui
 [type: gettext/glade]gitg/resources/ui/gitg-menus.ui
 [type: gettext/glade]gitg/resources/ui/gitg-preferences-commit.ui
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index 99368a3..5e3bc9d 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -27,6 +27,7 @@ libgitg/gitg-authentication-dialog.c
 libgitg/gitg-date.c
 libgitg/gitg-diff-view.c
 libgitg/gitg-remote-notification.c
+libgitg/gitg-repository-list-box.c
 libgitg/gitg-stage.c
 plugins/diff/gitg-diff.c
 plugins/files/gitg-files.c



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