using ElectronNET.API.Entities;
using ElectronNET.API.Extensions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace ElectronNET.API
{
///
/// Add icons and context menus to the system's notification area.
///
public sealed class Tray
{
///
/// Emitted when the tray icon is clicked.
///
public event Action OnClick
{
add
{
if (_click == null)
{
BridgeConnector.Socket.On("tray-click-event" + GetHashCode(), (result) =>
{
var args = ((JArray)result).ToObject();
var trayClickEventArgs = ((JObject)args[0]).ToObject();
var bounds = ((JObject)args[1]).ToObject();
_click(trayClickEventArgs, bounds);
});
BridgeConnector.Socket.Emit("register-tray-click", GetHashCode());
}
_click += value;
}
remove
{
_click -= value;
if (_click == null)
BridgeConnector.Socket.Off("tray-click-event" + GetHashCode());
}
}
private event Action _click;
///
/// macOS, Windows: Emitted when the tray icon is right clicked.
///
public event Action OnRightClick
{
add
{
if (_rightClick == null)
{
BridgeConnector.Socket.On("tray-right-click-event" + GetHashCode(), (result) =>
{
var args = ((JArray)result).ToObject();
var trayClickEventArgs = ((JObject)args[0]).ToObject();
var bounds = ((JObject)args[1]).ToObject();
_rightClick(trayClickEventArgs, bounds);
});
BridgeConnector.Socket.Emit("register-tray-right-click", GetHashCode());
}
_rightClick += value;
}
remove
{
_rightClick -= value;
if (_rightClick == null)
BridgeConnector.Socket.Off("tray-right-click-event" + GetHashCode());
}
}
private event Action _rightClick;
///
/// macOS, Windows: Emitted when the tray icon is double clicked.
///
public event Action OnDoubleClick
{
add
{
if (_doubleClick == null)
{
BridgeConnector.Socket.On("tray-double-click-event" + GetHashCode(), (result) =>
{
var args = ((JArray)result).ToObject();
var trayClickEventArgs = ((JObject)args[0]).ToObject();
var bounds = ((JObject)args[1]).ToObject();
_doubleClick(trayClickEventArgs, bounds);
});
BridgeConnector.Socket.Emit("register-tray-double-click", GetHashCode());
}
_doubleClick += value;
}
remove
{
_doubleClick -= value;
if (_doubleClick == null)
BridgeConnector.Socket.Off("tray-double-click-event" + GetHashCode());
}
}
private event Action _doubleClick;
///
/// Windows: Emitted when the tray balloon shows.
///
public event Action OnBalloonShow
{
add
{
if (_balloonShow == null)
{
BridgeConnector.Socket.On("tray-balloon-show-event" + GetHashCode(), () =>
{
_balloonShow();
});
BridgeConnector.Socket.Emit("register-tray-balloon-show", GetHashCode());
}
_balloonShow += value;
}
remove
{
_balloonShow -= value;
if (_balloonShow == null)
BridgeConnector.Socket.Off("tray-balloon-show-event" + GetHashCode());
}
}
private event Action _balloonShow;
///
/// Windows: Emitted when the tray balloon is clicked.
///
public event Action OnBalloonClick
{
add
{
if (_balloonClick == null)
{
BridgeConnector.Socket.On("tray-balloon-click-event" + GetHashCode(), () =>
{
_balloonClick();
});
BridgeConnector.Socket.Emit("register-tray-balloon-click", GetHashCode());
}
_balloonClick += value;
}
remove
{
_balloonClick -= value;
if (_balloonClick == null)
BridgeConnector.Socket.Off("tray-balloon-click-event" + GetHashCode());
}
}
private event Action _balloonClick;
///
/// Windows: Emitted when the tray balloon is closed
/// because of timeout or user manually closes it.
///
public event Action OnBalloonClosed
{
add
{
if (_balloonClosed == null)
{
BridgeConnector.Socket.On("tray-balloon-closed-event" + GetHashCode(), () =>
{
_balloonClosed();
});
BridgeConnector.Socket.Emit("register-tray-balloon-closed", GetHashCode());
}
_balloonClosed += value;
}
remove
{
_balloonClosed -= value;
if (_balloonClosed == null)
BridgeConnector.Socket.Off("tray-balloon-closed-event" + GetHashCode());
}
}
private event Action _balloonClosed;
// TODO: Implement macOS Events
private static Tray _tray;
private static readonly object _syncRoot = new();
internal Tray() { }
internal static Tray Instance
{
get
{
if (_tray == null)
{
lock (_syncRoot)
{
if (_tray == null)
{
_tray = new Tray();
}
}
}
return _tray;
}
}
///
/// Gets the menu items.
///
///
/// The menu items.
///
public IReadOnlyCollection MenuItems => _items.AsReadOnly();
private readonly List _items = new();
///
/// Shows the Traybar.
///
/// The image.
/// The menu item.
public async Task Show(string image, MenuItem menuItem)
{
await Show(image, new MenuItem[] { menuItem });
}
///
/// Shows the Traybar.
///
/// The image.
/// The menu items.
public async Task Show(string image, MenuItem[] menuItems)
{
menuItems.AddMenuItemsId();
await BridgeConnector.Socket.Emit("create-tray", image, JArray.FromObject(menuItems, _jsonSerializer));
_items.Clear();
_items.AddRange(menuItems);
BridgeConnector.Socket.Off("trayMenuItemClicked");
BridgeConnector.Socket.On("trayMenuItemClicked", (id) =>
{
MenuItem menuItem = _items.GetMenuItem(id);
menuItem?.Click();
});
}
///
/// Shows the Traybar (empty).
///
/// The image.
public async Task Show(string image)
{
await BridgeConnector.Socket.Emit("create-tray", image);
}
///
/// Destroys the tray icon immediately.
///
public async Task Destroy()
{
await BridgeConnector.Socket.Emit("tray-destroy");
_items.Clear();
}
///
/// Sets the image associated with this tray icon.
///
///
public async Task SetImage(string image)
{
await BridgeConnector.Socket.Emit("tray-setImage", image);
}
///
/// Sets the image associated with this tray icon when pressed on macOS.
///
///
public async Task SetPressedImage(string image)
{
await BridgeConnector.Socket.Emit("tray-setPressedImage", image);
}
///
/// Sets the hover text for this tray icon.
///
///
public async Task SetToolTip(string toolTip)
{
await BridgeConnector.Socket.Emit("tray-setToolTip", toolTip);
}
///
/// macOS: Sets the title displayed aside of the tray icon in the status bar.
///
///
public async Task SetTitle(string title)
{
await BridgeConnector.Socket.Emit("tray-setTitle", title);
}
///
/// Windows: Displays a tray balloon.
///
///
public async Task DisplayBalloon(DisplayBalloonOptions options)
{
await BridgeConnector.Socket.Emit("tray-displayBalloon", JObject.FromObject(options, _jsonSerializer));
}
///
/// Whether the tray icon is destroyed.
///
///
public async Task IsDestroyedAsync()
{
var taskCompletionSource = new TaskCompletionSource();
BridgeConnector.Socket.On("tray-isDestroyedCompleted", (isDestroyed) =>
{
BridgeConnector.Socket.Off("tray-isDestroyedCompleted");
taskCompletionSource.SetResult(isDestroyed);
});
await BridgeConnector.Socket.Emit("tray-isDestroyed");
return await taskCompletionSource.Task;
}
private readonly JsonSerializer _jsonSerializer = new()
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
private const string ModuleName = "tray";
///
/// Subscribe to an unmapped event on the module.
///
/// The event name
/// The handler
public void On(string eventName, Action action)
=> Events.Instance.On(ModuleName, eventName, action);
///
/// Subscribe to an unmapped event on the module.
///
/// The event name
/// The handler
public async Task On(string eventName, Action action)
=> await Events.Instance.On(ModuleName, eventName, action);
///
/// Subscribe to an unmapped event on the module once.
///
/// The event name
/// The handler
public void Once(string eventName, Action action)
=> Events.Instance.Once(ModuleName, eventName, action);
///
/// Subscribe to an unmapped event on the module once.
///
/// The event name
/// The handler
public async Task Once(string eventName, Action action)
=> await Events.Instance.Once(ModuleName, eventName, action);
}
}