mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-06-23 23:00:23 -07:00
Compare commits
7 Commits
690699fcda
...
dc637f9156
Author | SHA1 | Date | |
---|---|---|---|
|
dc637f9156 | ||
|
338ebba191 | ||
|
d7e5912eb9 | ||
|
c78b04dce7 | ||
|
9700c61523 | ||
|
c9dabd6b4f | ||
|
9318813bdb |
@ -39,6 +39,8 @@
|
||||
<converters:StringFormatConverter x:Key="StringFormatConverter" />
|
||||
<converters:RangeConverter x:Key="RangeConverter" />
|
||||
<converters:EnumNameConverter x:Key="EnumNameConverter" />
|
||||
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<converters:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" />
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
@ -575,30 +575,32 @@ namespace Bloxstrap
|
||||
// launch custom integrations now
|
||||
foreach (var integration in App.Settings.Prop.CustomIntegrations)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Launching custom integration '{integration.Name}' ({integration.Location} {integration.LaunchArgs} - autoclose is {integration.AutoClose})");
|
||||
if (!integration.SpecifyGame) {
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Launching custom integration '{integration.Name}' ({integration.Location} {integration.LaunchArgs} - autoclose is {integration.AutoClose})");
|
||||
|
||||
int pid = 0;
|
||||
int pid = 0;
|
||||
|
||||
try
|
||||
{
|
||||
var process = Process.Start(new ProcessStartInfo
|
||||
try
|
||||
{
|
||||
FileName = integration.Location,
|
||||
Arguments = integration.LaunchArgs.Replace("\r\n", " "),
|
||||
WorkingDirectory = Path.GetDirectoryName(integration.Location),
|
||||
UseShellExecute = true
|
||||
})!;
|
||||
var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = integration.Location,
|
||||
Arguments = integration.LaunchArgs.Replace("\r\n", " "),
|
||||
WorkingDirectory = Path.GetDirectoryName(integration.Location),
|
||||
UseShellExecute = true
|
||||
})!;
|
||||
|
||||
pid = process.Id;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to launch integration '{integration.Name}'!");
|
||||
App.Logger.WriteLine(LOG_IDENT, ex.Message);
|
||||
}
|
||||
pid = process.Id;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to launch integration '{integration.Name}'!");
|
||||
App.Logger.WriteLine(LOG_IDENT, ex.Message);
|
||||
}
|
||||
|
||||
if (integration.AutoClose && pid != 0)
|
||||
autoclosePids.Add(pid);
|
||||
if (integration.AutoClose && pid != 0)
|
||||
autoclosePids.Add(pid);
|
||||
}
|
||||
}
|
||||
|
||||
if (App.Settings.Prop.EnableActivityTracking || App.LaunchSettings.TestModeFlag.Active || autoclosePids.Any())
|
||||
|
@ -1,10 +1,36 @@
|
||||
namespace Bloxstrap.Extensions
|
||||
using System.Text;
|
||||
|
||||
namespace Bloxstrap.Extensions
|
||||
{
|
||||
static class CustomThemeTemplateEx
|
||||
{
|
||||
const string EXAMPLES_URL = "https://github.com/bloxstraplabs/custom-bootstrapper-examples";
|
||||
|
||||
public static string GetFileName(this CustomThemeTemplate template)
|
||||
{
|
||||
return $"CustomBootstrapperTemplate_{template}.xml";
|
||||
}
|
||||
|
||||
public static string GetFileContents(this CustomThemeTemplate template)
|
||||
{
|
||||
string contents = Encoding.UTF8.GetString(Resource.Get(template.GetFileName()).Result);
|
||||
|
||||
switch (template)
|
||||
{
|
||||
case CustomThemeTemplate.Blank:
|
||||
{
|
||||
string moreText = string.Format(Strings.CustomTheme_Templates_Blank_MoreExamples, EXAMPLES_URL);
|
||||
return string.Format(contents, Strings.CustomTheme_Templates_Blank_UIElements, moreText);
|
||||
}
|
||||
case CustomThemeTemplate.Simple:
|
||||
{
|
||||
string moreText = string.Format(Strings.CustomTheme_Templates_Simple_MoreExamples, EXAMPLES_URL);
|
||||
return string.Format(contents, moreText);
|
||||
}
|
||||
default:
|
||||
Debug.Assert(false);
|
||||
return contents;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
100
Bloxstrap/Integrations/IntegrationWatcher.cs
Normal file
100
Bloxstrap/Integrations/IntegrationWatcher.cs
Normal file
@ -0,0 +1,100 @@
|
||||
namespace Bloxstrap.Integrations
|
||||
{
|
||||
public class IntegrationWatcher : IDisposable
|
||||
{
|
||||
private readonly ActivityWatcher _activityWatcher;
|
||||
private readonly Dictionary<int, CustomIntegration> _activeIntegrations = new();
|
||||
|
||||
public IntegrationWatcher(ActivityWatcher activityWatcher)
|
||||
{
|
||||
_activityWatcher = activityWatcher;
|
||||
|
||||
_activityWatcher.OnGameJoin += OnGameJoin;
|
||||
_activityWatcher.OnGameLeave += OnGameLeave;
|
||||
}
|
||||
|
||||
private void OnGameJoin(object? sender, EventArgs e)
|
||||
{
|
||||
if (!_activityWatcher.InGame)
|
||||
return;
|
||||
|
||||
long currentGameId = _activityWatcher.Data.PlaceId;
|
||||
|
||||
foreach (var integration in App.Settings.Prop.CustomIntegrations)
|
||||
{
|
||||
if (!integration.SpecifyGame || integration.GameID != currentGameId.ToString())
|
||||
continue;
|
||||
|
||||
LaunchIntegration(integration);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGameLeave(object? sender, EventArgs e)
|
||||
{
|
||||
foreach (var pid in _activeIntegrations.Keys.ToList())
|
||||
{
|
||||
var integration = _activeIntegrations[pid];
|
||||
if (integration.AutoCloseOnGame)
|
||||
{
|
||||
TerminateProcess(pid);
|
||||
_activeIntegrations.Remove(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LaunchIntegration(CustomIntegration integration)
|
||||
{
|
||||
const string LOG_IDENT = "IntegrationWatcher::LaunchIntegration";
|
||||
|
||||
try
|
||||
{
|
||||
var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = integration.Location,
|
||||
Arguments = integration.LaunchArgs.Replace("\r\n", " "),
|
||||
WorkingDirectory = Path.GetDirectoryName(integration.Location),
|
||||
UseShellExecute = true
|
||||
});
|
||||
|
||||
if (process != null)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Integration '{integration.Name}' launched for game ID '{integration.GameID}' (PID {process.Id}).");
|
||||
_activeIntegrations[process.Id] = integration;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to launch integration '{integration.Name}': {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void TerminateProcess(int pid)
|
||||
{
|
||||
const string LOG_IDENT = "IntegrationWatcher::TerminateProcess";
|
||||
|
||||
try
|
||||
{
|
||||
var process = Process.GetProcessById(pid);
|
||||
process.Kill();
|
||||
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Terminated integration process (PID {pid}).");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to terminate process (PID {pid}), likely already exited.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var pid in _activeIntegrations.Keys)
|
||||
{
|
||||
TerminateProcess(pid);
|
||||
}
|
||||
|
||||
_activeIntegrations.Clear();
|
||||
_activityWatcher.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,9 @@
|
||||
public string Name { get; set; } = "";
|
||||
public string Location { get; set; } = "";
|
||||
public string LaunchArgs { get; set; } = "";
|
||||
public bool SpecifyGame { get; set; } = false;
|
||||
public string GameID { get; set; } = "";
|
||||
public bool AutoCloseOnGame { get; set; } = true;
|
||||
public bool AutoClose { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<BloxstrapCustomBootstrapper Version="1" Height="320" Width="500">
|
||||
<!-- Put UI elements here -->
|
||||
<!-- Examples of custom bootstrappers can be found at https://github.com/bloxstraplabs/custom-bootstrapper-examples -->
|
||||
<!-- {0} -->
|
||||
<!-- {1} -->
|
||||
</BloxstrapCustomBootstrapper>
|
@ -1,5 +1,5 @@
|
||||
<BloxstrapCustomBootstrapper Version="1" Height="320" Width="520" IgnoreTitleBarInset="True" Theme="Default" Margin="30">
|
||||
<!-- Find more custom bootstrapper examples at https://github.com/bloxstraplabs/custom-bootstrapper-examples -->
|
||||
<!-- {0} -->
|
||||
<TitleBar Title="" ShowMinimize="False" ShowClose="False" />
|
||||
|
||||
<Image Source="{Icon}" Height="100" Width="100" HorizontalAlignment="Center" Margin="0,15,0,0" />
|
||||
|
65
Bloxstrap/Resources/Strings.Designer.cs
generated
65
Bloxstrap/Resources/Strings.Designer.cs
generated
@ -973,6 +973,15 @@ namespace Bloxstrap.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Custom Theme {0}.
|
||||
/// </summary>
|
||||
public static string CustomTheme_DefaultName {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomTheme.DefaultName", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Save changes to {0}?.
|
||||
/// </summary>
|
||||
@ -1271,6 +1280,33 @@ namespace Bloxstrap.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Examples of custom bootstrappers can be found at {0}.
|
||||
/// </summary>
|
||||
public static string CustomTheme_Templates_Blank_MoreExamples {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomTheme.Templates.Blank.MoreExamples", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Put UI elements here.
|
||||
/// </summary>
|
||||
public static string CustomTheme_Templates_Blank_UIElements {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomTheme.Templates.Blank.UIElements", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Find more custom bootstrapper examples at {0}.
|
||||
/// </summary>
|
||||
public static string CustomTheme_Templates_Simple_MoreExamples {
|
||||
get {
|
||||
return ResourceManager.GetString("CustomTheme.Templates.Simple.MoreExamples", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Add Fast Flag.
|
||||
/// </summary>
|
||||
@ -3280,7 +3316,34 @@ namespace Bloxstrap.Resources {
|
||||
return ResourceManager.GetString("Menu.Integrations.Custom.AppLocation", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Run on specific games.
|
||||
/// </summary>
|
||||
public static string Menu_Integrations_Custom_SpecifyGame {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu.Integrations.Custom.SpecifyGame", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Game ID.
|
||||
/// </summary>
|
||||
public static string Menu_Integrations_Custom_GameID {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu.Integrations.Custom.GameID", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Auto close when game closes.
|
||||
/// </summary>
|
||||
public static string Menu_Integrations_Custom_AutoCloseOnGame {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu.Integrations.Custom.AutoCloseOnGame", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Auto close when Roblox closes.
|
||||
/// </summary>
|
||||
|
@ -689,6 +689,15 @@ Selecting 'No' will ignore this warning and continue installation.</value>
|
||||
<data name="Menu.Integrations.Custom.AppLocation" xml:space="preserve">
|
||||
<value>Application Location</value>
|
||||
</data>
|
||||
<data name="Menu.Integrations.Custom.SpecifyGame" xml:space="preserve">
|
||||
<value>Run on a specific game</value>
|
||||
</data>
|
||||
<data name="Menu.Integrations.Custom.GameID" xml:space="preserve">
|
||||
<value>Game ID</value>
|
||||
</data>
|
||||
<data name="Menu.Integrations.Custom.AutoCloseOnGame" xml:space="preserve">
|
||||
<value>Auto close when the game closes</value>
|
||||
</data>
|
||||
<data name="Menu.Integrations.Custom.AutoClose" xml:space="preserve">
|
||||
<value>Auto close when Roblox closes</value>
|
||||
</data>
|
||||
@ -1474,4 +1483,17 @@ Defaulting to {1}.</value>
|
||||
<data name="Menu.Behaviour.BackgroundUpdates.Description" xml:space="preserve">
|
||||
<value>Update Roblox in the background instead of waiting. Not recommended for slow networks. At least 3GB of free storage space is required for this feature to work.</value>
|
||||
</data>
|
||||
<data name="CustomTheme.Templates.Blank.UIElements" xml:space="preserve">
|
||||
<value>Put UI elements here</value>
|
||||
</data>
|
||||
<data name="CustomTheme.Templates.Blank.MoreExamples" xml:space="preserve">
|
||||
<value>Examples of custom bootstrappers can be found at {0}</value>
|
||||
</data>
|
||||
<data name="CustomTheme.Templates.Simple.MoreExamples" xml:space="preserve">
|
||||
<value>Find more custom bootstrapper examples at {0}</value>
|
||||
</data>
|
||||
<data name="CustomTheme.DefaultName" xml:space="preserve">
|
||||
<value>Custom Theme {0}</value>
|
||||
<comment>{0} is a string (e.g. '1', '1-1234')</comment>
|
||||
</data>
|
||||
</root>
|
21
Bloxstrap/UI/Converters/BooleanToVisibilityConverter.cs
Normal file
21
Bloxstrap/UI/Converters/BooleanToVisibilityConverter.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Bloxstrap.UI.Converters
|
||||
{
|
||||
public class BooleanToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool boolValue)
|
||||
return boolValue ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Bloxstrap.UI.Converters
|
||||
{
|
||||
public class InverseBooleanToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool boolValue)
|
||||
return boolValue ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
return Visibility.Visible;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -110,6 +110,7 @@
|
||||
<controls:MarkdownTextBlock MarkdownText="[Redusofficial](https://github.com/Redusofficial)" />
|
||||
<controls:MarkdownTextBlock MarkdownText="[srthMD](https://github.com/srthMD)" />
|
||||
<controls:MarkdownTextBlock MarkdownText="[axellse](https://github.com/axellse)" />
|
||||
<controls:MarkdownTextBlock MarkdownText="[CubesterYT](https://github.com/CubesterYT)" />
|
||||
</StackPanel>
|
||||
</controls:Expander>
|
||||
|
||||
|
@ -39,11 +39,12 @@ namespace Bloxstrap.UI.Elements.Dialogs
|
||||
{
|
||||
int count = Directory.GetDirectories(Paths.CustomThemes).Count();
|
||||
|
||||
string name = $"Custom Theme {count + 1}";
|
||||
int i = count + 1;
|
||||
string name = string.Format(Strings.CustomTheme_DefaultName, i);
|
||||
|
||||
// TODO: this sucks
|
||||
if (File.Exists(GetThemePath(name)))
|
||||
name += " " + Random.Shared.Next(1, 100000).ToString(); // easy
|
||||
name = string.Format(Strings.CustomTheme_DefaultName, $"{i}-{Random.Shared.Next(1, 100000)}"); // easy
|
||||
|
||||
return name;
|
||||
}
|
||||
@ -76,7 +77,7 @@ namespace Bloxstrap.UI.Elements.Dialogs
|
||||
|
||||
string themeFilePath = Path.Combine(dir, "Theme.xml");
|
||||
|
||||
string templateContent = Encoding.UTF8.GetString(Resource.Get(template.GetFileName()).Result);
|
||||
string templateContent = template.GetFileContents();
|
||||
|
||||
File.WriteAllText(themeFilePath, templateContent);
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
|
||||
<TextBlock Text="{x:Static resources:Strings.Menu_Integrations_Custom_Title}" FontSize="20" FontWeight="Medium" Margin="0,16,0,0" />
|
||||
<TextBlock Text="{x:Static resources:Strings.Menu_Integrations_Custom_Description}" TextWrapping="Wrap" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
||||
<Grid Margin="0,8,0,0">
|
||||
<Grid Margin="0,8,0,0" MinHeight="325">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
@ -109,7 +109,11 @@
|
||||
</Grid>
|
||||
<TextBlock Margin="0,8,0,0" Text="{x:Static resources:Strings.Menu_Integrations_Custom_LaunchArgs}" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
||||
<ui:TextBox Margin="0,4,0,0" PlaceholderText="{Binding Source='/k echo {0}', Converter={StaticResource StringFormatConverter}, ConverterParameter={x:Static resources:Strings.Menu_Integrations_Custom_LaunchArgs_Placeholder}}" Text="{Binding SelectedCustomIntegration.LaunchArgs}" TextWrapping="Wrap" AcceptsReturn="True" AcceptsTab="True" />
|
||||
<CheckBox Margin="0,8,0,0" Content="{x:Static resources:Strings.Menu_Integrations_Custom_AutoClose}" IsChecked="{Binding SelectedCustomIntegration.AutoClose}" />
|
||||
<CheckBox Margin="0,8,0,0" Content="{x:Static resources:Strings.Menu_Integrations_Custom_SpecifyGame}" IsChecked="{Binding SelectedCustomIntegration.SpecifyGame, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBlock Margin="0,8,0,0" Text="{x:Static resources:Strings.Menu_Integrations_Custom_GameID}" Foreground="{DynamicResource TextFillColorSecondaryBrush}" Visibility="{Binding SelectedCustomIntegration.SpecifyGame, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
<ui:TextBox Margin="0,4,0,0" PlaceholderText="1818" Text="{Binding SelectedCustomIntegration.GameID}" Visibility="{Binding SelectedCustomIntegration.SpecifyGame, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
<CheckBox Margin="0,8,0,0" Content="{x:Static resources:Strings.Menu_Integrations_Custom_AutoCloseOnGame}" IsChecked="{Binding SelectedCustomIntegration.AutoCloseOnGame, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding SelectedCustomIntegration.SpecifyGame, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
<CheckBox Margin="0,8,0,0" Content="{x:Static resources:Strings.Menu_Integrations_Custom_AutoClose}" IsChecked="{Binding SelectedCustomIntegration.AutoClose, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding SelectedCustomIntegration.SpecifyGame, Converter={StaticResource InverseBooleanToVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Row="0" Grid.RowSpan="2" Grid.Column="1" Text="{x:Static resources:Strings.Menu_Integrations_Custom_NoneSelected}" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||
<TextBlock.Style>
|
||||
|
@ -9,13 +9,15 @@ namespace Bloxstrap
|
||||
private readonly InterProcessLock _lock = new("Watcher");
|
||||
|
||||
private readonly WatcherData? _watcherData;
|
||||
|
||||
|
||||
private readonly NotifyIconWrapper? _notifyIcon;
|
||||
|
||||
public readonly ActivityWatcher? ActivityWatcher;
|
||||
|
||||
public readonly DiscordRichPresence? RichPresence;
|
||||
|
||||
public readonly IntegrationWatcher? IntegrationWatcher;
|
||||
|
||||
public Watcher()
|
||||
{
|
||||
const string LOG_IDENT = "Watcher";
|
||||
@ -63,6 +65,8 @@ namespace Bloxstrap
|
||||
|
||||
if (App.Settings.Prop.UseDiscordRichPresence)
|
||||
RichPresence = new(ActivityWatcher);
|
||||
|
||||
IntegrationWatcher = new IntegrationWatcher(ActivityWatcher);
|
||||
}
|
||||
|
||||
_notifyIcon = new(this);
|
||||
@ -122,6 +126,7 @@ namespace Bloxstrap
|
||||
{
|
||||
App.Logger.WriteLine("Watcher::Dispose", "Disposing Watcher");
|
||||
|
||||
IntegrationWatcher?.Dispose();
|
||||
_notifyIcon?.Dispose();
|
||||
RichPresence?.Dispose();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user