diff --git a/AUTHORS b/AUTHORS index efd98ae3..50e6aaba 100644 --- a/AUTHORS +++ b/AUTHORS @@ -10,7 +10,7 @@ Contributors: Benjamin Podszun Bertrand Lorentz Garrett LeSage - Jakub Steiner + Jakub Steiner Lapo Calamandrei Łukasz Jernaś Michael Monreal @@ -21,5 +21,6 @@ Contributors: Sandy Armstrong Simon Pither Steven Harms + Vincent Untz Thanks very much! diff --git a/SparkleLib/Makefile.am b/SparkleLib/Makefile.am index 9f8b44c4..934ae199 100644 --- a/SparkleLib/Makefile.am +++ b/SparkleLib/Makefile.am @@ -5,9 +5,10 @@ LINK = $(REF_SPARKLELIB) SOURCES = \ Defines.cs \ - SparkleOptions.cs \ + SparkleEvents.cs \ SparkleFetcher.cs \ SparkleHelpers.cs \ + SparkleOptions.cs \ SparklePaths.cs \ SparklePlatform.cs \ SparkleRepo.cs diff --git a/SparkleLib/SparkleHelpers.cs b/SparkleLib/SparkleHelpers.cs index 9ffe020c..f54bef61 100644 --- a/SparkleLib/SparkleHelpers.cs +++ b/SparkleLib/SparkleHelpers.cs @@ -14,176 +14,46 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -using Gtk; -using Mono.Unix; using System; using System.IO; -using System.Net; -using System.Security.Cryptography; -using System.Text; - namespace SparkleLib { public static class SparkleHelpers { - // Gets the avatar for a specific email address and size - public static Gdk.Pixbuf GetAvatar (string Email, int Size) - { - - string AvatarPath = CombineMore (SparklePaths.SparkleLocalIconPath, Size + "x" + Size, "status"); - - if (!Directory.Exists (AvatarPath)) { - Directory.CreateDirectory (AvatarPath); - SparkleHelpers.DebugInfo ("Config", "Created '" + AvatarPath + "'"); - } - - string AvatarFilePath = CombineMore (AvatarPath, "avatar-" + Email); - - if (File.Exists (AvatarFilePath)) - return new Gdk.Pixbuf (AvatarFilePath); - else { - - // Let's try to get the person's gravatar for next time - WebClient WebClient = new WebClient (); - Uri GravatarUri = new Uri ("http://www.gravatar.com/avatar/" + GetMD5 (Email) + - ".jpg?s=" + Size + "&d=404"); - - string TmpFile = CombineMore (SparklePaths.SparkleTmpPath, Email + Size); - - if (!File.Exists (TmpFile)) { - - WebClient.DownloadFileAsync (GravatarUri, TmpFile); - WebClient.DownloadFileCompleted += delegate { - File.Delete (AvatarFilePath); - FileInfo TmpFileInfo = new FileInfo (TmpFile); - if (TmpFileInfo.Length > 255) - File.Move (TmpFile, AvatarFilePath); - }; - - } - - // Fall back to a generic icon if there is no gravatar - if (File.Exists (AvatarFilePath)) - return new Gdk.Pixbuf (AvatarFilePath); - else - return GetIcon ("avatar-default", Size); - - } - - } - - - // Creates an MD5 hash of input - 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 ("-", ""); - } - - // Makes it possible to combine more than - // two paths at once - public static string CombineMore (params string [] Parts) - { - string NewPath = " "; - foreach (string Part in Parts) - NewPath = Path.Combine (NewPath, Part); - return NewPath; - } - - - // Looks up an icon from the system's theme - public static Gdk.Pixbuf GetIcon (string name, int size) - { - - IconTheme IconTheme = new IconTheme (); - IconTheme.AppendSearchPath (SparklePaths.SparkleIconPath); - IconTheme.AppendSearchPath (SparklePaths.SparkleLocalIconPath); - - try { - - return IconTheme.LoadIcon (name, size, IconLookupFlags.GenericFallback); - - } catch { - - try { - - return IconTheme.LoadIcon ("gtk-missing-image", size, IconLookupFlags.GenericFallback); - - } catch { - - return null; - - } - - } - - } - - public static bool ShowDebugInfo = true; // Show debug info if needed - public static void DebugInfo (string Type, string Message) + public static void DebugInfo (string type, string message) { if (ShowDebugInfo) { - DateTime DateTime = new DateTime (); - string TimeStamp = DateTime.Now.ToString ("HH:mm:ss"); - if (Message.StartsWith ("[")) - Console.WriteLine ("[" + TimeStamp + "]" + "[" + Type + "]" + Message); + + string timestamp = DateTime.Now.ToString ("HH:mm:ss"); + + if (message.StartsWith ("[")) + Console.WriteLine ("[" + timestamp + "]" + "[" + type + "]" + message); else - Console.WriteLine ("[" + TimeStamp + "]" + "[" + Type + "] " + Message); + Console.WriteLine ("[" + timestamp + "]" + "[" + type + "] " + message); + } } - // Formats a timestamp to a relative date compared to the current time - // Example: "about 5 hours ago" - public static string ToRelativeDate (DateTime date_time) + // Makes it possible to combine more than + // two paths at once + public static string CombineMore (params string [] parts) { - TimeSpan time_span = new TimeSpan (0); - time_span = DateTime.Now - date_time; + string new_path = ""; - if (time_span <= TimeSpan.FromSeconds (60)) { - return string.Format (Catalog.GetPluralString ("a second ago", "{0} seconds ago", - time_span.Seconds), - time_span.Seconds); - } + foreach (string part in parts) + new_path = Path.Combine (new_path, part); - if (time_span <= TimeSpan.FromSeconds (60)) { - return string.Format (Catalog.GetPluralString ("a minute ago", "about {0} minutes ago", - time_span.Minutes), - time_span.Minutes); - } - - if (time_span <= TimeSpan.FromHours (24)) { - return string.Format (Catalog.GetPluralString ("about an hour ago", "about {0} hours ago", - time_span.Hours), - time_span.Hours); - } - - if (time_span <= TimeSpan.FromDays (30)) { - return string.Format (Catalog.GetPluralString ("yesterday", "{0} days ago", - time_span.Days), - time_span.Days); - } - - if (time_span <= TimeSpan.FromDays (365)) { - return string.Format (Catalog.GetPluralString ("a month ago", "{0} months ago", - (int) time_span.Days / 30), - (int) time_span.Days / 30); - } - - return string.Format (Catalog.GetPluralString ("a year ago", "{0} years ago", - (int) time_span.Days / 365), - (int) time_span.Days / 365); + return new_path; } diff --git a/SparkleLib/SparkleLib.csproj b/SparkleLib/SparkleLib.csproj index 06b0e3cb..b2decdeb 100644 --- a/SparkleLib/SparkleLib.csproj +++ b/SparkleLib/SparkleLib.csproj @@ -30,9 +30,6 @@ - - gtk-sharp-2.0 - @@ -42,6 +39,8 @@ + + diff --git a/SparkleLib/SparkleRepo.cs b/SparkleLib/SparkleRepo.cs index 499d8a58..370b1deb 100644 --- a/SparkleLib/SparkleRepo.cs +++ b/SparkleLib/SparkleRepo.cs @@ -775,40 +775,4 @@ namespace SparkleLib { } - // Arguments for most events - public class SparkleEventArgs : System.EventArgs { - - public string Type; - public string Message; - - public SparkleEventArgs (string type) - { - - Type = type; - - } - - } - - - // Arguments for the NewCommit event - public class NewCommitArgs : System.EventArgs { - - public string Author; - public string Email; - public string Message; - public string RepositoryName; - - public NewCommitArgs (string author, string email, string message, string repository_name) - { - - Author = author; - Email = email; - Message = message; - RepositoryName = repository_name; - - } - - } - } diff --git a/SparkleShare/Makefile.am b/SparkleShare/Makefile.am index 0d4e89c6..e898ceff 100644 --- a/SparkleShare/Makefile.am +++ b/SparkleShare/Makefile.am @@ -18,6 +18,7 @@ SOURCES = \ SparkleSpinner.cs \ SparkleStatusIcon.cs \ SparkleUI.cs \ + SparkleUIHelpers.cs \ SparkleWindow.cs include $(top_srcdir)/build/build.mk diff --git a/SparkleShare/SparkleIntro.cs b/SparkleShare/SparkleIntro.cs index a76697ab..4995e02b 100644 --- a/SparkleShare/SparkleIntro.cs +++ b/SparkleShare/SparkleIntro.cs @@ -172,7 +172,7 @@ namespace SparkleShare { HBox layout_server = new HBox (true, 0); ServerEntry = new SparkleEntry () { - ExampleText = _("ssh://address-to-my-server/") + ExampleText = _("address-to-server.com") }; ServerEntry.Changed += CheckServerForm; @@ -295,9 +295,18 @@ namespace SparkleShare { if (name.EndsWith ("/")) name = name.TrimEnd ("/".ToCharArray ()); + if (name.StartsWith ("/")) + name = name.TrimStart ("/".ToCharArray ()); + if (radio_button.Active) { - server = SparkleToGitUrl (ServerEntry.Text); + // Use the default user 'git' if no username is specified + if (!server.Contains ("@")) + server = "git@" + server; + + // Prepend the Secure Shell protocol when it isn't specified + if (!server.StartsWith ("ssh://")) + server = "ssh://" + server; // Remove the trailing slash if there is one if (server.EndsWith ("/")) @@ -368,6 +377,7 @@ namespace SparkleShare { } + // The page shown when syncing has failed private void ShowErrorPage () { @@ -401,54 +411,56 @@ namespace SparkleShare { } + // The page shown when syncing has succeeded private void ShowSuccessPage (string name) { Reset (); - VBox layout_vertical = new VBox (false, 0); + VBox layout_vertical = new VBox (false, 0); - Label header = new Label ("" + - _("Folder synced successfully!") + - "") { - UseMarkup = true, - Xalign = 0 - }; - - Label information = new Label (_("Now you can access the synced files from ‘" + name + "’ " + - "in your SparkleShare folder.")) { - Xalign = 0, - Wrap = true, - UseMarkup = true - }; + Label header = new Label ("" + + _("Folder synced successfully!") + + "") { + UseMarkup = true, + Xalign = 0 + }; + + Label information = new Label (_("Now you can access the synced files from ‘" + name + "’ " + + "in your SparkleShare folder.")) { + Xalign = 0, + Wrap = true, + UseMarkup = true + }; - Button open_folder_button = new Button (_("Open Folder")); + // A button that opens the synced folder + Button open_folder_button = new Button (_("Open Folder")); - open_folder_button.Clicked += delegate (object o, EventArgs args) { + open_folder_button.Clicked += delegate (object o, EventArgs args) { - string path = SparkleHelpers.CombineMore (SparklePaths.SparklePath, name); + string path = SparkleHelpers.CombineMore (SparklePaths.SparklePath, name); - Process process = new Process (); - process.StartInfo.FileName = "xdg-open"; - process.StartInfo.Arguments = path.Replace (" ", "\\ "); // Escape space-characters - process.Start (); + Process process = new Process (); + process.StartInfo.FileName = "xdg-open"; + process.StartInfo.Arguments = path.Replace (" ", "\\ "); // Escape space-characters + process.Start (); - if (ServerFormOnly) - Destroy (); - - }; - - Button finish_button = new Button (_("Finish")); - - finish_button.Clicked += delegate (object o, EventArgs args) { + if (ServerFormOnly) Destroy (); - }; - - AddButton (open_folder_button); - AddButton (finish_button); - layout_vertical.PackStart (header, false, false, 0); - layout_vertical.PackStart (information, false, false, 21); + }; + + Button finish_button = new Button (_("Finish")); + + finish_button.Clicked += delegate (object o, EventArgs args) { + Destroy (); + }; + + AddButton (open_folder_button); + AddButton (finish_button); + + layout_vertical.PackStart (header, false, false, 0); + layout_vertical.PackStart (information, false, false, 21); Add (layout_vertical); @@ -457,55 +469,56 @@ namespace SparkleShare { } + // The page shown whilst syncing private void ShowSyncingPage (string name) { Reset (); - VBox layout_vertical = new VBox (false, 0); + VBox layout_vertical = new VBox (false, 0); - Label header = new Label ("" + - String.Format (_("Syncing folder ‘{0}’…"), name) + - "") { - UseMarkup = true, - Xalign = 0, - Wrap = true - }; - - Label information = new Label (_("This may take a while.\n") + - _("You sure it’s not coffee o-clock?")) { - UseMarkup = true, - Xalign = 0 - }; - - - Button button = new Button () { - Sensitive = false, - Label = _("Finish") - }; - - button.Clicked += delegate { - Destroy (); - }; - - AddButton (button); - - SparkleSpinner spinner = new SparkleSpinner (22); - - Table table = new Table (2, 2, false) { - RowSpacing = 12, - ColumnSpacing = 9 + Label header = new Label ("" + + String.Format (_("Syncing folder ‘{0}’…"), name) + + "") { + UseMarkup = true, + Xalign = 0, + Wrap = true }; - HBox box = new HBox (false, 0); + Label information = new Label (_("This may take a while.\n") + + _("You sure it’s not coffee o-clock?")) { + UseMarkup = true, + Xalign = 0 + }; - table.Attach (spinner, 0, 1, 0, 1); - table.Attach (header, 1, 2, 0, 1); - table.Attach (information, 1, 2, 1, 2); - box.PackStart (table, false, false, 0); + Button button = new Button () { + Sensitive = false, + Label = _("Finish") + }; + + button.Clicked += delegate { + Destroy (); + }; - layout_vertical.PackStart (box, false, false, 0); + AddButton (button); + + SparkleSpinner spinner = new SparkleSpinner (22); + + Table table = new Table (2, 2, false) { + RowSpacing = 12, + ColumnSpacing = 9 + }; + + HBox box = new HBox (false, 0); + + table.Attach (spinner, 0, 1, 0, 1); + table.Attach (header, 1, 2, 0, 1); + table.Attach (information, 1, 2, 1, 2); + + box.PackStart (table, false, false, 0); + + layout_vertical.PackStart (box, false, false, 0); Add (layout_vertical); @@ -514,6 +527,7 @@ namespace SparkleShare { } + // The page shown when the setup has been completed private void ShowCompletedPage () { @@ -572,9 +586,11 @@ namespace SparkleShare { private void FetchFolder (string url, string name) { + // Strip the '.git' from the name string canonical_name = System.IO.Path.GetFileNameWithoutExtension (name); string tmp_folder = SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, canonical_name); + ShowSyncingPage (canonical_name); SparkleFetcher fetcher = new SparkleFetcher (url, tmp_folder); @@ -643,8 +659,6 @@ namespace SparkleShare { }; - ShowSyncingPage (canonical_name); - fetcher.Clone (); } @@ -806,19 +820,6 @@ namespace SparkleShare { } - - // Convert the more human readable sparkle:// url to something Git can use. - // Example: sparkle://gitorious.org/sparkleshare ssh://git@gitorious.org/sparkleshare - private static string SparkleToGitUrl (string url) - { - - if (url.StartsWith ("sparkle://")) - url = url.Replace ("sparkle://", "ssh://git@"); - - return url; - - } - } } diff --git a/SparkleShare/SparkleLog.cs b/SparkleShare/SparkleLog.cs index b39e514c..a758c410 100644 --- a/SparkleShare/SparkleLog.cs +++ b/SparkleShare/SparkleLog.cs @@ -290,10 +290,6 @@ namespace SparkleShare { link.ModifyBg (StateType.Normal, background_color); - link.ButtonPressEvent += delegate { - Destroy (); - }; - added_files.PackStart (link, false, false, 0); } @@ -306,10 +302,6 @@ namespace SparkleShare { link.ModifyBg (StateType.Normal, background_color); - link.ButtonPressEvent += delegate { - Destroy (); - }; - deleted_files.PackStart (link, false, false, 0); } @@ -321,19 +313,11 @@ namespace SparkleShare { from_link.ModifyBg (StateType.Normal, background_color); - from_link.ButtonPressEvent += delegate { - Destroy (); - }; - SparkleLink to_link = new SparkleLink (change_set.MovedTo [i], SparkleHelpers.CombineMore (LocalPath, change_set.MovedTo [i])); to_link.ModifyBg (StateType.Normal, background_color); - to_link.ButtonPressEvent += delegate { - Destroy (); - }; - Label to_label = new Label ("" + "to ") { UseMarkup = true, @@ -344,10 +328,11 @@ namespace SparkleShare { link_wrapper.PackStart (to_label, false, false, 0); link_wrapper.PackStart (to_link, true, true, 0); - moved_files.PackStart (from_link, false, false, 0); moved_files.PackStart (link_wrapper, false, false, 0); - moved_files.PackStart (new Label (""), false, false, 0); + + if (change_set.MovedFrom.Count > 1) + moved_files.PackStart (new Label (""), false, false, 0); } @@ -419,7 +404,7 @@ namespace SparkleShare { HBox hbox = new HBox (false, 0); - Image avatar = new Image (SparkleHelpers.GetAvatar (change_set.UserEmail, 32)) { + Image avatar = new Image (SparkleUIHelpers.GetAvatar (change_set.UserEmail, 32)) { Yalign = 0 }; @@ -452,7 +437,7 @@ namespace SparkleShare { // Converts a UNIX timestamp to a more usable time object - public DateTime UnixTimestampToDateTime (int timestamp) + public static DateTime UnixTimestampToDateTime (int timestamp) { DateTime unix_epoch = new DateTime (1970, 1, 1, 0, 0, 0, 0); return unix_epoch.AddSeconds (timestamp); @@ -461,7 +446,7 @@ namespace SparkleShare { // Converts a Gdk RGB color to a hex value. // Example: from "rgb:0,0,0" to "#000000" - public string GdkColorToHex (Gdk.Color color) + public static string GdkColorToHex (Gdk.Color color) { return String.Format ("#{0:X2}{1:X2}{2:X2}", @@ -481,16 +466,18 @@ namespace SparkleShare { public ActivityDay (DateTime date_time) { + DateTime = date_time; DateTime = new DateTime (DateTime.Year, DateTime.Month, DateTime.Day); + } } - + // TODO: Move this to the repo public class ChangeSet { - + public string UserName; public string UserEmail; public string Message; @@ -501,7 +488,7 @@ namespace SparkleShare { public List MovedTo; public DateTime DateTime; public string Hash; - + public ChangeSet (string user_name, string user_email, string message, DateTime date_time, string hash) { @@ -511,9 +498,9 @@ namespace SparkleShare { DateTime = date_time; Hash = hash; - Edited = new List (); - Added = new List (); - Deleted = new List (); + Edited = new List (); + Added = new List (); + Deleted = new List (); MovedFrom = new List (); MovedTo = new List (); diff --git a/SparkleShare/SparkleSpinner.cs b/SparkleShare/SparkleSpinner.cs index 1622e567..5d83d3b9 100644 --- a/SparkleShare/SparkleSpinner.cs +++ b/SparkleShare/SparkleSpinner.cs @@ -41,7 +41,7 @@ namespace SparkleShare { CycleDuration = 600; CurrentStep = 0; - Gdk.Pixbuf spinner_gallery = SparkleHelpers.GetIcon ("process-working", Size); + Gdk.Pixbuf spinner_gallery = SparkleUIHelpers.GetIcon ("process-working", Size); int frames_in_width = spinner_gallery.Width / Size; int frames_in_height = spinner_gallery.Height / Size; diff --git a/SparkleShare/SparkleStatusIcon.cs b/SparkleShare/SparkleStatusIcon.cs index 812b6d2e..0c3871e1 100644 --- a/SparkleShare/SparkleStatusIcon.cs +++ b/SparkleShare/SparkleStatusIcon.cs @@ -37,7 +37,6 @@ namespace SparkleShare { private Gdk.Pixbuf [] AnimationFrames; private int FrameNumber; - private Gtk.Action FolderAction; private double FolderSize; @@ -79,7 +78,7 @@ namespace SparkleShare { { Gdk.Pixbuf [] animation_frames = new Gdk.Pixbuf [5]; - Gdk.Pixbuf frames_pixbuf = SparkleHelpers.GetIcon ("process-syncing-sparkleshare", 24); + Gdk.Pixbuf frames_pixbuf = SparkleUIHelpers.GetIcon ("process-syncing-sparkleshare", 24); for (int i = 0; i < animation_frames.Length; i++) animation_frames [i] = new Gdk.Pixbuf (frames_pixbuf, (i * 24), 0, 24, 24); @@ -133,7 +132,7 @@ namespace SparkleShare { double size = 0; - // Ignore the temporary rebase-apply directory. + // Ignore the temporary 'rebase-apply' directory // This prevents potential crashes when files are being // queried whilst the files have already been deleted. if (parent.Name.Equals ("rebase-apply")) @@ -164,25 +163,30 @@ namespace SparkleShare { } - // Format a file size nicely. + // Format a file size nicely with small caps. // Example: 1048576 becomes "1 ᴍʙ" private string FormatFileSize (double byte_count) { - string size = ""; - if (byte_count >= 1099511627776) - size = String.Format (_("{0:##.##} ᴛʙ"), Math.Round (byte_count / 1099511627776, 1)); - else if (byte_count >= 1073741824) - size = String.Format (_("{0:##.##} ɢʙ"), Math.Round (byte_count / 1073741824, 1)); - else if (byte_count >= 1048576) - size = String.Format (_("{0:##.##} ᴍʙ"), Math.Round (byte_count / 1048576, 1)); - else if (byte_count >= 1024) - size = String.Format (_("{0:##.##} ᴋʙ"), Math.Round (byte_count / 1024, 1)); - else - size = byte_count.ToString () + " bytes"; - return size; + return String.Format ("{0:##.##} ᴛʙ", Math.Round (byte_count / 1099511627776, 1)); + + else if (byte_count >= 1073741824) + + return String.Format ("{0:##.##} ɢʙ", Math.Round (byte_count / 1073741824, 1)); + + else if (byte_count >= 1048576) + + return String.Format ("{0:##.##} ᴍʙ", Math.Round (byte_count / 1048576, 1)); + + else if (byte_count >= 1024) + + return String.Format ("{0:##.##} ᴋʙ", Math.Round (byte_count / 1024, 1)); + + else + + return byte_count.ToString () + " bytes"; } @@ -194,20 +198,21 @@ namespace SparkleShare { Menu = new Menu (); + // The menu item showing the status and size of the SparkleShare folder StatusMenuItem = new MenuItem (StateText) { Sensitive = false }; Menu.Add (StatusMenuItem); - Menu.Add (new SeparatorMenuItem ()); - FolderAction = new Gtk.Action ("", "SparkleShare") { + // A menu item that provides a link to the SparkleShare folder + Gtk.Action folder_action = new Gtk.Action ("", "SparkleShare") { IconName = "folder-sparkleshare", IsImportant = true }; - FolderAction.Activated += delegate { + folder_action.Activated += delegate { Process process = new Process (); process.StartInfo.FileName = "xdg-open"; @@ -216,20 +221,22 @@ namespace SparkleShare { }; - Menu.Add (FolderAction.CreateMenuItem ()); + Menu.Add (folder_action.CreateMenuItem ()); + if (SparkleUI.Repositories.Count > 0) { + // Creates a menu item for each repository with a link to them foreach (SparkleRepo repo in SparkleUI.Repositories) { - FolderAction = new Gtk.Action ("", repo.Name) { + folder_action = new Gtk.Action ("", repo.Name) { IconName = "folder", IsImportant = true }; - FolderAction.Activated += CreateWindowDelegate (repo.LocalPath); + folder_action.Activated += CreateWindowDelegate (repo.LocalPath); - MenuItem menu_item = (MenuItem) FolderAction.CreateMenuItem (); + MenuItem menu_item = (MenuItem) folder_action.CreateMenuItem (); if (repo.Description != null) menu_item.TooltipText = repo.Description; @@ -258,7 +265,6 @@ namespace SparkleShare { }; Menu.Add (add_item); - Menu.Add (new SeparatorMenuItem ()); CheckMenuItem notify_item = new CheckMenuItem (_("Show Notifications")); @@ -296,11 +302,9 @@ namespace SparkleShare { }; Menu.Add (about_item); - Menu.Add (new SeparatorMenuItem ()); - MenuItem quit_item = new MenuItem (_("Quit")); - + MenuItem quit_item = new MenuItem (_("Quit")); quit_item.Activated += Quit; Menu.Add (quit_item); @@ -320,9 +324,7 @@ namespace SparkleShare { private void UpdateStatusMenuItem () { - Label label = (Label) StatusMenuItem.Children [0]; - label.Text = StateText; - + (StatusMenuItem.Children [0] as Label).Text = StateText; Menu.ShowAll (); } @@ -336,6 +338,7 @@ namespace SparkleShare { } + // Shows the state and keeps the number of syncing repositories in mind public void ShowState (bool error) { @@ -394,7 +397,7 @@ namespace SparkleShare { { Timer.Stop (); - Application.Invoke (delegate { Pixbuf = SparkleHelpers.GetIcon ("sparkleshare-syncing-error", 24); }); + Application.Invoke (delegate { Pixbuf = SparkleUIHelpers.GetIcon ("sparkleshare-syncing-error", 24); }); StateText = _("Failed to sync changes"); } diff --git a/SparkleShare/SparkleUI.cs b/SparkleShare/SparkleUI.cs index 36b79ed6..1e4d9806 100644 --- a/SparkleShare/SparkleUI.cs +++ b/SparkleShare/SparkleUI.cs @@ -311,7 +311,7 @@ namespace SparkleShare { if (File.Exists (notify_settings_file)) { SparkleBubble bubble = new SparkleBubble (author, message) { - Icon = SparkleHelpers.GetAvatar (email, 32) + Icon = SparkleUIHelpers.GetAvatar (email, 32) }; bubble.AddAction ("", "Show Events", delegate { diff --git a/SparkleShare/SparkleUIHelpers.cs b/SparkleShare/SparkleUIHelpers.cs new file mode 100644 index 00000000..d9163527 --- /dev/null +++ b/SparkleShare/SparkleUIHelpers.cs @@ -0,0 +1,126 @@ +// SparkleShare, an instant update workflow to Git. +// Copyright (C) 2010 Hylke Bons +// +// 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 3 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 . + +using Gtk; +using SparkleLib; +using System; +using System.IO; +using System.Net; +using System.Security.Cryptography; +using System.Text; + +namespace SparkleShare { + + public static class SparkleUIHelpers + { + + // Creates an MD5 hash of input + 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 ("-", ""); + } + + + // Gets the avatar for a specific email address and size + public static Gdk.Pixbuf GetAvatar (string email, int size) + { + + string avatar_path = SparkleHelpers.CombineMore (SparklePaths.SparkleLocalIconPath, + size + "x" + size, "status"); + + if (!Directory.Exists (avatar_path)) { + + Directory.CreateDirectory (avatar_path); + SparkleHelpers.DebugInfo ("Config", "Created '" + avatar_path + "'"); + + } + + string avatar_file_path = SparkleHelpers.CombineMore (avatar_path, "avatar-" + email); + + if (File.Exists (avatar_file_path)) { + + return new Gdk.Pixbuf (avatar_file_path); + + } else { + + // Let's try to get the person's gravatar for next time + WebClient WebClient = new WebClient (); + Uri uri = new Uri ("http://www.gravatar.com/avatar/" + GetMD5 (email) + + ".jpg?s=" + size + "&d=404"); + + string tmp_file_path = SparkleHelpers.CombineMore (SparklePaths.SparkleTmpPath, email + size); + + if (!File.Exists (tmp_file_path)) { + + WebClient.DownloadFileAsync (uri, tmp_file_path); + + WebClient.DownloadFileCompleted += delegate { + + File.Delete (avatar_file_path); + FileInfo tmp_file_info = new FileInfo (tmp_file_path); + + if (tmp_file_info.Length > 255) + File.Move (tmp_file_path, avatar_file_path); + + }; + + } + + // Fall back to a generic icon if there is no gravatar + if (File.Exists (avatar_file_path)) + return new Gdk.Pixbuf (avatar_file_path); + else + return GetIcon ("avatar-default", size); + + } + + } + + + // Looks up an icon from the system's theme + public static Gdk.Pixbuf GetIcon (string name, int size) + { + + IconTheme icon_theme = new IconTheme (); + icon_theme.AppendSearchPath (SparklePaths.SparkleIconPath); + icon_theme.AppendSearchPath (SparklePaths.SparkleLocalIconPath); + + try { + + return icon_theme.LoadIcon (name, size, IconLookupFlags.GenericFallback); + + } catch { + + try { + + return icon_theme.LoadIcon ("gtk-missing-image", size, IconLookupFlags.GenericFallback); + + } catch { + + return null; + + } + + } + + } + + } + +}