gravatar support, code cleanup, 0.0.8
This commit is contained in:
parent
18f48b8706
commit
8ddff52a66
BIN
data/icons/hicolor/48x48/status/avatar-default.png
Normal file
BIN
data/icons/hicolor/48x48/status/avatar-default.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.2 KiB |
|
@ -1,4 +1,4 @@
|
||||||
// SparklePony 0.0.7
|
// SparklePony 0.0.8
|
||||||
|
|
||||||
// SparklePony, an instant update workflow to Git.
|
// SparklePony, an instant update workflow to Git.
|
||||||
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
using Gtk;
|
using Gtk;
|
||||||
using Notifications;
|
using Notifications;
|
||||||
|
using SparklePonyHelpers;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
@ -42,7 +43,8 @@ public class SparklePony {
|
||||||
Process.StartInfo.FileName = "git";
|
Process.StartInfo.FileName = "git";
|
||||||
Process.Start();
|
Process.Start();
|
||||||
if (Process.StandardOutput.ReadToEnd().IndexOf ("version") == -1) {
|
if (Process.StandardOutput.ReadToEnd().IndexOf ("version") == -1) {
|
||||||
Console.WriteLine ("Git wasn't found.\nYou can get it from http://git-scm.com/.");
|
Console.WriteLine ("Git wasn't found.");
|
||||||
|
Console.WriteLine ("You can get it from http://git-scm.com/.");
|
||||||
Environment.Exit (0);
|
Environment.Exit (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,10 +52,12 @@ public class SparklePony {
|
||||||
Process.StartInfo.FileName = "whoami";
|
Process.StartInfo.FileName = "whoami";
|
||||||
Process.Start();
|
Process.Start();
|
||||||
if (Process.StandardOutput.ReadToEnd().Trim ().Equals ("root")) {
|
if (Process.StandardOutput.ReadToEnd().Trim ().Equals ("root")) {
|
||||||
Console.WriteLine ("Sorry, you can't run SparklePony as root.\nThings will go utterly wrong.");
|
Console.WriteLine ("Sorry, you can't run SparklePony as root.");
|
||||||
|
Console.WriteLine ("Things will go utterly wrong.");
|
||||||
Environment.Exit (0);
|
Environment.Exit (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the command line arguments
|
||||||
bool HideUI = false;
|
bool HideUI = false;
|
||||||
if (args.Length > 0) {
|
if (args.Length > 0) {
|
||||||
foreach (string Argument in args) {
|
foreach (string Argument in args) {
|
||||||
|
@ -64,11 +68,14 @@ public class SparklePony {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Gtk.Application.Init ();
|
Gtk.Application.Init ();
|
||||||
|
|
||||||
SparklePonyUI = new SparklePonyUI (HideUI);
|
SparklePonyUI = new SparklePonyUI (HideUI);
|
||||||
SparklePonyUI.StartMonitoring ();
|
SparklePonyUI.StartMonitoring ();
|
||||||
|
|
||||||
Gtk.Application.Run ();
|
Gtk.Application.Run ();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ShowHelp () {
|
public static void ShowHelp () {
|
||||||
|
@ -92,6 +99,7 @@ public class SparklePony {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Holds the status icon, window and repository list
|
||||||
public class SparklePonyUI {
|
public class SparklePonyUI {
|
||||||
|
|
||||||
public SparklePonyWindow SparklePonyWindow;
|
public SparklePonyWindow SparklePonyWindow;
|
||||||
|
@ -118,13 +126,28 @@ public class SparklePonyUI {
|
||||||
// Create place to store configuration user's home folder
|
// Create place to store configuration user's home folder
|
||||||
string ConfigPath = UserHome + ".config/sparklepony/";
|
string ConfigPath = UserHome + ".config/sparklepony/";
|
||||||
if (!Directory.Exists (ConfigPath)) {
|
if (!Directory.Exists (ConfigPath)) {
|
||||||
|
|
||||||
Directory.CreateDirectory (ConfigPath);
|
Directory.CreateDirectory (ConfigPath);
|
||||||
Console.WriteLine ("[Config] Created '" + ConfigPath + "'");
|
Console.WriteLine ("[Config] Created '" + ConfigPath + "'");
|
||||||
Directory.CreateDirectory (ConfigPath + "gravatars");
|
|
||||||
Console.WriteLine ("[Config] Created '" + ConfigPath + "gravatars'");
|
// Create a first run file to show the intro message
|
||||||
|
File.Create (ConfigPath + "firstrun");
|
||||||
|
Console.WriteLine ("[Config] Created '" + ConfigPath + "firstrun'");
|
||||||
|
|
||||||
|
// Create a place to store the avatars
|
||||||
|
Directory.CreateDirectory (ConfigPath + "avatars/");
|
||||||
|
Console.WriteLine ("[Config] Created '" + ConfigPath + "avatars'");
|
||||||
|
|
||||||
|
Directory.CreateDirectory (ConfigPath + "avatars/22x22/");
|
||||||
|
Console.WriteLine ("[Config] Created '" + ConfigPath +
|
||||||
|
"avatars/22x22/'");
|
||||||
|
|
||||||
|
Directory.CreateDirectory (ConfigPath + "avatars/48x48/");
|
||||||
|
Console.WriteLine ("[Config] Created '" + ConfigPath +
|
||||||
|
"avatars/48x48/'");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all the Repos in ~/SparklePony
|
// Get all the repos in ~/SparklePony
|
||||||
string [] Repos = Directory.GetDirectories (ReposPath);
|
string [] Repos = Directory.GetDirectories (ReposPath);
|
||||||
Repositories = new Repository [Repos.Length];
|
Repositories = new Repository [Repos.Length];
|
||||||
|
|
||||||
|
@ -134,7 +157,8 @@ public class SparklePonyUI {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't create the window and status icon if --disable-gui was given
|
// Don't create the window and status
|
||||||
|
// icon when --disable-gui was given
|
||||||
if (!HideUI) {
|
if (!HideUI) {
|
||||||
|
|
||||||
// Create the window
|
// Create the window
|
||||||
|
@ -143,12 +167,15 @@ public class SparklePonyUI {
|
||||||
|
|
||||||
// Create the status icon
|
// Create the status icon
|
||||||
SparklePonyStatusIcon = new SparklePonyStatusIcon ();
|
SparklePonyStatusIcon = new SparklePonyStatusIcon ();
|
||||||
SparklePonyStatusIcon.Activate += delegate { SparklePonyWindow.ToggleVisibility (); };
|
SparklePonyStatusIcon.Activate += delegate {
|
||||||
|
SparklePonyWindow.ToggleVisibility ();
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Closes the window
|
||||||
public void CloseSparklePonyWindow (object o, DeleteEventArgs args) {
|
public void CloseSparklePonyWindow (object o, DeleteEventArgs args) {
|
||||||
SparklePonyWindow = new SparklePonyWindow (Repositories);
|
SparklePonyWindow = new SparklePonyWindow (Repositories);
|
||||||
SparklePonyWindow.DeleteEvent += CloseSparklePonyWindow;
|
SparklePonyWindow.DeleteEvent += CloseSparklePonyWindow;
|
||||||
|
@ -162,12 +189,27 @@ public class SparklePonyUI {
|
||||||
public class SparklePonyStatusIcon : StatusIcon {
|
public class SparklePonyStatusIcon : StatusIcon {
|
||||||
|
|
||||||
public SparklePonyStatusIcon () : base () {
|
public SparklePonyStatusIcon () : base () {
|
||||||
|
|
||||||
IconName = "folder-publicshare";
|
IconName = "folder-publicshare";
|
||||||
// TODO: Only on first run
|
|
||||||
Notification Notification = new Notification ("Welcome to SparklePony!", "Click here to add some folders.");
|
string UserHome = Environment.GetEnvironmentVariable("HOME") + "/";
|
||||||
Notification.Urgency = Urgency.Normal;
|
string FirstRunFile = UserHome + ".config/sparklepony/firstrun";
|
||||||
Notification.Timeout = 7500;
|
|
||||||
Notification.Show ();
|
// Show a notification on the first run
|
||||||
|
if (File.Exists (FirstRunFile)) {
|
||||||
|
|
||||||
|
Notification Notification;
|
||||||
|
Notification = new Notification ("Welcome to SparklePony!",
|
||||||
|
"Click here to add some folders.");
|
||||||
|
|
||||||
|
Notification.Urgency = Urgency.Normal;
|
||||||
|
Notification.Timeout = 7500;
|
||||||
|
Notification.Show ();
|
||||||
|
|
||||||
|
File.Delete (FirstRunFile);
|
||||||
|
Console.WriteLine ("[Config] Deleted '" + FirstRunFile + "'");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetIdleState () {
|
public void SetIdleState () {
|
||||||
|
@ -233,7 +275,9 @@ public class Repository {
|
||||||
RemoteOriginUrl = Process.StandardOutput.ReadToEnd().Trim ();
|
RemoteOriginUrl = Process.StandardOutput.ReadToEnd().Trim ();
|
||||||
|
|
||||||
// Get the repository name, example: "Project"
|
// Get the repository name, example: "Project"
|
||||||
Name = RepoPath.Substring (RepoPath.TrimEnd ( "/".ToCharArray ()).LastIndexOf ("/") + 1);
|
|
||||||
|
string s = RepoPath.TrimEnd ( "/".ToCharArray ());
|
||||||
|
Name = RepoPath.Substring (s.LastIndexOf ("/") + 1);
|
||||||
|
|
||||||
// Get the domain, example: "github.com"
|
// Get the domain, example: "github.com"
|
||||||
Domain = RemoteOriginUrl;
|
Domain = RemoteOriginUrl;
|
||||||
|
@ -266,25 +310,28 @@ public class Repository {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add everything that changed
|
|
||||||
// since SparklePony was stopped
|
|
||||||
|
|
||||||
FetchTimer.Start();
|
FetchTimer.Start();
|
||||||
BufferTimer = new Timer ();
|
BufferTimer = new Timer ();
|
||||||
|
|
||||||
|
// Add everything that changed
|
||||||
|
// since SparklePony was stopped
|
||||||
Add ();
|
Add ();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Starts a time buffer when something changes
|
||||||
public void OnFileActivity (object o, FileSystemEventArgs args) {
|
public void OnFileActivity (object o, FileSystemEventArgs args) {
|
||||||
WatcherChangeTypes wct = args.ChangeType;
|
WatcherChangeTypes wct = args.ChangeType;
|
||||||
if (!ShouldIgnore (args.Name) && !MonitorOnly) {
|
if (!ShouldIgnore (args.Name) && !MonitorOnly) {
|
||||||
Console.WriteLine("[" + Name + "][Event] " + wct.ToString() + " '" + args.Name + "'");
|
Console.WriteLine("[Event][" + Name + "] " + wct.ToString() +
|
||||||
|
" '" + args.Name + "'");
|
||||||
StartBufferTimer ();
|
StartBufferTimer ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A buffer that will fetch changes after
|
||||||
|
// file activity has settles down
|
||||||
public void StartBufferTimer () {
|
public void StartBufferTimer () {
|
||||||
|
|
||||||
int Interval = 2000;
|
int Interval = 2000;
|
||||||
|
@ -293,10 +340,12 @@ public class Repository {
|
||||||
// Delay for a few seconds to see if more files change
|
// Delay for a few seconds to see if more files change
|
||||||
BufferTimer.Interval = Interval;
|
BufferTimer.Interval = Interval;
|
||||||
BufferTimer.Elapsed += delegate (object o, ElapsedEventArgs args) {
|
BufferTimer.Elapsed += delegate (object o, ElapsedEventArgs args) {
|
||||||
Console.WriteLine ("[" + Name + "][Buffer] Done waiting.");
|
Console.WriteLine ("[Buffer][" + Name + "] Done waiting.");
|
||||||
Add ();
|
Add ();
|
||||||
};
|
};
|
||||||
Console.WriteLine ("[" + Name + "][Buffer] Waiting for more changes...");
|
Console.WriteLine ("[Buffer][" + Name + "] " +
|
||||||
|
"Waiting for more changes...");
|
||||||
|
|
||||||
BufferTimer.Start();
|
BufferTimer.Start();
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -305,15 +354,19 @@ public class Repository {
|
||||||
BufferTimer = new Timer ();
|
BufferTimer = new Timer ();
|
||||||
BufferTimer.Interval = Interval;
|
BufferTimer.Interval = Interval;
|
||||||
BufferTimer.Elapsed += delegate (object o, ElapsedEventArgs args) {
|
BufferTimer.Elapsed += delegate (object o, ElapsedEventArgs args) {
|
||||||
Console.WriteLine ("[" + Name + "][Buffer] Done waiting.");
|
Console.WriteLine ("[Buffer][" + Name + "] Done waiting.");
|
||||||
Add ();
|
Add ();
|
||||||
};
|
};
|
||||||
|
|
||||||
BufferTimer.Start();
|
BufferTimer.Start();
|
||||||
Console.WriteLine ("[" + Name + "][Buffer] Waiting for more changes...");
|
Console.WriteLine ("[Buffer][" + Name + "] " +
|
||||||
|
"Waiting for more changes...");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clones a remote repo
|
||||||
public void Clone () {
|
public void Clone () {
|
||||||
Process.StartInfo.Arguments = "clone " + RemoteOriginUrl;
|
Process.StartInfo.Arguments = "clone " + RemoteOriginUrl;
|
||||||
Process.Start();
|
Process.Start();
|
||||||
|
@ -325,9 +378,10 @@ public class Repository {
|
||||||
Writer.Close();
|
Writer.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stages the made changes
|
||||||
public void Add () {
|
public void Add () {
|
||||||
BufferTimer.Stop ();
|
BufferTimer.Stop ();
|
||||||
Console.WriteLine ("[" + Name + "][Git] Staging changes...");
|
Console.WriteLine ("[Git][" + Name + "] Staging changes...");
|
||||||
Process.StartInfo.Arguments = "add --all";
|
Process.StartInfo.Arguments = "add --all";
|
||||||
Process.Start();
|
Process.Start();
|
||||||
|
|
||||||
|
@ -339,17 +393,21 @@ public class Repository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Commits the made changes
|
||||||
public void Commit (string Message) {
|
public void Commit (string Message) {
|
||||||
Console.WriteLine ("[" + Name + "][Commit] " + Message);
|
Console.WriteLine ("[Commit][" + Name + "] " + Message);
|
||||||
Console.WriteLine ("[" + Name + "][Git] Commiting changes...");
|
Console.WriteLine ("[Git][" + Name + "] Commiting changes...");
|
||||||
Process.StartInfo.Arguments = "commit -m \"" + Message + "\"";
|
Process.StartInfo.Arguments = "commit -m \"" + Message + "\"";
|
||||||
Process.Start();
|
Process.Start();
|
||||||
|
ShowEventNotification (UserName + " " + Message,
|
||||||
|
SparklePonyHelpers.SparklePonyHelpers.GetAvatarFileName (UserEmail, 48), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetches changes from the remote repo
|
||||||
public void Fetch () {
|
public void Fetch () {
|
||||||
// TODO: change status icon to sync
|
// TODO: change status icon to sync
|
||||||
FetchTimer.Stop ();
|
FetchTimer.Stop ();
|
||||||
Console.WriteLine ("[" + Name + "][Git] Fetching changes...");
|
Console.WriteLine ("[Git][" + Name + "] Fetching changes...");
|
||||||
Process.StartInfo.Arguments = "fetch";
|
Process.StartInfo.Arguments = "fetch";
|
||||||
Process.Start();
|
Process.Start();
|
||||||
Process.WaitForExit ();
|
Process.WaitForExit ();
|
||||||
|
@ -357,22 +415,10 @@ public class Repository {
|
||||||
FetchTimer.Start ();
|
FetchTimer.Start ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Fetch (object o, ElapsedEventArgs args) {
|
// Merges the fetched changes
|
||||||
// TODO: What happens when network disconnects during a fetch
|
|
||||||
// TODO: change status icon to sync
|
|
||||||
FetchTimer.Stop ();
|
|
||||||
Console.WriteLine ("[" + Name + "][Git] Fetching changes...");
|
|
||||||
Process.StartInfo.Arguments = "fetch";
|
|
||||||
Process.Start();
|
|
||||||
Process.WaitForExit ();
|
|
||||||
Merge ();
|
|
||||||
FetchTimer.Start ();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Merge () {
|
public void Merge () {
|
||||||
Watcher.EnableRaisingEvents = false;
|
Watcher.EnableRaisingEvents = false;
|
||||||
Console.WriteLine ("[" + Name + "][Git] Merging fetched changes...");
|
Console.WriteLine ("[Git][" + Name + "] Merging fetched changes...");
|
||||||
Process.StartInfo.Arguments = "merge origin/master";
|
Process.StartInfo.Arguments = "merge origin/master";
|
||||||
Process.Start();
|
Process.Start();
|
||||||
Process.WaitForExit ();
|
Process.WaitForExit ();
|
||||||
|
@ -380,25 +426,41 @@ public class Repository {
|
||||||
|
|
||||||
// Show notification if there are updates
|
// Show notification if there are updates
|
||||||
if (!Output.Equals ("Already up-to-date.")) {
|
if (!Output.Equals ("Already up-to-date.")) {
|
||||||
Process.StartInfo.Arguments = "log --pretty=oneline -1";
|
|
||||||
|
// Get the last commit message
|
||||||
|
Process.StartInfo.Arguments = "log --format=\"%ae\" -1";
|
||||||
Process.Start();
|
Process.Start();
|
||||||
string LastCommitMessage = Process.StandardOutput.ReadToEnd().Trim ().Substring (41);
|
string LastCommitEmail = Process.StandardOutput.ReadToEnd().Trim ();
|
||||||
ShowNotification (LastCommitMessage, "", true);
|
|
||||||
|
// Get the last commit message
|
||||||
|
Process.StartInfo.Arguments = "log --format=\"%s\" -1";
|
||||||
|
Process.Start();
|
||||||
|
string LastCommitMessage = Process.StandardOutput.ReadToEnd().Trim ();
|
||||||
|
|
||||||
|
// Get the last commiter
|
||||||
|
Process.StartInfo.Arguments = "log --format=\"%an\" -1";
|
||||||
|
Process.Start();
|
||||||
|
string LastCommitUserName = Process.StandardOutput.ReadToEnd().Trim ();
|
||||||
|
|
||||||
|
ShowEventNotification (LastCommitUserName + " " + LastCommitMessage,
|
||||||
|
SparklePonyHelpers.SparklePonyHelpers.GetAvatarFileName (LastCommitEmail, 48), true);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Watcher.EnableRaisingEvents = true;
|
Watcher.EnableRaisingEvents = true;
|
||||||
// TODO: change status icon to normal
|
// TODO: change status icon to normal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pushes the changes to the remote repo
|
||||||
public void Push () {
|
public void Push () {
|
||||||
// TODO: What happens when network disconnects during a push
|
// TODO: What happens when network disconnects during a push
|
||||||
Console.WriteLine ("[" + Name + "][Git] Pushing changes...");
|
Console.WriteLine ("[Git][" + Name + "] Pushing changes...");
|
||||||
Process.StartInfo.Arguments = "push";
|
Process.StartInfo.Arguments = "push";
|
||||||
Process.Start();
|
Process.Start();
|
||||||
Process.WaitForExit ();
|
Process.WaitForExit ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore Repos, dotfiles, swap files and the like.
|
// Ignores Repos, dotfiles, swap files and the like.
|
||||||
public bool ShouldIgnore (string FileName) {
|
public bool ShouldIgnore (string FileName) {
|
||||||
if (FileName.Substring (0, 1).Equals (".") ||
|
if (FileName.Substring (0, 1).Equals (".") ||
|
||||||
FileName.Contains (".lock") ||
|
FileName.Contains (".lock") ||
|
||||||
|
@ -406,11 +468,13 @@ public class Repository {
|
||||||
FileName.Contains ("/.") ||
|
FileName.Contains ("/.") ||
|
||||||
Directory.Exists (RepoPath + FileName))
|
Directory.Exists (RepoPath + FileName))
|
||||||
return true; // Yes, ignore it.
|
return true; // Yes, ignore it.
|
||||||
else if (FileName.Length > 3 && FileName.Substring (FileName.Length - 4).Equals (".swp"))
|
else if (FileName.Length > 3 &&
|
||||||
|
FileName.Substring (FileName.Length - 4).Equals (".swp"))
|
||||||
return true;
|
return true;
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates a pretty commit message based on what has changed
|
||||||
public string FormatCommitMessage () {
|
public string FormatCommitMessage () {
|
||||||
|
|
||||||
bool DoneAddCommit = false;
|
bool DoneAddCommit = false;
|
||||||
|
@ -439,65 +503,84 @@ public class Repository {
|
||||||
|
|
||||||
foreach (string Line in Regex.Split (Output, "\n")) {
|
foreach (string Line in Regex.Split (Output, "\n")) {
|
||||||
|
|
||||||
|
// Format message for when files are added,
|
||||||
|
// example: "added 'file' and 3 more."
|
||||||
if (Line.IndexOf ("new file:") > -1 && !DoneAddCommit) {
|
if (Line.IndexOf ("new file:") > -1 && !DoneAddCommit) {
|
||||||
DoneAddCommit = true;
|
DoneAddCommit = true;
|
||||||
if (FilesAdded > 1)
|
if (FilesAdded > 1)
|
||||||
return "added '" +
|
return "added '" +
|
||||||
Line.Replace ("#\tnew file:", "").Trim () + "' and " + (FilesAdded - 1) + " more.";
|
Line.Replace ("#\tnew file:", "").Trim () +
|
||||||
|
"' and " + (FilesAdded - 1) + " more.";
|
||||||
else
|
else
|
||||||
return "added '" +
|
return "added '" +
|
||||||
Line.Replace ("#\tnew file:", "").Trim () + "'.";
|
Line.Replace ("#\tnew file:", "").Trim () + "'.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format message for when files are edited,
|
||||||
|
// example: "edited 'file'."
|
||||||
if (Line.IndexOf ("modified:") > -1 && !DoneEditCommit) {
|
if (Line.IndexOf ("modified:") > -1 && !DoneEditCommit) {
|
||||||
DoneEditCommit = true;
|
DoneEditCommit = true;
|
||||||
if (FilesEdited > 1)
|
if (FilesEdited > 1)
|
||||||
return "edited '" +
|
return "edited '" +
|
||||||
Line.Replace ("#\tmodified:", "").Trim () + "' and " + (FilesEdited - 1) + " more.";
|
Line.Replace ("#\tmodified:", "").Trim () +
|
||||||
|
"' and " + (FilesEdited - 1) + " more.";
|
||||||
else
|
else
|
||||||
return "edited '" +
|
return "edited '" +
|
||||||
Line.Replace ("#\tmodified:", "").Trim () + "'.";
|
Line.Replace ("#\tmodified:", "").Trim () + "'.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Line.IndexOf ("renamed:") > -1 && !DoneRenameCommit) {
|
// Format message for when files are edited,
|
||||||
DoneDeleteCommit = true;
|
// example: "deleted 'file'."
|
||||||
if (FilesRenamed > 1)
|
|
||||||
return "renamed '" +
|
|
||||||
Line.Replace ("#\trenamed:", "").Trim ().Replace (" -> ", "' to '") + "' and " + (FilesDeleted - 1) + " more.";
|
|
||||||
else
|
|
||||||
return "renamed '" +
|
|
||||||
Line.Replace ("#\trenamed:", "").Trim ().Replace (" -> ", "' to '") + "'.";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Line.IndexOf ("deleted:") > -1 && !DoneDeleteCommit) {
|
if (Line.IndexOf ("deleted:") > -1 && !DoneDeleteCommit) {
|
||||||
DoneDeleteCommit = true;
|
DoneDeleteCommit = true;
|
||||||
if (FilesDeleted > 1)
|
if (FilesDeleted > 1)
|
||||||
return "deleted '" +
|
return "deleted '" +
|
||||||
Line.Replace ("#\tdeleted:", "").Trim () + "' and " + (FilesDeleted - 1) + " more.";
|
Line.Replace ("#\tdeleted:", "").Trim () +
|
||||||
|
"' and " + (FilesDeleted - 1) + " more.";
|
||||||
else
|
else
|
||||||
return "deleted '" +
|
return "deleted '" +
|
||||||
Line.Replace ("#\tdeleted:", "").Trim () + "'.";
|
Line.Replace ("#\tdeleted:", "").Trim () + "'.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format message for when files are renamed,
|
||||||
|
// example: "renamed 'file' to 'new name'."
|
||||||
|
if (Line.IndexOf ("renamed:") > -1 && !DoneRenameCommit) {
|
||||||
|
DoneDeleteCommit = true;
|
||||||
|
if (FilesRenamed > 1)
|
||||||
|
return "renamed '" +
|
||||||
|
Line.Replace ("#\trenamed:", "").Trim ().Replace
|
||||||
|
(" -> ", "' to '") + "' and " + (FilesDeleted - 1) +
|
||||||
|
" more.";
|
||||||
|
else
|
||||||
|
return "renamed '" +
|
||||||
|
Line.Replace ("#\trenamed:", "").Trim ().Replace
|
||||||
|
(" -> ", "' to '") + "'.";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Nothing happened:
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ShowNotification (string Title, string SubText, bool ShowButtons) {
|
// Shows a notification with text and image
|
||||||
|
public void ShowEventNotification (string Title,
|
||||||
|
string IconFileName,
|
||||||
|
bool ShowButtons) {
|
||||||
|
|
||||||
Notification Notification = new Notification (Title, SubText);
|
Notification Notification = new Notification (Title, " ");
|
||||||
Notification.Urgency = Urgency.Low;
|
Notification.Urgency = Urgency.Low;
|
||||||
Notification.Timeout = 4500;
|
Notification.Timeout = 4500;
|
||||||
|
Notification.Icon = new Gdk.Pixbuf (IconFileName);
|
||||||
|
|
||||||
// Add a button to open the folder the changed file resides in
|
// Add a button to open the folder where the changed file is
|
||||||
if (ShowButtons)
|
if (ShowButtons)
|
||||||
Notification.AddAction ("", "Open Folder",
|
Notification.AddAction ("", "Open Folder",
|
||||||
delegate (object o, ActionArgs args) {
|
delegate (object o, ActionArgs args) {
|
||||||
Process.StartInfo.FileName = "xdg-open";
|
Process.StartInfo.FileName = "xdg-open";
|
||||||
Process.StartInfo.Arguments = RepoPath;
|
Process.StartInfo.Arguments = RepoPath;
|
||||||
Process.Start();
|
Process.Start();
|
||||||
Process.StartInfo.FileName = "git";
|
Process.StartInfo.FileName = "git";
|
||||||
} );
|
} );
|
||||||
Notification.Show ();
|
Notification.Show ();
|
||||||
|
@ -531,7 +614,9 @@ public class SparklePonyWindow : Window {
|
||||||
|
|
||||||
HBox LayoutHorizontal = new HBox (false, 0);
|
HBox LayoutHorizontal = new HBox (false, 0);
|
||||||
|
|
||||||
ReposStore = new ListStore (typeof (Gdk.Pixbuf), typeof (string));
|
ReposStore = new ListStore (typeof (Gdk.Pixbuf),
|
||||||
|
typeof (string));
|
||||||
|
|
||||||
LayoutVerticalLeft = CreateReposList ();
|
LayoutVerticalLeft = CreateReposList ();
|
||||||
LayoutVerticalLeft.BorderWidth = 12;
|
LayoutVerticalLeft.BorderWidth = 12;
|
||||||
|
|
||||||
|
@ -561,7 +646,10 @@ public class SparklePonyWindow : Window {
|
||||||
QuitServiceButton.Clicked += Quit;
|
QuitServiceButton.Clicked += Quit;
|
||||||
|
|
||||||
Button CloseButton = new Button (Stock.Close);
|
Button CloseButton = new Button (Stock.Close);
|
||||||
CloseButton.Clicked += delegate (object o, EventArgs args) { HideAll (); Visibility = false; };
|
CloseButton.Clicked += delegate (object o, EventArgs args) {
|
||||||
|
Visibility = false;
|
||||||
|
HideAll ();
|
||||||
|
};
|
||||||
|
|
||||||
DialogButtons.Add (QuitServiceButton);
|
DialogButtons.Add (QuitServiceButton);
|
||||||
DialogButtons.Add (CloseButton);
|
DialogButtons.Add (CloseButton);
|
||||||
|
@ -572,6 +660,7 @@ public class SparklePonyWindow : Window {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates a visual list of repositories
|
||||||
public VBox CreateReposList() {
|
public VBox CreateReposList() {
|
||||||
|
|
||||||
string RemoteFolderIcon = "/usr/share/icons/gnome/22x22/places/folder.png";
|
string RemoteFolderIcon = "/usr/share/icons/gnome/22x22/places/folder.png";
|
||||||
|
@ -579,7 +668,8 @@ public class SparklePonyWindow : Window {
|
||||||
foreach (Repository Repository in Repositories) {
|
foreach (Repository Repository in Repositories) {
|
||||||
ReposIter = ReposStore.Prepend ();
|
ReposIter = ReposStore.Prepend ();
|
||||||
ReposStore.SetValue (ReposIter, 0, new Gdk.Pixbuf (RemoteFolderIcon));
|
ReposStore.SetValue (ReposIter, 0, new Gdk.Pixbuf (RemoteFolderIcon));
|
||||||
ReposStore.SetValue (ReposIter, 1, Repository.Name + " \n" + Repository.Domain + " ");
|
ReposStore.SetValue (ReposIter, 1, Repository.Name + " \n" +
|
||||||
|
Repository.Domain + " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -593,8 +683,8 @@ public class SparklePonyWindow : Window {
|
||||||
|
|
||||||
ReposStore.IterNthChild (out ReposIter, 1);
|
ReposStore.IterNthChild (out ReposIter, 1);
|
||||||
|
|
||||||
ReposView.ActivateRow (ReposStore.GetPath (ReposIter), ReposViewColumns [1]);
|
ReposView.ActivateRow (ReposStore.GetPath (ReposIter),
|
||||||
|
ReposViewColumns [1]);
|
||||||
|
|
||||||
HBox AddRemoveButtons = new HBox (false, 6);
|
HBox AddRemoveButtons = new HBox (false, 6);
|
||||||
Button AddButton = new Button ("Add...");
|
Button AddButton = new Button ("Add...");
|
||||||
|
@ -612,8 +702,10 @@ public class SparklePonyWindow : Window {
|
||||||
VBox.PackStart (AddRemoveButtons, false, false, 0);
|
VBox.PackStart (AddRemoveButtons, false, false, 0);
|
||||||
|
|
||||||
return VBox;
|
return VBox;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates the detailed view
|
||||||
public VBox CreateDetailsView () {
|
public VBox CreateDetailsView () {
|
||||||
|
|
||||||
Label Label1 = new Label ("Remote URL: ");
|
Label Label1 = new Label ("Remote URL: ");
|
||||||
|
@ -632,8 +724,11 @@ public class SparklePonyWindow : Window {
|
||||||
Label6.UseMarkup = true;
|
Label6.UseMarkup = true;
|
||||||
Label6.SetAlignment (0, 0);
|
Label6.SetAlignment (0, 0);
|
||||||
|
|
||||||
Button NotificationsCheckButton = new CheckButton ("Notify me when something changes");
|
Button NotificationsCheckButton =
|
||||||
Button ChangesCheckButton = new CheckButton ("Synchronize my changes");
|
new CheckButton ("Notify me when something changes");
|
||||||
|
|
||||||
|
Button ChangesCheckButton =
|
||||||
|
new CheckButton ("Synchronize my changes");
|
||||||
|
|
||||||
Table Table = new Table(7, 2, false);
|
Table Table = new Table(7, 2, false);
|
||||||
Table.RowSpacing = 6;
|
Table.RowSpacing = 6;
|
||||||
|
@ -658,23 +753,30 @@ public class SparklePonyWindow : Window {
|
||||||
|
|
||||||
public ScrolledWindow CreateEventLog() {
|
public ScrolledWindow CreateEventLog() {
|
||||||
|
|
||||||
ListStore LogStore = new ListStore (typeof (Gdk.Pixbuf), typeof (string), typeof (string));
|
ListStore LogStore = new ListStore (typeof (Gdk.Pixbuf),
|
||||||
|
typeof (string),
|
||||||
|
typeof (string));
|
||||||
|
|
||||||
Process Process = new Process();
|
Process Process = new Process();
|
||||||
Process.EnableRaisingEvents = false;
|
Process.EnableRaisingEvents = false;
|
||||||
Process.StartInfo.RedirectStandardOutput = true;
|
Process.StartInfo.RedirectStandardOutput = true;
|
||||||
Process.StartInfo.UseShellExecute = false;
|
Process.StartInfo.UseShellExecute = false;
|
||||||
|
|
||||||
Process.StartInfo.FileName = "git";
|
Process.StartInfo.FileName = "git";
|
||||||
|
|
||||||
string Output = "";
|
string Output = "";
|
||||||
foreach (Repository Repository in Repositories) {
|
foreach (Repository Repository in Repositories) {
|
||||||
|
|
||||||
// We're using the snowman here to separate messages :)
|
// We're using the snowman here to separate messages :)
|
||||||
Process.StartInfo.Arguments = "log --format=\"%at☃In '" + Repository.Name + "', %an %s☃%cr\" -25";
|
Process.StartInfo.Arguments =
|
||||||
|
"log --format=\"%at☃In '" + Repository.Name + "', %an %s☃%cr\" -25";
|
||||||
|
|
||||||
Process.StartInfo.WorkingDirectory = Repository.RepoPath;
|
Process.StartInfo.WorkingDirectory = Repository.RepoPath;
|
||||||
Process.Start();
|
Process.Start();
|
||||||
Output += "\n" + Process.StandardOutput.ReadToEnd().Trim ();
|
Output += "\n" + Process.StandardOutput.ReadToEnd().Trim ();
|
||||||
}
|
}
|
||||||
string [] Lines = Regex.Split (Output.TrimStart ("\n".ToCharArray ()), "\n");
|
|
||||||
|
Output = Output.TrimStart ("\n".ToCharArray ());
|
||||||
|
string [] Lines = Regex.Split (Output, "\n");
|
||||||
|
|
||||||
// Sort by time and get the last 25
|
// Sort by time and get the last 25
|
||||||
Array.Sort (Lines);
|
Array.Sort (Lines);
|
||||||
|
@ -690,19 +792,29 @@ public class SparklePonyWindow : Window {
|
||||||
string Message = Parts [1];
|
string Message = Parts [1];
|
||||||
string TimeAgo = Parts [2];
|
string TimeAgo = Parts [2];
|
||||||
|
|
||||||
string IconFile = "/usr/share/icons/hicolor/16x16/status/document-edited.png";
|
string IconFile =
|
||||||
|
"/usr/share/icons/hicolor/16x16/status/document-edited.png";
|
||||||
|
|
||||||
if (Message.IndexOf (" added '") > -1)
|
if (Message.IndexOf (" added '") > -1)
|
||||||
IconFile = "/usr/share/icons/hicolor/16x16/status/document-added.png";
|
IconFile =
|
||||||
|
"/usr/share/icons/hicolor/16x16/status/document-added.png";
|
||||||
|
|
||||||
if (Message.IndexOf (" deleted '") > -1)
|
if (Message.IndexOf (" deleted '") > -1)
|
||||||
IconFile = "/usr/share/icons/hicolor/16x16/status/document-removed.png";
|
IconFile =
|
||||||
if (Message.IndexOf (" moved '") > -1 || Message.IndexOf (" renamed '") > -1)
|
"/usr/share/icons/hicolor/16x16/status/document-removed.png";
|
||||||
IconFile = "/usr/share/icons/hicolor/16x16/status/document-moved.png";
|
|
||||||
|
if (Message.IndexOf (" moved '") > -1 ||
|
||||||
|
Message.IndexOf (" renamed '") > -1)
|
||||||
|
|
||||||
|
IconFile =
|
||||||
|
"/usr/share/icons/hicolor/16x16/status/document-moved.png";
|
||||||
|
|
||||||
Iter = LogStore.Append ();
|
Iter = LogStore.Append ();
|
||||||
LogStore.SetValue (Iter, 0, new Gdk.Pixbuf (IconFile));
|
LogStore.SetValue (Iter, 0, new Gdk.Pixbuf (IconFile));
|
||||||
LogStore.SetValue (Iter, 1, Message);
|
LogStore.SetValue (Iter, 1, Message);
|
||||||
// TODO: right align time
|
// TODO: right align time
|
||||||
LogStore.SetValue (Iter, 2, " " + TimeAgo);
|
LogStore.SetValue (Iter, 2, " " + TimeAgo);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeView LogView = new TreeView (LogStore);
|
TreeView LogView = new TreeView (LogStore);
|
||||||
|
@ -727,6 +839,7 @@ public class SparklePonyWindow : Window {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates a visual list of people working in the repo
|
||||||
public ScrolledWindow CreatePeopleList (Repository Repository) {
|
public ScrolledWindow CreatePeopleList (Repository Repository) {
|
||||||
|
|
||||||
Process Process = new Process ();
|
Process Process = new Process ();
|
||||||
|
@ -740,12 +853,15 @@ public class SparklePonyWindow : Window {
|
||||||
Process.StartInfo.WorkingDirectory = Repository.RepoPath;
|
Process.StartInfo.WorkingDirectory = Repository.RepoPath;
|
||||||
Process.Start();
|
Process.Start();
|
||||||
|
|
||||||
|
|
||||||
|
string Output = Process.StandardOutput.ReadToEnd().Trim ();
|
||||||
string [] People = new string [50];
|
string [] People = new string [50];
|
||||||
string [] Lines = Regex.Split (Process.StandardOutput.ReadToEnd().Trim (), "\n");
|
string [] Lines = Regex.Split (Output, "\n");
|
||||||
|
|
||||||
ListStore PeopleStore = new ListStore (typeof (Gdk.Pixbuf), typeof (string), typeof (string));
|
ListStore PeopleStore = new ListStore (typeof (Gdk.Pixbuf),
|
||||||
|
typeof (string),
|
||||||
|
typeof (string));
|
||||||
|
|
||||||
string PersonIcon = "/usr/share/icons/hicolor/16x16/status/avatar-default.png";
|
|
||||||
TreeIter PeopleIter;
|
TreeIter PeopleIter;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
foreach (string Line in Lines) {
|
foreach (string Line in Lines) {
|
||||||
|
@ -753,36 +869,43 @@ public class SparklePonyWindow : Window {
|
||||||
// Only add name if it isn't there already
|
// Only add name if it isn't there already
|
||||||
if (Array.IndexOf (People, Line) == -1) {
|
if (Array.IndexOf (People, Line) == -1) {
|
||||||
|
|
||||||
People [i] = Line;
|
People [i] = Line;
|
||||||
string [] Parts = Regex.Split (Line, "☃");
|
string [] Parts = Regex.Split (Line, "☃");
|
||||||
|
|
||||||
|
string UserName = Parts [0];
|
||||||
|
string UserEmail = Parts [1];
|
||||||
|
|
||||||
// Do something special if the person is you
|
// Do something special if the person is you
|
||||||
if (Parts [0].Equals (Repository.UserName))
|
if (UserName.Equals (Repository.UserName))
|
||||||
Parts [0] += " (that's you)";
|
UserName += " (that's you)";
|
||||||
|
|
||||||
string GravatarFile = Environment.GetEnvironmentVariable("HOME") +
|
|
||||||
"/.config/sparklepony/gravatars/" + Parts [1];
|
|
||||||
|
|
||||||
// Add a gravatar if it has been downloaded before
|
|
||||||
if (File.Exists (GravatarFile))
|
|
||||||
PersonIcon = GravatarFile;
|
|
||||||
|
|
||||||
// Actually add to the list
|
// Actually add to the list
|
||||||
PeopleIter = PeopleStore.Prepend ();
|
PeopleIter = PeopleStore.Prepend ();
|
||||||
PeopleStore.SetValue (PeopleIter, 0, new Gdk.Pixbuf (PersonIcon));
|
PeopleStore.SetValue (PeopleIter, 0, new Gdk.Pixbuf (SparklePonyHelpers.SparklePonyHelpers.GetAvatarFileName (UserEmail, 22)));
|
||||||
PeopleStore.SetValue (PeopleIter, 1, Parts [0]);
|
PeopleStore.SetValue (PeopleIter, 1, UserName + " ");
|
||||||
PeopleStore.SetValue (PeopleIter, 2, Parts [1] + " ");
|
PeopleStore.SetValue (PeopleIter, 2, UserEmail + " ");
|
||||||
|
|
||||||
// Let's try to get the person's gravatar for next time
|
// Let's try to get the person's gravatar for next time
|
||||||
string AvatarsDir = Environment.GetEnvironmentVariable("HOME") + "/.config/sparklepony/gravatars/";
|
string AvatarsDirSmall =
|
||||||
|
Environment.GetEnvironmentVariable("HOME") +
|
||||||
|
"/.config/sparklepony/avatars/22x22/";
|
||||||
|
|
||||||
WebClient WebClient = new WebClient ();
|
WebClient WebClient1 = new WebClient ();
|
||||||
Uri Uri = new Uri ("http://www.gravatar.com/avatar/" + GetMD5 (Parts [1]) + ".jpg?s=22");
|
Uri UriSmall = new Uri ("http://www.gravatar.com/avatar/" + SparklePonyHelpers.SparklePonyHelpers.GetMD5 (UserEmail) + ".jpg?s=22");
|
||||||
WebClient.DownloadFileAsync (Uri, AvatarsDir + Parts [1]);
|
WebClient1.DownloadFileAsync (UriSmall, AvatarsDirSmall + UserEmail);
|
||||||
|
|
||||||
|
string AvatarsDirLarge =
|
||||||
|
Environment.GetEnvironmentVariable("HOME") +
|
||||||
|
"/.config/sparklepony/avatars/48x48/";
|
||||||
|
|
||||||
|
WebClient WebClient2 = new WebClient ();
|
||||||
|
Uri UriLarge = new Uri ("http://www.gravatar.com/avatar/" + SparklePonyHelpers.SparklePonyHelpers.GetMD5 (UserEmail) + ".jpg?s=48");
|
||||||
|
WebClient2.DownloadFileAsync (UriLarge, AvatarsDirLarge + UserEmail);
|
||||||
|
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeView PeopleView = new TreeView (PeopleStore);
|
TreeView PeopleView = new TreeView (PeopleStore);
|
||||||
PeopleView.AppendColumn ("", new CellRendererPixbuf () , "pixbuf", 0);
|
PeopleView.AppendColumn ("", new CellRendererPixbuf () , "pixbuf", 0);
|
||||||
PeopleView.AppendColumn ("", new Gtk.CellRendererText (), "text", 1);
|
PeopleView.AppendColumn ("", new Gtk.CellRendererText (), "text", 1);
|
||||||
|
@ -794,8 +917,8 @@ public class SparklePonyWindow : Window {
|
||||||
ScrolledWindow ScrolledWindow = new ScrolledWindow ();
|
ScrolledWindow ScrolledWindow = new ScrolledWindow ();
|
||||||
ScrolledWindow.AddWithViewport (PeopleView);
|
ScrolledWindow.AddWithViewport (PeopleView);
|
||||||
|
|
||||||
|
|
||||||
return ScrolledWindow;
|
return ScrolledWindow;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdatePeopleList () {
|
public void UpdatePeopleList () {
|
||||||
|
@ -817,15 +940,50 @@ public class SparklePonyWindow : Window {
|
||||||
Application.Quit ();
|
Application.Quit ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper that creates an MD5 hash
|
}
|
||||||
public static string GetMD5 (string s) {
|
|
||||||
|
|
||||||
MD5 md5 = new MD5CryptoServiceProvider ();
|
namespace SparklePonyHelpers {
|
||||||
Byte[] Bytes = ASCIIEncoding.Default.GetBytes (s);
|
|
||||||
Byte[] EncodedBytes = md5.ComputeHash (Bytes);
|
|
||||||
|
|
||||||
return BitConverter.ToString(EncodedBytes).ToLower ().Replace ("-", "");
|
|
||||||
|
// Helper that returns a user's avatar
|
||||||
|
class SparklePonyHelpers {
|
||||||
|
|
||||||
|
public static string GetAvatarFileName (string Email, int Size) {
|
||||||
|
|
||||||
|
string GravatarFile = Environment.GetEnvironmentVariable("HOME") +
|
||||||
|
"/.config/sparklepony/avatars/" +
|
||||||
|
Size + "x" + Size +
|
||||||
|
"/" + Email;
|
||||||
|
|
||||||
|
if (File.Exists (GravatarFile))
|
||||||
|
return GravatarFile;
|
||||||
|
|
||||||
|
else {
|
||||||
|
|
||||||
|
string FallbackFileName = "/usr/share/icons/hicolor/" +
|
||||||
|
Size + "x" + Size +
|
||||||
|
"/status/avatar-default.png";
|
||||||
|
|
||||||
|
if (File.Exists (FallbackFileName))
|
||||||
|
return FallbackFileName;
|
||||||
|
else
|
||||||
|
return "/usr/share/icons/hicolor/16x16/status/avatar-default.png";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 ("-", "");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue