diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 8e30496..f9ae13f 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -234,7 +234,6 @@ namespace Bloxstrap List autocloseProcesses = new(); RobloxActivity? activityWatcher = null; DiscordRichPresence? richPresence = null; - ServerNotifier? serverNotifier = null; App.Logger.WriteLine($"[Bootstrapper::StartRoblox] Started Roblox (PID {gameClientPid})"); @@ -253,16 +252,15 @@ namespace Bloxstrap activityWatcher = new(); shouldWait = true; + App.NotifyIcon?.SetActivityWatcher(activityWatcher); + if (App.Settings.Prop.UseDiscordRichPresence) { App.Logger.WriteLine("[Bootstrapper::StartRoblox] Using Discord Rich Presence"); richPresence = new(activityWatcher); - } - if (App.Settings.Prop.ShowServerDetails) - { - App.Logger.WriteLine("[Bootstrapper::StartRoblox] Using server details notifier"); - serverNotifier = new(activityWatcher); + if (App.NotifyIcon is not null) + App.NotifyIcon.RichPresenceIntegration = richPresence; } } diff --git a/Bloxstrap/Integrations/ServerNotifier.cs b/Bloxstrap/Integrations/ServerNotifier.cs deleted file mode 100644 index 4f9929f..0000000 --- a/Bloxstrap/Integrations/ServerNotifier.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Windows; - -namespace Bloxstrap.Integrations -{ - public class ServerNotifier - { - private readonly RobloxActivity _activityWatcher; - - public ServerNotifier(RobloxActivity activityWatcher) - { - _activityWatcher = activityWatcher; - _activityWatcher.OnGameJoin += (_, _) => Task.Run(() => Notify()); - } - - public async void Notify() - { - string machineAddress = _activityWatcher.ActivityMachineAddress; - string message = ""; - - App.Logger.WriteLine($"[ServerNotifier::Notify] Getting server information for {machineAddress}"); - - // basically nobody has a free public access geolocation api that's accurate, - // the ones that do require an api key which isn't suitable for a client-side application like this - // so, hopefully this is reliable enough? - string locationCity = await App.HttpClient.GetStringAsync($"https://ipinfo.io/{machineAddress}/city"); - string locationRegion = await App.HttpClient.GetStringAsync($"https://ipinfo.io/{machineAddress}/region"); - string locationCountry = await App.HttpClient.GetStringAsync($"https://ipinfo.io/{machineAddress}/country"); - - locationCity = locationCity.ReplaceLineEndings(""); - locationRegion = locationRegion.ReplaceLineEndings(""); - locationCountry = locationCountry.ReplaceLineEndings(""); - - if (String.IsNullOrEmpty(locationCountry)) - message = "Location: N/A"; - else if (locationCity == locationRegion) - message = $"Location: {locationRegion}, {locationCountry}"; - else - message = $"Location: {locationCity}, {locationRegion}, {locationCountry}"; - - message += "\nClick to copy Instance ID"; - - App.NotifyIcon?.ShowAlert("Connnected to server", message, 10, (_, _) => Clipboard.SetText(_activityWatcher.ActivityJobId)); - } - } -} diff --git a/Bloxstrap/UI/Elements/NotifyIconMenu.xaml b/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml similarity index 50% rename from Bloxstrap/UI/Elements/NotifyIconMenu.xaml rename to Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml index 373a2b8..a3c9bad 100644 --- a/Bloxstrap/UI/Elements/NotifyIconMenu.xaml +++ b/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml @@ -1,12 +1,12 @@ - - - + - - - + + + - - - - - diff --git a/Bloxstrap/UI/Elements/NotifyIconMenu.xaml.cs b/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs similarity index 57% rename from Bloxstrap/UI/Elements/NotifyIconMenu.xaml.cs rename to Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs index d8e14d0..6154055 100644 --- a/Bloxstrap/UI/Elements/NotifyIconMenu.xaml.cs +++ b/Bloxstrap/UI/Elements/ContextMenu/MenuContainer.xaml.cs @@ -15,29 +15,44 @@ using System.Windows.Shapes; using Bloxstrap.UI.ViewModels; -namespace Bloxstrap.UI.Elements +namespace Bloxstrap.UI.Elements.ContextMenu { /// /// Interaction logic for NotifyIconMenu.xaml /// - public partial class NotifyIconMenu + public partial class MenuContainer { - public NotifyIconMenu() + // i wouldve gladly done this as mvvm but turns out that data binding just does not work with menuitems for some reason so idk this sucks + + public MenuContainer() { InitializeComponent(); + + VersionMenuItem.Header = $"{App.ProjectName} v{App.Version}"; } private void Window_Loaded(object? sender, RoutedEventArgs e) { // this is an awful hack lmao im so sorry to anyone who reads this - // https://stackoverflow.com/questions/357076/best-way-to-hide-a-window-from-the-alt-tab-program-switcher#:~:text=ShowInTaskbar%20%3D%20false%3B%20Owner%20%3D%20form1,form%27s%20ShowInTaskbar%20property%20to%20false. + // this is done to register the context menu wrapper as a tool window so it doesnt appear in the alt+tab switcher + // https://stackoverflow.com/a/551847/11852173 + var wndHelper = new WindowInteropHelper(this); long exStyle = NativeMethods.GetWindowLongPtr(wndHelper.Handle, NativeMethods.GWL_EXSTYLE).ToInt64(); exStyle |= NativeMethods.WS_EX_TOOLWINDOW; NativeMethods.SetWindowLongPtr(wndHelper.Handle, NativeMethods.GWL_EXSTYLE, (IntPtr)exStyle); } - // i tried to use a viewmodel but uhhhhhhh it just didnt work idk + private void RichPresenceMenuItem_Click(object sender, RoutedEventArgs e) + { + Controls.ShowMessageBox($"hi how u doing i am {RichPresenceMenuItem.IsChecked}", MessageBoxImage.Warning); + } + + private void ServerDetailsMenuItem_Click(object sender, RoutedEventArgs e) + { + Controls.ShowMessageBox($"hi how u doing i am {RichPresenceMenuItem.IsChecked}", MessageBoxImage.Warning); + } + private void TestMenuItem_Click(object sender, RoutedEventArgs e) { Controls.ShowMessageBox($"hi how u doing i am {TestMenuItem.IsChecked}", MessageBoxImage.Warning); diff --git a/Bloxstrap/UI/NotifyIconWrapper.cs b/Bloxstrap/UI/NotifyIconWrapper.cs index 14fcbdc..9194417 100644 --- a/Bloxstrap/UI/NotifyIconWrapper.cs +++ b/Bloxstrap/UI/NotifyIconWrapper.cs @@ -1,6 +1,7 @@ -using System.Windows.Forms; +using System.Windows; -using Bloxstrap.UI.Elements; +using Bloxstrap.Integrations; +using Bloxstrap.UI.Elements.ContextMenu; namespace Bloxstrap.UI { @@ -8,12 +9,14 @@ namespace Bloxstrap.UI { bool _disposed = false; - private readonly NotifyIcon _notifyIcon; - private readonly NotifyIconMenu _contextMenuWrapper = new(); + private readonly System.Windows.Forms.NotifyIcon _notifyIcon; + private readonly MenuContainer _menuContainer = new(); + private RobloxActivity? _activityWatcher; + + public DiscordRichPresence? RichPresenceIntegration; EventHandler? _alertClickHandler; - public NotifyIconWrapper() { App.Logger.WriteLine("[NotifyIconWrapper::NotifyIconWrapper] Initializing notification area icon"); @@ -27,18 +30,65 @@ namespace Bloxstrap.UI _notifyIcon.MouseClick += MouseClickEventHandler; - _contextMenuWrapper.Dispatcher.BeginInvoke(_contextMenuWrapper.ShowDialog); - - _contextMenuWrapper.Closing += (_, _) => App.Logger.WriteLine("[NotifyIconWrapper::NotifyIconWrapper] Context menu wrapper closing"); + _menuContainer.Dispatcher.BeginInvoke(_menuContainer.ShowDialog); + _menuContainer.Closing += (_, _) => App.Logger.WriteLine("[NotifyIconWrapper::NotifyIconWrapper] Context menu container closed"); } - public void MouseClickEventHandler(object? sender, MouseEventArgs e) + public void SetActivityWatcher(RobloxActivity activityWatcher) { - if (e.Button != MouseButtons.Right) + if (_activityWatcher is not null) return; - _contextMenuWrapper.Activate(); - _contextMenuWrapper.ContextMenu.IsOpen = true; + _activityWatcher = activityWatcher; + _activityWatcher.OnGameJoin += (_, _) => Task.Run(OnGameJoin); + _activityWatcher.OnGameLeave += OnGameLeave; + } + + public async void OnGameJoin() + { + if (!App.Settings.Prop.ShowServerDetails) + return; + + App.Logger.WriteLine($"[NotifyIconWrapper::OnActivityGameJoin] Getting game/server information"); + + string machineAddress = _activityWatcher!.ActivityMachineAddress; + string machineLocation = ""; + + // basically nobody has a free public access geolocation api that's accurate, + // the ones that do require an api key which isn't suitable for a client-side application like this + // so, hopefully this is reliable enough? + string locationCity = await App.HttpClient.GetStringAsync($"https://ipinfo.io/{machineAddress}/city"); + string locationRegion = await App.HttpClient.GetStringAsync($"https://ipinfo.io/{machineAddress}/region"); + string locationCountry = await App.HttpClient.GetStringAsync($"https://ipinfo.io/{machineAddress}/country"); + + locationCity = locationCity.ReplaceLineEndings(""); + locationRegion = locationRegion.ReplaceLineEndings(""); + locationCountry = locationCountry.ReplaceLineEndings(""); + + if (String.IsNullOrEmpty(locationCountry)) + machineLocation = "N/A"; + else if (locationCity == locationRegion) + machineLocation = $"{locationRegion}, {locationCountry}"; + else + machineLocation = $"{locationCity}, {locationRegion}, {locationCountry}"; + + _menuContainer.Dispatcher.Invoke(() => _menuContainer.ServerDetailsMenuItem.Visibility = Visibility.Visible); + + ShowAlert("Connnected to server", $"Location: {machineLocation}\nClick to copy Instance ID", 10, (_, _) => System.Windows.Clipboard.SetText(_activityWatcher.ActivityJobId)); + } + + public void OnGameLeave(object? sender, EventArgs e) + { + _menuContainer.Dispatcher.Invoke(() => _menuContainer.ServerDetailsMenuItem.Visibility = Visibility.Collapsed); + } + + 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; } public void ShowAlert(string caption, string message, int duration, EventHandler? clickHandler) @@ -84,7 +134,7 @@ namespace Bloxstrap.UI App.Logger.WriteLine($"[NotifyIconWrapper::Dispose] Disposing NotifyIcon"); - _contextMenuWrapper.Dispatcher.Invoke(_contextMenuWrapper.Close); + _menuContainer.Dispatcher.Invoke(_menuContainer.Close); _notifyIcon.Dispose(); _disposed = true;