From bae3b7556facbd6c3e34074226a4ca4a6450e2f7 Mon Sep 17 00:00:00 2001 From: Hylke Bons Date: Sat, 1 May 2010 03:31:20 +0100 Subject: [PATCH] people list and half baked gravatar support --- Makefile | 1 + .../hicolor/16x16/status/avatar-default.png | Bin 0 -> 846 bytes src/SparklePony.cs | 171 ++++++++++++------ 3 files changed, 119 insertions(+), 53 deletions(-) create mode 100644 data/icons/hicolor/16x16/status/avatar-default.png diff --git a/Makefile b/Makefile index c46344e0..58e88b07 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ uninstall: rmdir /usr/local/share/sparklepony rm /usr/share/icons/hicolor/*x*/places/folder-publicshare.png rm /usr/share/icons/hicolor/*x*/status/document-*ed.png + rm /usr/share/icons/hicolor/*x*/status/avatar-default.png clean: rm src/SparklePony.exe diff --git a/data/icons/hicolor/16x16/status/avatar-default.png b/data/icons/hicolor/16x16/status/avatar-default.png new file mode 100644 index 0000000000000000000000000000000000000000..0d231ee31172d93cb4e997275eb40d6593edfc18 GIT binary patch literal 846 zcmV-U1F`&xP)AW3d!Z|pJm-v9sr7j#8fbU}4=Xm4@= zOkr?uAVXnnVQpbCNzi} z`vu{qz#o;nP}<0l&|2sZP)cc<%+Z*{U8EQ!m8n4xMy}fBB8m{*w6U0yX2#KR=KZ>J zXWo6cg*MC>LI=*`!1wdva5zLtiNiJV=s{PF<{bmUY3WKyDA_17erITC_~SoeDP>hp zPCcAhT$(pb(~v?4DTI)^k(V##=k&>`c;s-tY8a1?cD;P{+;AL63gMImLO8Nmp66^chq`S^?oIzRt}CM&MJz6OeTf8 zx?}MB0{{TaGLg&eAsDPhK5tw&Qec<{7_-5c4N56EF8}~I=ir<{Q55J#9!Cn8%{Ef$ zBP#wz^#Dm z3Rsp2K!Q>Q0N}bVD5dcGgCK-pW_H?2Z2i0%kHtT!08nxY_rl>Dfn;(E*=z=y=7FlJ zP?UXv5CV?lpjhOnuRo4(UpO#6F*X9AM~z0K)UeDp#w=`ZeuJuN2e1l42mnAzw=Bu! zvIvD*pc_Uz0H~2j#0~fNk!&^t+cp6ZD2fV7X@x+-bp?bFkP_J4&A>2CS^fiN*`L?f z*Dp6WhlrE}loAj^ss#HI2||FiwKbPn_GR69OV07*qoM6N<$f{H|OP5=M^ literal 0 HcmV?d00001 diff --git a/src/SparklePony.cs b/src/SparklePony.cs index 5688de76..d1095ea7 100644 --- a/src/SparklePony.cs +++ b/src/SparklePony.cs @@ -17,12 +17,17 @@ // along with this program. If not, see . using Gtk; -using System; -using System.IO; -using System.Diagnostics; -using System.Timers; using Notifications; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Security.Cryptography; +using System.Text; using System.Text.RegularExpressions; +using System.Timers; + public class SparklePony { @@ -90,8 +95,6 @@ public class SparklePonyUI { public SparklePonyWindow SparklePonyWindow; public SparklePonyStatusIcon SparklePonyStatusIcon; - public string ReposPath; - public string UserHome; public Repository [] Repositories; public SparklePonyUI (bool HideUI) { @@ -101,14 +104,23 @@ public class SparklePonyUI { Process.StartInfo.RedirectStandardOutput = true; Process.StartInfo.UseShellExecute = false; - // Get home folder, example: "/home/user" - UserHome = Environment.GetEnvironmentVariable("HOME"); + // Get home folder, example: "/home/user/" + string UserHome = Environment.GetEnvironmentVariable("HOME") + "/"; // Create 'Collaboration' folder in the user's home folder - ReposPath = UserHome + "/Collaboration"; + string ReposPath = UserHome + "Collaboration"; if (!Directory.Exists (ReposPath)) { Directory.CreateDirectory (ReposPath); - Console.WriteLine ("Created '" + ReposPath + "'"); + Console.WriteLine ("[Config] Created '" + ReposPath + "'"); + } + + // Create place to store configuration user's home folder + string ConfigPath = UserHome + ".config/sparklepony/"; + if (!Directory.Exists (ConfigPath)) { + Directory.CreateDirectory (ConfigPath); + Console.WriteLine ("[Config] Created '" + ConfigPath + "'"); + Directory.CreateDirectory (ConfigPath + "gravatars"); + Console.WriteLine ("[Config] Created '" + ConfigPath + "gravatars'"); } // Get all the Repos in ~/Collaboration @@ -147,7 +159,7 @@ public class SparklePonyUI { public class SparklePonyStatusIcon : StatusIcon { public SparklePonyStatusIcon () : base () { - IconName = "folder-remote"; + IconName = "folder-publicshare"; // TODO: Only on first run Notification Notification = new Notification ("Welcome to SparklePony!", "Click here to add some folders."); Notification.Urgency = Urgency.Normal; @@ -156,7 +168,7 @@ public class SparklePonyStatusIcon : StatusIcon { } public void SetIdleState () { - IconName = "folder-remote"; + IconName = "folder-publicshare"; } public void SetSyncingState () { @@ -191,7 +203,6 @@ public class Repository { Process.EnableRaisingEvents = false; Process.StartInfo.RedirectStandardOutput = true; Process.StartInfo.UseShellExecute = false; - // Get the repository's path, example: "/home/user/Collaboration/repo/" RepoPath = Path; Process.StartInfo.WorkingDirectory = RepoPath + "/"; @@ -303,7 +314,8 @@ public class Repository { // Add a gitignore file TextWriter Writer = new StreamWriter(RepoPath + ".gitignore"); - Writer.WriteLine("*~"); + Writer.WriteLine("*~"); // Ignore gedit swap files + Writer.WriteLine(".*.sw?"); // Ignore vi swap files Writer.Close(); } @@ -381,14 +393,14 @@ public class Repository { } // Ignore Repos, dotfiles, swap files and the like. - public bool ShouldIgnore (string s) { - if (s.Substring (0, 1).Equals (".") || - s.Contains (".lock") || - s.Contains (".git") || - s.Contains ("/.") || - Directory.Exists (Process.StartInfo.WorkingDirectory + "/" + s)) + public bool ShouldIgnore (string FileName) { + if (FileName.Substring (0, 1).Equals (".") || + FileName.Contains (".lock") || + FileName.Contains (".git") || + FileName.Contains ("/.") || + Directory.Exists (RepoPath + FileName)) return true; // Yes, ignore it. - else if (s.Length > 3 && s.Substring (s.Length - 4).Equals (".swp")) + else if (FileName.Length > 3 && FileName.Substring (FileName.Length - 4).Equals (".swp")) return true; else return false; } @@ -501,17 +513,17 @@ public class SparklePonyWindow : Window { Repositories = R; Visibility = false; - SetSizeRequest (640, 480); + SetSizeRequest (800, 600); SetPosition (WindowPosition.Center); BorderWidth = 6; - IconName = "folder-remote"; + IconName = "folder-publicshare"; VBox LayoutVertical = new VBox (false, 0); Notebook Notebook = new Notebook (); Notebook.BorderWidth = 6; - HBox LayoutHorizontal = new HBox (false, 12); + HBox LayoutHorizontal = new HBox (false, 0); ReposStore = new ListStore (typeof (Gdk.Pixbuf), typeof (string)); LayoutVerticalLeft = CreateReposList (); @@ -519,8 +531,17 @@ public class SparklePonyWindow : Window { LayoutVerticalRight = CreateDetailsView (); + + Label PeopleLabel = new Label ("People"); + PeopleLabel.UseMarkup = true; + PeopleLabel.SetAlignment (0, 0); + + LayoutVerticalRight.PackStart (PeopleLabel, false, false, 0); + + LayoutVerticalRight.PackStart (CreatePeopleList (Repositories [0]), true, true, 12); + LayoutHorizontal.PackStart (LayoutVerticalLeft, false, false, 0); - LayoutHorizontal.PackStart (LayoutVerticalRight, true, true, 0); + LayoutHorizontal.PackStart (LayoutVerticalRight, true, true, 12); Notebook.AppendPage (LayoutHorizontal, new Label ("Folders")); Notebook.AppendPage (CreateEventLog (), new Label ("Events")); @@ -547,13 +568,17 @@ public class SparklePonyWindow : Window { public VBox CreateReposList() { - string RemoteFolderIcon = "/usr/share/icons/gnome/22x22/places/folder-remote.png"; + string RemoteFolderIcon = "/usr/share/icons/gnome/22x22/places/folder.png"; TreeIter ReposIter; foreach (Repository Repository in Repositories) { ReposIter = ReposStore.Prepend (); ReposStore.SetValue (ReposIter, 0, new Gdk.Pixbuf (RemoteFolderIcon)); ReposStore.SetValue (ReposIter, 1, Repository.Name + " \n" + Repository.Domain + " "); } + + + ScrolledWindow ScrolledWindow = new ScrolledWindow (); + ReposView = new TreeView (ReposStore); ReposView.AppendColumn ("", new CellRendererPixbuf () , "pixbuf", 0); ReposView.AppendColumn ("", new Gtk.CellRendererText (), "text", 1); @@ -565,16 +590,19 @@ public class SparklePonyWindow : Window { ReposView.ActivateRow (ReposStore.GetPath (ReposIter), ReposViewColumns [1]); - HBox AddRemoveButtons = new HBox (); + HBox AddRemoveButtons = new HBox (false, 6); Button AddButton = new Button ("Add..."); AddRemoveButtons.PackStart (AddButton, true, true, 0); - Image RemoveImage = new Image (Stock.Remove); - Button RemoveButton = new Button (RemoveImage); + Image RemoveImage = new Image ("/usr/share/icons/gnome/16x16/actions/list-remove.png"); + Button RemoveButton = new Button (); + RemoveButton.Image = RemoveImage; AddRemoveButtons.PackStart (RemoveButton, false, false, 0); - VBox VBox = new VBox (false, 0); - VBox.PackStart (ReposView, true, true, 0); + ScrolledWindow.AddWithViewport (ReposView); + ScrolledWindow.WidthRequest = 200; + VBox VBox = new VBox (false, 6); + VBox.PackStart (ScrolledWindow, true, true, 0); VBox.PackStart (AddRemoveButtons, false, false, 0); return VBox; @@ -582,7 +610,7 @@ public class SparklePonyWindow : Window { public VBox CreateDetailsView () { - Label Label1 = new Label ("Remote URL:"); + Label Label1 = new Label ("Remote URL: "); Label1.UseMarkup = true; Label1.SetAlignment (0, 0); @@ -594,26 +622,25 @@ public class SparklePonyWindow : Window { Label5.UseMarkup = true; Label5.SetAlignment (0, 0); - Label Label6 = new Label ("~/Collaboration/Deal"); + Label Label6 = new Label ("~/Collaboration/Deal "); Label6.UseMarkup = true; Label6.SetAlignment (0, 0); Button NotificationsCheckButton = new CheckButton ("Notify me when something changes"); Button ChangesCheckButton = new CheckButton ("Synchronize my changes"); - Table Table = new Table(8, 2, false); + Table Table = new Table(7, 2, false); Table.RowSpacing = 6; - Table.Attach(Label1, 0, 1, 0, 1); - Table.Attach(Label2, 1, 2, 0, 1); - Table.Attach(Label5, 0, 1, 1, 2); - Table.Attach(Label6, 1, 2, 1, 2); - Table.Attach(NotificationsCheckButton, 0, 2, 3, 4); - Table.Attach(ChangesCheckButton, 0, 2, 4, 5); - Table.Attach (CreatePeopleList (Repositories [0]), 0, 2, 5, 8); + Table.Attach(Label1, 0, 1, 1, 2); + Table.Attach(Label2, 1, 2, 1, 2); + Table.Attach(Label5, 0, 1, 2, 3); + Table.Attach(Label6, 1, 2, 2, 3); + Table.Attach(NotificationsCheckButton, 0, 2, 4, 5); + Table.Attach(ChangesCheckButton, 0, 2, 5, 6); VBox VBox = new VBox (false, 0); - VBox.PackStart (Table, false, false, 24); + VBox.PackStart (Table, false, false, 12); return VBox; @@ -635,7 +662,6 @@ public class SparklePonyWindow : Window { Process.StartInfo.FileName = "git"; string Output = ""; foreach (Repository Repository in Repositories) { - // We're using the snowman here to separate messages :) Process.StartInfo.Arguments = "log --format=\"%at☃In '" + Repository.Name + "', %an %s☃%cr\" -25"; Process.StartInfo.WorkingDirectory = Repository.RepoPath; @@ -695,7 +721,7 @@ public class SparklePonyWindow : Window { } - public TreeView CreatePeopleList (Repository Repository) { + public ScrolledWindow CreatePeopleList (Repository Repository) { Process Process = new Process (); Process.EnableRaisingEvents = false; @@ -706,27 +732,54 @@ public class SparklePonyWindow : Window { Process.StartInfo.Arguments = "log --format=\"%an☃%ae\" -50"; Process.StartInfo.WorkingDirectory = Repository.RepoPath; Process.Start(); + + string [] People = new string [50]; string [] Lines = Regex.Split (Process.StandardOutput.ReadToEnd().Trim (), "\n"); - ListStore PeopleStore = new ListStore (typeof (Gdk.Pixbuf), typeof (string), typeof (string)); - string PersonIcon = "/usr/share/icons/gnome/22x22/status/printer-error.png"; + + string PersonIcon = "/usr/share/icons/hicolor/16x16/status/avatar-default.png"; TreeIter PeopleIter; + int i = 0; foreach (string Line in Lines) { - string [] Parts = Regex.Split (Line, "☃"); - PeopleIter = PeopleStore.Prepend (); - PeopleStore.SetValue (PeopleIter, 0, new Gdk.Pixbuf (PersonIcon)); - PeopleStore.SetValue (PeopleIter, 1, Parts [0]); - PeopleStore.SetValue (PeopleIter, 2, Parts [1]); + if (Array.IndexOf (People, Line) == -1) { + People [i] = Line; + string [] Parts = Regex.Split (Line, "☃"); + if (Parts [0].Equals (Repository.UserName)) + Parts [0] += " (that's you)"; + + if (File.Exists (Environment.GetEnvironmentVariable("HOME") + "/.config/sparklepony/gravatars/" + Parts [1])) + PersonIcon = Environment.GetEnvironmentVariable("HOME") + "/.config/sparklepony/gravatars/" + Parts [1]; + PeopleIter = PeopleStore.Prepend (); + PeopleStore.SetValue (PeopleIter, 0, new Gdk.Pixbuf (PersonIcon)); + PeopleStore.SetValue (PeopleIter, 1, Parts [0]); + PeopleStore.SetValue (PeopleIter, 2, Parts [1] + " "); + + // Let's get the gravatar for next time + WebClient WebClient = new WebClient (); + string AvatarsDir = Environment.GetEnvironmentVariable("HOME") + "/.config/sparklepony/gravatars/"; + + Uri Uri1, Uri2; + Console.WriteLine ("http://www.gravatar.com/avatar/" + GetMD5 (Parts [1]) + ".jpg"); + Uri1 = new Uri ("http://www.gravatar.com/avatar/" + GetMD5 (Parts [1]) + ".jpg?s=22"); + WebClient.DownloadFileAsync (Uri1, AvatarsDir + Parts [1]); + + } + i++; } TreeView PeopleView = new TreeView (PeopleStore); PeopleView.AppendColumn ("", new CellRendererPixbuf () , "pixbuf", 0); PeopleView.AppendColumn ("", new Gtk.CellRendererText (), "text", 1); PeopleView.AppendColumn ("", new Gtk.CellRendererText (), "text", 2); TreeViewColumn [] PeopleViewColumns = PeopleView.Columns; - PeopleViewColumns [0].MinWidth = 34; + PeopleViewColumns [0].MinWidth = 32; + PeopleViewColumns [1].Expand = true; - return PeopleView; + ScrolledWindow ScrolledWindow = new ScrolledWindow (); + ScrolledWindow.AddWithViewport (PeopleView); + + + return ScrolledWindow; } public void UpdatePeopleList () { @@ -734,6 +787,7 @@ public class SparklePonyWindow : Window { } public void ToggleVisibility() { + Present (); if (Visibility) { if (HasFocus) HideAll (); @@ -747,4 +801,15 @@ public class SparklePonyWindow : Window { Application.Quit (); } + // Helper that creates an MD5 hash + public static string GetMD5 (string s) { + + MD5 md5 = new MD5CryptoServiceProvider (); + Byte[] Bytes = ASCIIEncoding.Default.GetBytes (s); + Byte[] EncodedBytes = md5.ComputeHash (Bytes); + + return BitConverter.ToString(EncodedBytes).ToLower ().Replace ("-", ""); + + } + }