mac statusicon: Implement per repo status and pausing
This commit is contained in:
parent
b6ea49f059
commit
e04d2957f8
|
@ -16,6 +16,7 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
|
||||
|
@ -35,7 +36,8 @@ namespace SparkleShare {
|
|||
private NSMenuItem state_item, folder_item, add_item, about_item, recent_events_item, quit_item,
|
||||
code_item, copy_item, link_code_item;
|
||||
|
||||
private NSMenuItem [] folder_menu_items, error_menu_items, try_again_menu_items;
|
||||
private NSMenuItem [] folder_menu_items, try_again_menu_items, pause_menu_items,
|
||||
resume_menu_items, state_menu_items;
|
||||
|
||||
private NSImage syncing_idle_image = NSImage.ImageNamed ("process-syncing-idle");
|
||||
private NSImage syncing_up_image = NSImage.ImageNamed ("process-syncing-up");
|
||||
|
@ -95,7 +97,15 @@ namespace SparkleShare {
|
|||
};
|
||||
|
||||
Controller.UpdateStatusItemEvent += delegate (string state_text) {
|
||||
Program.Controller.Invoke (() => { this.state_item.Title = state_text; });
|
||||
Program.Controller.Invoke (() => {
|
||||
this.state_item.Title = state_text;
|
||||
|
||||
|
||||
if (Controller.Projects.Length == this.state_menu_items.Length) {
|
||||
for (int i = 0; i < Controller.Projects.Length; i++)
|
||||
this.state_menu_items [i].Title = Controller.Projects [i].StatusMessage;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Controller.UpdateMenuEvent += delegate {
|
||||
|
@ -168,36 +178,63 @@ namespace SparkleShare {
|
|||
Enabled = Controller.QuitItemEnabled
|
||||
};
|
||||
|
||||
this.folder_menu_items = new NSMenuItem [Controller.Folders.Length];
|
||||
this.error_menu_items = new NSMenuItem [Controller.Folders.Length];
|
||||
this.try_again_menu_items = new NSMenuItem [Controller.Folders.Length];
|
||||
this.folder_menu_items = new NSMenuItem [Controller.Projects.Length];
|
||||
this.try_again_menu_items = new NSMenuItem [Controller.Projects.Length];
|
||||
this.pause_menu_items = new NSMenuItem [Controller.Projects.Length];
|
||||
this.resume_menu_items = new NSMenuItem [Controller.Projects.Length];
|
||||
this.state_menu_items = new NSMenuItem [Controller.Projects.Length];
|
||||
|
||||
if (Controller.Folders.Length > 0) {
|
||||
if (Controller.Projects.Length > 0) {
|
||||
int i = 0;
|
||||
foreach (string folder_name in Controller.Folders) {
|
||||
NSMenuItem item = new NSMenuItem () { Title = folder_name };
|
||||
foreach (ProjectInfo project in Controller.Projects) {
|
||||
NSMenuItem item = new NSMenuItem () { Title = project.Name };
|
||||
this.folder_menu_items [i] = item;
|
||||
|
||||
if (!string.IsNullOrEmpty (Controller.FolderErrors [i])) {
|
||||
item.Image = this.caution_image;
|
||||
item.Submenu = new NSMenu ();
|
||||
item.Submenu = new NSMenu ();
|
||||
item.Image = this.folder_image;
|
||||
|
||||
this.error_menu_items [i] = new NSMenuItem ();
|
||||
this.error_menu_items [i].Title = Controller.FolderErrors [i];
|
||||
this.state_menu_items [i] = new NSMenuItem (project.StatusMessage);
|
||||
|
||||
this.try_again_menu_items [i] = new NSMenuItem ();
|
||||
this.try_again_menu_items [i].Title = "Try Again";
|
||||
this.try_again_menu_items [i].Activated += Controller.TryAgainDelegate (folder_name);;
|
||||
item.Submenu.AddItem (this.state_menu_items [i]);
|
||||
item.Submenu.AddItem (NSMenuItem.SeparatorItem);
|
||||
|
||||
item.Submenu.AddItem (this.error_menu_items [i]);
|
||||
item.Submenu.AddItem (NSMenuItem.SeparatorItem);
|
||||
item.Submenu.AddItem (this.try_again_menu_items [i]);
|
||||
if (project.IsPaused) {
|
||||
if (project.UnsyncedChangesInfo.Count > 0) {
|
||||
foreach (KeyValuePair<string, string> pair in project.UnsyncedChangesInfo)
|
||||
item.Submenu.AddItem (new NSMenuItem (pair.Key) {
|
||||
Image = NSImage.ImageNamed (pair.Value)
|
||||
});
|
||||
|
||||
item.Submenu.AddItem (NSMenuItem.SeparatorItem);
|
||||
this.resume_menu_items [i] = new NSMenuItem ("Sync and Resume…");
|
||||
|
||||
} else {
|
||||
this.resume_menu_items [i] = new NSMenuItem ("Resume");
|
||||
}
|
||||
|
||||
this.resume_menu_items [i].Activated += Controller.ResumeDelegate (project.Name);
|
||||
item.Submenu.AddItem (this.resume_menu_items [i]);
|
||||
|
||||
} else {
|
||||
item.Image = this.folder_image;
|
||||
this.folder_menu_items [i].Activated += Controller.OpenFolderDelegate (folder_name);
|
||||
if (Controller.Projects [i].HasError) {
|
||||
item.Image = this.caution_image;
|
||||
|
||||
this.try_again_menu_items [i] = new NSMenuItem ();
|
||||
this.try_again_menu_items [i].Title = "Try Again";
|
||||
this.try_again_menu_items [i].Activated += Controller.TryAgainDelegate (project.Name);
|
||||
|
||||
item.Submenu.AddItem (this.try_again_menu_items [i]);
|
||||
|
||||
} else {
|
||||
this.pause_menu_items [i] = new NSMenuItem ("Pause");
|
||||
this.pause_menu_items [i].Activated += Controller.PauseDelegate (project.Name);
|
||||
item.Submenu.AddItem (this.pause_menu_items [i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Controller.Projects [i].HasError)
|
||||
this.folder_menu_items [i].Activated += Controller.OpenFolderDelegate (project.Name);
|
||||
|
||||
item.Image.Size = new SizeF (16, 16);
|
||||
i++;
|
||||
};
|
||||
|
@ -263,6 +300,5 @@ namespace SparkleShare {
|
|||
MenuIsOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,24 +46,35 @@ namespace SparkleShare {
|
|||
|
||||
public string StatusMessage {
|
||||
get {
|
||||
string status_message = "Last sync at <time>";
|
||||
|
||||
if (IsPaused) {
|
||||
status_message = "Paused";
|
||||
string status_message = "";
|
||||
|
||||
} else if (this.repo.Status == SyncStatus.Error) {
|
||||
if (this.repo.Status == SyncStatus.SyncUp)
|
||||
status_message = "Sending changes… " + this.repo.ProgressPercentage + "%";
|
||||
|
||||
if (this.repo.Status == SyncStatus.SyncDown)
|
||||
status_message = "Receiving changes… " + this.repo.ProgressPercentage + "%";
|
||||
|
||||
if (this.repo.Status == SyncStatus.SyncUp || this.repo.Status == SyncStatus.SyncDown) {
|
||||
if (this.repo.ProgressSpeed > 0)
|
||||
status_message += " " + this.repo.ProgressSpeed.ToSize () + "/s";
|
||||
}
|
||||
|
||||
if (IsPaused) {
|
||||
return "Paused";
|
||||
|
||||
} else if (HasError) {
|
||||
switch (this.repo.Error) {
|
||||
case ErrorStatus.HostUnreachable: return "Can't reach the host";
|
||||
case ErrorStatus.HostIdentityChanged: return "The host's identity has changed";
|
||||
case ErrorStatus.HostUnreachable: return "Can’t reach the host";
|
||||
case ErrorStatus.HostIdentityChanged: return "The host’s identity has changed";
|
||||
case ErrorStatus.AuthenticationFailed: return "Authentication failed";
|
||||
case ErrorStatus.DiskSpaceExceeded: return "Host is out of disk space";
|
||||
case ErrorStatus.UnreadableFiles: return "Some local files are unreadable or in use";
|
||||
case ErrorStatus.NotFound: return "Project doesn't exist on host";
|
||||
case ErrorStatus.NotFound: return "Project doesn’t exist on host";
|
||||
case ErrorStatus.IncompatibleClientServer: return "Incompatible client/server versions";
|
||||
}
|
||||
}
|
||||
|
||||
return status_message;
|
||||
return string.Format ("Synced {0}", this.repo.LastSync.ToPrettyDate ());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,20 +124,6 @@ namespace SparkleShare {
|
|||
public ProjectInfo [] Projects = new ProjectInfo [0];
|
||||
|
||||
|
||||
public string FolderSize {
|
||||
get {
|
||||
double size = 0;
|
||||
|
||||
foreach (SparkleRepoBase repo in Program.Controller.Repositories)
|
||||
size += repo.Size;
|
||||
|
||||
if (size == 0)
|
||||
return "";
|
||||
else
|
||||
return "— " + size.ToSize ();
|
||||
}
|
||||
}
|
||||
|
||||
public int ProgressPercentage {
|
||||
get {
|
||||
return (int) Program.Controller.ProgressPercentage;
|
||||
|
@ -184,7 +181,7 @@ namespace SparkleShare {
|
|||
if (Projects.Length == 0)
|
||||
StateText = "Welcome to SparkleShare!";
|
||||
else
|
||||
StateText = "Projects up to date " + FolderSize;
|
||||
StateText = "Projects up to date";
|
||||
}
|
||||
|
||||
UpdateFolders ();
|
||||
|
@ -200,7 +197,7 @@ namespace SparkleShare {
|
|||
if (Projects.Length == 0)
|
||||
StateText = "Welcome to SparkleShare!";
|
||||
else
|
||||
StateText = "Projects up to date " + FolderSize;
|
||||
StateText = "Projects up to date";
|
||||
}
|
||||
|
||||
UpdateFolders ();
|
||||
|
@ -247,7 +244,7 @@ namespace SparkleShare {
|
|||
|
||||
Program.Controller.OnError += delegate {
|
||||
CurrentState = IconState.Error;
|
||||
StateText = "Failed to send some changes";
|
||||
StateText = "Some changes weren’t synced";
|
||||
|
||||
UpdateFolders ();
|
||||
|
||||
|
@ -257,7 +254,7 @@ namespace SparkleShare {
|
|||
};
|
||||
|
||||
|
||||
// FIXME: Hack to work around a race condition causing
|
||||
// FIXME: Work around a race condition causing
|
||||
// the icon to not always show the right state
|
||||
Timers.Timer timer = new Timers.Timer () { Interval = 30 * 1000 };
|
||||
|
||||
|
@ -270,32 +267,7 @@ namespace SparkleShare {
|
|||
}
|
||||
|
||||
|
||||
public void SubfolderClicked (string subfolder)
|
||||
{
|
||||
Program.Controller.OpenSparkleShareFolder (subfolder);
|
||||
}
|
||||
|
||||
|
||||
public void TryAgainClicked (string subfolder)
|
||||
{
|
||||
foreach (SparkleRepoBase repo in Program.Controller.Repositories)
|
||||
if (repo.Name.Equals (subfolder))
|
||||
new Thread (() => repo.ForceRetry ()).Start ();
|
||||
}
|
||||
|
||||
|
||||
public EventHandler OpenFolderDelegate (string subfolder)
|
||||
{
|
||||
return delegate { SubfolderClicked (subfolder); };
|
||||
}
|
||||
|
||||
|
||||
public EventHandler TryAgainDelegate (string subfolder)
|
||||
{
|
||||
return delegate { TryAgainClicked (subfolder); };
|
||||
}
|
||||
|
||||
|
||||
// Main menu items
|
||||
public void RecentEventsClicked ()
|
||||
{
|
||||
new Thread (() => {
|
||||
|
@ -307,31 +279,74 @@ namespace SparkleShare {
|
|||
}).Start ();
|
||||
}
|
||||
|
||||
|
||||
public void AddHostedProjectClicked ()
|
||||
{
|
||||
new Thread (() => Program.Controller.ShowSetupWindow (PageType.Add)).Start ();
|
||||
}
|
||||
|
||||
|
||||
public void CopyToClipboardClicked ()
|
||||
{
|
||||
Program.Controller.CopyToClipboard (Program.Controller.CurrentUser.PublicKey);
|
||||
}
|
||||
|
||||
|
||||
public void AboutClicked ()
|
||||
{
|
||||
Program.Controller.ShowAboutWindow ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void QuitClicked ()
|
||||
{
|
||||
Program.Controller.Quit ();
|
||||
}
|
||||
|
||||
|
||||
// Project items
|
||||
public void ProjectClicked (string project)
|
||||
{
|
||||
Program.Controller.OpenSparkleShareFolder (project);
|
||||
}
|
||||
|
||||
public void PauseClicked (string project)
|
||||
{
|
||||
GetRepoByName (project).Pause ();
|
||||
UpdateMenuEvent (CurrentState);
|
||||
}
|
||||
|
||||
public void ResumeClicked (string project)
|
||||
{
|
||||
GetRepoByName (project).Resume ("");
|
||||
UpdateMenuEvent (CurrentState);
|
||||
TryAgainClicked (project);
|
||||
}
|
||||
|
||||
public void TryAgainClicked (string project)
|
||||
{
|
||||
new Thread (() => GetRepoByName (project).ForceRetry ()).Start ();
|
||||
}
|
||||
|
||||
|
||||
// Helper delegates
|
||||
public EventHandler OpenFolderDelegate (string project)
|
||||
{
|
||||
return delegate { ProjectClicked (project); };
|
||||
}
|
||||
|
||||
public EventHandler TryAgainDelegate (string project)
|
||||
{
|
||||
return delegate { TryAgainClicked (project); };
|
||||
}
|
||||
|
||||
public EventHandler PauseDelegate (string project)
|
||||
{
|
||||
return delegate { PauseClicked (project); };
|
||||
}
|
||||
|
||||
public EventHandler ResumeDelegate (string project)
|
||||
{
|
||||
return delegate { ResumeClicked (project); };
|
||||
}
|
||||
|
||||
|
||||
private Object projects_lock = new Object ();
|
||||
|
||||
private void UpdateFolders ()
|
||||
|
@ -345,5 +360,15 @@ namespace SparkleShare {
|
|||
Projects = projects.ToArray ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private SparkleRepoBase GetRepoByName (string name)
|
||||
{
|
||||
foreach (SparkleRepoBase repo in Program.Controller.Repositories)
|
||||
if (repo.Name.Equals (name))
|
||||
return repo;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue