bloxstrap/Bloxstrap/UI/NotifyIconWrapper.cs
pizzaboxer fd290f9ff7
Move activity watcher to separate process (#810)
this was done to:
- ensure robloxplayerbeta launches as an orphaned process
- help alleviate problems with multiple instances
- alleviate problems with the notifyicon causing blocking conflicts on the bootstrapper ui thread
- help reduce functional dependency on the bootstrapper, makes it less monolithic and more maintainable

ive always wanted to do this for a long while, but have always put it off because of how painful it would be

this may genuinely be the most painful refactoring i've ever had to do, but after 2 days, i managed to do it, and it works great!
2024-08-28 22:47:04 +01:00

134 lines
4.4 KiB
C#

using Bloxstrap.Integrations;
using Bloxstrap.UI.Elements.About;
using Bloxstrap.UI.Elements.ContextMenu;
namespace Bloxstrap.UI
{
public class NotifyIconWrapper : IDisposable
{
// lol who needs properly structured mvvm and xaml when you have the absolute catastrophe that this is
private bool _disposing = false;
private readonly System.Windows.Forms.NotifyIcon _notifyIcon;
private readonly MenuContainer _menuContainer;
private readonly Watcher _watcher;
private ActivityWatcher? _activityWatcher => _watcher.ActivityWatcher;
EventHandler? _alertClickHandler;
public NotifyIconWrapper(Watcher watcher)
{
App.Logger.WriteLine("NotifyIconWrapper::NotifyIconWrapper", "Initializing notification area icon");
_watcher = watcher;
_notifyIcon = new()
{
Icon = Properties.Resources.IconBloxstrap,
Text = App.ProjectName,
Visible = true
};
_notifyIcon.MouseClick += MouseClickEventHandler;
if (_activityWatcher is not null)
_activityWatcher.OnGameJoin += OnGameJoin;
_menuContainer = new(_watcher);
_menuContainer.Show();
}
#region Context menu
public void MouseClickEventHandler(object? sender, System.Windows.Forms.MouseEventArgs e)
{
if (e.Button != System.Windows.Forms.MouseButtons.Right)
return;
_menuContainer.Activate();
_menuContainer.ContextMenu.IsOpen = true;
}
#endregion
#region Activity handlers
public async void OnGameJoin(object? sender, EventArgs e)
{
if (_activityWatcher is null)
return;
string serverLocation = await _activityWatcher.GetServerLocation();
string title = _activityWatcher.ActivityServerType switch
{
ServerType.Public => Strings.ContextMenu_ServerInformation_Notification_Title_Public,
ServerType.Private => Strings.ContextMenu_ServerInformation_Notification_Title_Private,
ServerType.Reserved => Strings.ContextMenu_ServerInformation_Notification_Title_Reserved,
_ => ""
};
ShowAlert(
title,
String.Format(Strings.ContextMenu_ServerInformation_Notification_Text, serverLocation),
10,
(_, _) => _menuContainer.ShowServerInformationWindow()
);
}
#endregion
public void ShowAlert(string caption, string message, int duration, EventHandler? clickHandler)
{
string id = Guid.NewGuid().ToString()[..8];
string LOG_IDENT = $"NotifyIconWrapper::ShowAlert.{id}";
App.Logger.WriteLine(LOG_IDENT, $"Showing alert for {duration} seconds (clickHandler={clickHandler is not null})");
App.Logger.WriteLine(LOG_IDENT, $"{caption}: {message.Replace("\n", "\\n")}");
_notifyIcon.BalloonTipTitle = caption;
_notifyIcon.BalloonTipText = message;
if (_alertClickHandler is not null)
{
App.Logger.WriteLine(LOG_IDENT, "Previous alert still present, erasing click handler");
_notifyIcon.BalloonTipClicked -= _alertClickHandler;
}
_alertClickHandler = clickHandler;
_notifyIcon.BalloonTipClicked += clickHandler;
_notifyIcon.ShowBalloonTip(duration);
Task.Run(async () =>
{
await Task.Delay(duration * 1000);
_notifyIcon.BalloonTipClicked -= clickHandler;
App.Logger.WriteLine(LOG_IDENT, "Duration over, erasing current click handler");
if (_alertClickHandler == clickHandler)
_alertClickHandler = null;
else
App.Logger.WriteLine(LOG_IDENT, "Click handler has been overridden by another alert");
});
}
public void Dispose()
{
if (_disposing)
return;
_disposing = true;
App.Logger.WriteLine("NotifyIconWrapper::Dispose", "Disposing NotifyIcon");
_menuContainer.Dispatcher.Invoke(_menuContainer.Close);
_notifyIcon.Dispose();
GC.SuppressFinalize(this);
}
}
}