mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-21 10:01:27 -07:00
Merge branch 'main' into user-pfp-discord-rpc
This commit is contained in:
commit
5d5726bf8b
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
ko_fi: boxerpizza
|
14
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
14
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -11,6 +11,7 @@ body:
|
|||||||
- If your problem is with Roblox itself (i.e. it crashes or doesn't launch), [check to see if it happens without Bloxstrap](https://github.com/pizzaboxer/bloxstrap/wiki/Roblox-crashes-or-does-not-launch).
|
- If your problem is with Roblox itself (i.e. it crashes or doesn't launch), [check to see if it happens without Bloxstrap](https://github.com/pizzaboxer/bloxstrap/wiki/Roblox-crashes-or-does-not-launch).
|
||||||
- Please only open an issue if your problem happens only with Bloxstrap, and state clearly that this is the case, as anything else is out of my control.
|
- Please only open an issue if your problem happens only with Bloxstrap, and state clearly that this is the case, as anything else is out of my control.
|
||||||
- If you are getting a Bloxstrap Exception error, please attach a copy of the provided log file. There is a button on the dialog that locates it for you.
|
- If you are getting a Bloxstrap Exception error, please attach a copy of the provided log file. There is a button on the dialog that locates it for you.
|
||||||
|
- Also, please ensure you are using the [latest version of Bloxstrap](https://github.com/pizzaboxer/bloxstrap/releases/latest). Your report will be null and void if you are not.
|
||||||
- If more clarification on the issue is needed, and you don't respond after a month, then your issue will be closed as stale.
|
- If more clarification on the issue is needed, and you don't respond after a month, then your issue will be closed as stale.
|
||||||
- type: checkboxes
|
- type: checkboxes
|
||||||
id: terms
|
id: terms
|
||||||
@ -19,7 +20,11 @@ body:
|
|||||||
options:
|
options:
|
||||||
- label: I have read the preliminary instructions, and I am certain that my problem has not already been addressed.
|
- label: I have read the preliminary instructions, and I am certain that my problem has not already been addressed.
|
||||||
required: true
|
required: true
|
||||||
- label: My answer given in the checkbox above is a lie.
|
- label: I have thoroughly looked through the available Wiki articles and could not find a solution to my problem.
|
||||||
|
required: true
|
||||||
|
- label: I am using the latest version of Bloxstrap.
|
||||||
|
required: true
|
||||||
|
- label: I did not answer truthfully to all the above checkboxes.
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: what-happened
|
id: what-happened
|
||||||
attributes:
|
attributes:
|
||||||
@ -27,3 +32,10 @@ body:
|
|||||||
description: Provide a comprehensive description of the problem you're facing. Don't forget to attach any additional resources you may have, such as log files and screenshots.
|
description: Provide a comprehensive description of the problem you're facing. Don't forget to attach any additional resources you may have, such as log files and screenshots.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: log
|
||||||
|
attributes:
|
||||||
|
label: Bloxstrap Log
|
||||||
|
description: If you're getting a Bloxstrap Exception error, upload your log file here. Otherwise, just leave it empty.
|
||||||
|
value: "N/A"
|
||||||
|
#render: text
|
||||||
|
@ -6,6 +6,9 @@ using System.Windows.Threading;
|
|||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
using Bloxstrap.Models.SettingTasks.Base;
|
using Bloxstrap.Models.SettingTasks.Base;
|
||||||
|
using Bloxstrap.UI.Elements.About.Pages;
|
||||||
|
using Bloxstrap.UI.Elements.About;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Bloxstrap
|
namespace Bloxstrap
|
||||||
{
|
{
|
||||||
@ -29,9 +32,11 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2];
|
public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2];
|
||||||
|
|
||||||
public static readonly MD5 MD5Provider = MD5.Create();
|
public static bool IsActionBuild => !String.IsNullOrEmpty(BuildMetadata.CommitRef);
|
||||||
|
|
||||||
public static NotifyIconWrapper? NotifyIcon { get; set; }
|
public static bool IsProductionBuild => IsActionBuild && BuildMetadata.CommitRef.StartsWith("tag", StringComparison.Ordinal);
|
||||||
|
|
||||||
|
public static readonly MD5 MD5Provider = MD5.Create();
|
||||||
|
|
||||||
public static readonly Logger Logger = new();
|
public static readonly Logger Logger = new();
|
||||||
|
|
||||||
@ -49,19 +54,23 @@ namespace Bloxstrap
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
#if RELEASE
|
|
||||||
private static bool _showingExceptionDialog = false;
|
private static bool _showingExceptionDialog = false;
|
||||||
#endif
|
|
||||||
|
private static bool _terminating = false;
|
||||||
|
|
||||||
public static void Terminate(ErrorCode exitCode = ErrorCode.ERROR_SUCCESS)
|
public static void Terminate(ErrorCode exitCode = ErrorCode.ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
|
if (_terminating)
|
||||||
|
return;
|
||||||
|
|
||||||
int exitCodeNum = (int)exitCode;
|
int exitCodeNum = (int)exitCode;
|
||||||
|
|
||||||
Logger.WriteLine("App::Terminate", $"Terminating with exit code {exitCodeNum} ({exitCode})");
|
Logger.WriteLine("App::Terminate", $"Terminating with exit code {exitCodeNum} ({exitCode})");
|
||||||
|
|
||||||
NotifyIcon?.Dispose();
|
Current.Dispatcher.Invoke(() => Current.Shutdown(exitCodeNum));
|
||||||
|
// Environment.Exit(exitCodeNum);
|
||||||
|
|
||||||
Environment.Exit(exitCodeNum);
|
_terminating = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalExceptionHandler(object sender, DispatcherUnhandledExceptionEventArgs e)
|
void GlobalExceptionHandler(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||||||
@ -73,24 +82,28 @@ namespace Bloxstrap
|
|||||||
FinalizeExceptionHandling(e.Exception);
|
FinalizeExceptionHandling(e.Exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void FinalizeExceptionHandling(Exception exception, bool log = true)
|
public static void FinalizeExceptionHandling(AggregateException ex)
|
||||||
|
{
|
||||||
|
foreach (var innerEx in ex.InnerExceptions)
|
||||||
|
Logger.WriteException("App::FinalizeExceptionHandling", innerEx);
|
||||||
|
|
||||||
|
FinalizeExceptionHandling(ex.GetBaseException(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FinalizeExceptionHandling(Exception ex, bool log = true)
|
||||||
{
|
{
|
||||||
if (log)
|
if (log)
|
||||||
Logger.WriteException("App::FinalizeExceptionHandling", exception);
|
Logger.WriteException("App::FinalizeExceptionHandling", ex);
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
throw exception;
|
|
||||||
#else
|
|
||||||
if (_showingExceptionDialog)
|
if (_showingExceptionDialog)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_showingExceptionDialog = true;
|
_showingExceptionDialog = true;
|
||||||
|
|
||||||
if (!LaunchSettings.QuietFlag.Active)
|
if (!LaunchSettings.QuietFlag.Active)
|
||||||
Frontend.ShowExceptionDialog(exception);
|
Frontend.ShowExceptionDialog(ex);
|
||||||
|
|
||||||
Terminate(ErrorCode.ERROR_INSTALL_FAILURE);
|
Terminate(ErrorCode.ERROR_INSTALL_FAILURE);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnStartup(StartupEventArgs e)
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
@ -103,10 +116,10 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
Logger.WriteLine(LOG_IDENT, $"Starting {ProjectName} v{Version}");
|
Logger.WriteLine(LOG_IDENT, $"Starting {ProjectName} v{Version}");
|
||||||
|
|
||||||
if (String.IsNullOrEmpty(BuildMetadata.CommitHash))
|
if (IsActionBuild)
|
||||||
Logger.WriteLine(LOG_IDENT, $"Compiled {BuildMetadata.Timestamp.ToFriendlyString()} from {BuildMetadata.Machine}");
|
|
||||||
else
|
|
||||||
Logger.WriteLine(LOG_IDENT, $"Compiled {BuildMetadata.Timestamp.ToFriendlyString()} from commit {BuildMetadata.CommitHash} ({BuildMetadata.CommitRef})");
|
Logger.WriteLine(LOG_IDENT, $"Compiled {BuildMetadata.Timestamp.ToFriendlyString()} from commit {BuildMetadata.CommitHash} ({BuildMetadata.CommitRef})");
|
||||||
|
else
|
||||||
|
Logger.WriteLine(LOG_IDENT, $"Compiled {BuildMetadata.Timestamp.ToFriendlyString()} from {BuildMetadata.Machine}");
|
||||||
|
|
||||||
Logger.WriteLine(LOG_IDENT, $"Loaded from {Paths.Process}");
|
Logger.WriteLine(LOG_IDENT, $"Loaded from {Paths.Process}");
|
||||||
|
|
||||||
@ -202,10 +215,6 @@ namespace Bloxstrap
|
|||||||
State.Load();
|
State.Load();
|
||||||
FastFlags.Load();
|
FastFlags.Load();
|
||||||
|
|
||||||
// we can only parse them now as settings need
|
|
||||||
// to be loaded first to know what our channel is
|
|
||||||
// LaunchSettings.ParseRoblox();
|
|
||||||
|
|
||||||
if (!Locale.SupportedLocales.ContainsKey(Settings.Prop.Locale))
|
if (!Locale.SupportedLocales.ContainsKey(Settings.Prop.Locale))
|
||||||
{
|
{
|
||||||
Settings.Prop.Locale = "nil";
|
Settings.Prop.Locale = "nil";
|
||||||
@ -214,13 +223,15 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
Locale.Set(Settings.Prop.Locale);
|
Locale.Set(Settings.Prop.Locale);
|
||||||
|
|
||||||
|
#if !DEBUG
|
||||||
if (!LaunchSettings.UninstallFlag.Active)
|
if (!LaunchSettings.UninstallFlag.Active)
|
||||||
Installer.HandleUpgrade();
|
Installer.HandleUpgrade();
|
||||||
|
#endif
|
||||||
|
|
||||||
LaunchHandler.ProcessLaunchArgs();
|
LaunchHandler.ProcessLaunchArgs();
|
||||||
}
|
}
|
||||||
|
|
||||||
Terminate();
|
// you must *explicitly* call terminate when everything is done, it won't be called implicitly
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,6 @@ using System.Windows.Forms;
|
|||||||
|
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
using Bloxstrap.Integrations;
|
|
||||||
using Bloxstrap.Resources;
|
|
||||||
using Bloxstrap.AppData;
|
using Bloxstrap.AppData;
|
||||||
|
|
||||||
namespace Bloxstrap
|
namespace Bloxstrap
|
||||||
@ -289,9 +287,6 @@ namespace Bloxstrap
|
|||||||
_launchCommandLine = _launchCommandLine.Replace("robloxLocale:en_us", $"robloxLocale:{match.Groups[1].Value}", StringComparison.InvariantCultureIgnoreCase);
|
_launchCommandLine = _launchCommandLine.Replace("robloxLocale:en_us", $"robloxLocale:{match.Groups[1].Value}", StringComparison.InvariantCultureIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
// whether we should wait for roblox to exit to handle stuff in the background or clean up after roblox closes
|
|
||||||
bool shouldWait = false;
|
|
||||||
|
|
||||||
var startInfo = new ProcessStartInfo()
|
var startInfo = new ProcessStartInfo()
|
||||||
{
|
{
|
||||||
FileName = _playerLocation,
|
FileName = _playerLocation,
|
||||||
@ -308,19 +303,16 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
// v2.2.0 - byfron will trip if we keep a process handle open for over a minute, so we're doing this now
|
// v2.2.0 - byfron will trip if we keep a process handle open for over a minute, so we're doing this now
|
||||||
int gameClientPid;
|
int gameClientPid;
|
||||||
using (Process gameClient = Process.Start(startInfo)!)
|
using (var gameClient = Process.Start(startInfo)!)
|
||||||
{
|
{
|
||||||
gameClientPid = gameClient.Id;
|
gameClientPid = gameClient.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Process?> autocloseProcesses = new();
|
|
||||||
ActivityWatcher? activityWatcher = null;
|
|
||||||
DiscordRichPresence? richPresence = null;
|
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Started Roblox (PID {gameClientPid})");
|
App.Logger.WriteLine(LOG_IDENT, $"Started Roblox (PID {gameClientPid})");
|
||||||
|
|
||||||
using (var startEvent = new SystemEvent(AppData.StartEvent))
|
using (var startEvent = new SystemEvent(AppData.StartEvent))
|
||||||
{
|
{
|
||||||
|
// TODO: get rid of this
|
||||||
bool startEventFired = await startEvent.WaitForEvent();
|
bool startEventFired = await startEvent.WaitForEvent();
|
||||||
|
|
||||||
startEvent.Close();
|
startEvent.Close();
|
||||||
@ -330,40 +322,14 @@ namespace Bloxstrap
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (App.Settings.Prop.EnableActivityTracking && _launchMode == LaunchMode.Player)
|
var autoclosePids = new List<int>();
|
||||||
App.NotifyIcon?.SetProcessId(gameClientPid);
|
|
||||||
|
|
||||||
if (App.Settings.Prop.EnableActivityTracking)
|
|
||||||
{
|
|
||||||
activityWatcher = new(gameClientPid);
|
|
||||||
shouldWait = true;
|
|
||||||
|
|
||||||
App.NotifyIcon?.SetActivityWatcher(activityWatcher);
|
|
||||||
|
|
||||||
if (App.Settings.Prop.UseDisableAppPatch)
|
|
||||||
{
|
|
||||||
activityWatcher.OnAppClose += (_, _) =>
|
|
||||||
{
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Received desktop app exit, closing Roblox");
|
|
||||||
using var process = Process.GetProcessById(gameClientPid);
|
|
||||||
process.CloseMainWindow();
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (App.Settings.Prop.UseDiscordRichPresence)
|
|
||||||
{
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Using Discord Rich Presence");
|
|
||||||
richPresence = new(activityWatcher);
|
|
||||||
|
|
||||||
App.NotifyIcon?.SetRichPresenceHandler(richPresence);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// launch custom integrations now
|
// launch custom integrations now
|
||||||
foreach (CustomIntegration integration in App.Settings.Prop.CustomIntegrations)
|
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})");
|
App.Logger.WriteLine(LOG_IDENT, $"Launching custom integration '{integration.Name}' ({integration.Location} {integration.LaunchArgs} - autoclose is {integration.AutoClose})");
|
||||||
|
|
||||||
|
int pid = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var process = Process.Start(new ProcessStartInfo
|
var process = Process.Start(new ProcessStartInfo
|
||||||
@ -372,48 +338,34 @@ namespace Bloxstrap
|
|||||||
Arguments = integration.LaunchArgs.Replace("\r\n", " "),
|
Arguments = integration.LaunchArgs.Replace("\r\n", " "),
|
||||||
WorkingDirectory = Path.GetDirectoryName(integration.Location),
|
WorkingDirectory = Path.GetDirectoryName(integration.Location),
|
||||||
UseShellExecute = true
|
UseShellExecute = true
|
||||||
});
|
})!;
|
||||||
|
|
||||||
if (integration.AutoClose)
|
pid = process.Id;
|
||||||
{
|
|
||||||
shouldWait = true;
|
|
||||||
autocloseProcesses.Add(process);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to launch integration '{integration.Name}'!");
|
App.Logger.WriteLine(LOG_IDENT, $"Failed to launch integration '{integration.Name}'!");
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"{ex.Message}");
|
App.Logger.WriteLine(LOG_IDENT, $"{ex.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (integration.AutoClose && pid != 0)
|
||||||
|
autoclosePids.Add(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var proclock = new InterProcessLock("Watcher"))
|
||||||
|
{
|
||||||
|
string args = gameClientPid.ToString();
|
||||||
|
|
||||||
|
if (autoclosePids.Any())
|
||||||
|
args += $";{String.Join(',', autoclosePids)}";
|
||||||
|
|
||||||
|
if (proclock.IsAcquired)
|
||||||
|
Process.Start(Paths.Process, $"-watcher \"{args}\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
// event fired, wait for 3 seconds then close
|
// event fired, wait for 3 seconds then close
|
||||||
await Task.Delay(3000);
|
await Task.Delay(3000);
|
||||||
Dialog?.CloseBootstrapper();
|
Dialog?.CloseBootstrapper();
|
||||||
|
|
||||||
// keep bloxstrap open in the background if needed
|
|
||||||
if (!shouldWait)
|
|
||||||
return;
|
|
||||||
|
|
||||||
activityWatcher?.StartWatcher();
|
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Waiting for Roblox to close");
|
|
||||||
|
|
||||||
while (Utilities.GetProcessesSafe().Any(x => x.Id == gameClientPid))
|
|
||||||
await Task.Delay(1000);
|
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Roblox has exited");
|
|
||||||
|
|
||||||
richPresence?.Dispose();
|
|
||||||
|
|
||||||
foreach (var process in autocloseProcesses)
|
|
||||||
{
|
|
||||||
if (process is null || process.HasExited)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Autoclosing process '{process.ProcessName}' (PID {process.Id})");
|
|
||||||
process.Kill();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CancelInstall()
|
public void CancelInstall()
|
||||||
@ -528,7 +480,7 @@ namespace Bloxstrap
|
|||||||
var versionComparison = Utilities.CompareVersions(App.Version, releaseInfo.TagName);
|
var versionComparison = Utilities.CompareVersions(App.Version, releaseInfo.TagName);
|
||||||
|
|
||||||
// check if we aren't using a deployed build, so we can update to one if a new version comes out
|
// check if we aren't using a deployed build, so we can update to one if a new version comes out
|
||||||
if (versionComparison == VersionComparison.Equal && App.BuildMetadata.CommitRef.StartsWith("tag") || versionComparison == VersionComparison.GreaterThan)
|
if (versionComparison == VersionComparison.Equal && App.IsProductionBuild || versionComparison == VersionComparison.GreaterThan)
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"No updates found");
|
App.Logger.WriteLine(LOG_IDENT, $"No updates found");
|
||||||
return;
|
return;
|
||||||
|
@ -4,9 +4,7 @@
|
|||||||
{
|
{
|
||||||
[EnumName(FromTranslation = "Common.Automatic")]
|
[EnumName(FromTranslation = "Common.Automatic")]
|
||||||
Default,
|
Default,
|
||||||
// Vulkan,
|
|
||||||
D3D11,
|
D3D11,
|
||||||
D3D10,
|
D3D10,
|
||||||
// OpenGL
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
public override string FileLocation => Path.Combine(Paths.Modifications, "ClientSettings\\ClientAppSettings.json");
|
public override string FileLocation => Path.Combine(Paths.Modifications, "ClientSettings\\ClientAppSettings.json");
|
||||||
|
|
||||||
|
public bool Changed => !OriginalProp.SequenceEqual(Prop);
|
||||||
|
|
||||||
public static IReadOnlyDictionary<string, string> PresetFlags = new Dictionary<string, string>
|
public static IReadOnlyDictionary<string, string> PresetFlags = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
{ "Network.Log", "FLogNetwork" },
|
{ "Network.Log", "FLogNetwork" },
|
||||||
@ -28,9 +30,6 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
{ "Rendering.Mode.D3D11", "FFlagDebugGraphicsPreferD3D11" },
|
{ "Rendering.Mode.D3D11", "FFlagDebugGraphicsPreferD3D11" },
|
||||||
{ "Rendering.Mode.D3D10", "FFlagDebugGraphicsPreferD3D11FL10" },
|
{ "Rendering.Mode.D3D10", "FFlagDebugGraphicsPreferD3D11FL10" },
|
||||||
{ "Rendering.Mode.Vulkan", "FFlagDebugGraphicsPreferVulkan" },
|
|
||||||
{ "Rendering.Mode.Vulkan.Fix", "FFlagRenderVulkanFixMinimizeWindow" },
|
|
||||||
{ "Rendering.Mode.OpenGL", "FFlagDebugGraphicsPreferOpenGL" },
|
|
||||||
|
|
||||||
{ "Rendering.Lighting.Voxel", "DFFlagDebugRenderForceTechnologyVoxel" },
|
{ "Rendering.Lighting.Voxel", "DFFlagDebugRenderForceTechnologyVoxel" },
|
||||||
{ "Rendering.Lighting.ShadowMap", "FFlagDebugForceFutureIsBrightPhase2" },
|
{ "Rendering.Lighting.ShadowMap", "FFlagDebugForceFutureIsBrightPhase2" },
|
||||||
@ -63,10 +62,8 @@ namespace Bloxstrap
|
|||||||
public static IReadOnlyDictionary<RenderingMode, string> RenderingModes => new Dictionary<RenderingMode, string>
|
public static IReadOnlyDictionary<RenderingMode, string> RenderingModes => new Dictionary<RenderingMode, string>
|
||||||
{
|
{
|
||||||
{ RenderingMode.Default, "None" },
|
{ RenderingMode.Default, "None" },
|
||||||
// { RenderingMode.Vulkan, "Vulkan" },
|
|
||||||
{ RenderingMode.D3D11, "D3D11" },
|
{ RenderingMode.D3D11, "D3D11" },
|
||||||
{ RenderingMode.D3D10, "D3D10" },
|
{ RenderingMode.D3D10, "D3D10" },
|
||||||
// { RenderingMode.OpenGL, "OpenGL" }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public static IReadOnlyDictionary<LightingMode, string> LightingModes => new Dictionary<LightingMode, string>
|
public static IReadOnlyDictionary<LightingMode, string> LightingModes => new Dictionary<LightingMode, string>
|
||||||
@ -228,14 +225,6 @@ namespace Bloxstrap
|
|||||||
return mapping.First().Key;
|
return mapping.First().Key;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CheckManualFullscreenPreset()
|
|
||||||
{
|
|
||||||
if (GetPreset("Rendering.Mode.Vulkan") == "True" || GetPreset("Rendering.Mode.OpenGL") == "True")
|
|
||||||
SetPreset("Rendering.ManualFullscreen", null);
|
|
||||||
else
|
|
||||||
SetPreset("Rendering.ManualFullscreen", "False");
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Save()
|
public override void Save()
|
||||||
{
|
{
|
||||||
// convert all flag values to strings before saving
|
// convert all flag values to strings before saving
|
||||||
@ -244,13 +233,17 @@ namespace Bloxstrap
|
|||||||
Prop[pair.Key] = pair.Value.ToString()!;
|
Prop[pair.Key] = pair.Value.ToString()!;
|
||||||
|
|
||||||
base.Save();
|
base.Save();
|
||||||
|
|
||||||
|
// clone the dictionary
|
||||||
|
OriginalProp = new(Prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Load()
|
public override void Load()
|
||||||
{
|
{
|
||||||
base.Load();
|
base.Load();
|
||||||
|
|
||||||
CheckManualFullscreenPreset();
|
// clone the dictionary
|
||||||
|
OriginalProp = new(Prop);
|
||||||
|
|
||||||
// TODO - remove when activity tracking has been revamped
|
// TODO - remove when activity tracking has been revamped
|
||||||
if (GetPreset("Network.Log") != "7")
|
if (GetPreset("Network.Log") != "7")
|
||||||
|
@ -340,6 +340,18 @@ namespace Bloxstrap
|
|||||||
if (MD5Hash.FromFile(Paths.Process) == MD5Hash.FromFile(Paths.Application))
|
if (MD5Hash.FromFile(Paths.Process) == MD5Hash.FromFile(Paths.Application))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (currentVer is not null && existingVer is not null && Utilities.CompareVersions(currentVer, existingVer) == VersionComparison.LessThan)
|
||||||
|
{
|
||||||
|
var result = Frontend.ShowMessageBox(
|
||||||
|
Strings.InstallChecker_VersionLessThanInstalled,
|
||||||
|
MessageBoxImage.Question,
|
||||||
|
MessageBoxButton.YesNo
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != MessageBoxResult.Yes)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// silently upgrade version if the command line flag is set or if we're launching from an auto update
|
// silently upgrade version if the command line flag is set or if we're launching from an auto update
|
||||||
if (!App.LaunchSettings.UpgradeFlag.Active && !isAutoUpgrade)
|
if (!App.LaunchSettings.UpgradeFlag.Active && !isAutoUpgrade)
|
||||||
{
|
{
|
||||||
@ -466,6 +478,9 @@ namespace Bloxstrap
|
|||||||
App.FastFlags.Save();
|
App.FastFlags.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentVer is null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (isAutoUpgrade)
|
if (isAutoUpgrade)
|
||||||
{
|
{
|
||||||
Utilities.ShellExecute($"https://github.com/{App.ProjectRepository}/wiki/Release-notes-for-Bloxstrap-v{currentVer}");
|
Utilities.ShellExecute($"https://github.com/{App.ProjectRepository}/wiki/Release-notes-for-Bloxstrap-v{currentVer}");
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
private const string GameJoinedEntryPattern = @"serverId: ([0-9\.]+)\|[0-9]+";
|
private const string GameJoinedEntryPattern = @"serverId: ([0-9\.]+)\|[0-9]+";
|
||||||
private const string GameMessageEntryPattern = @"\[BloxstrapRPC\] (.*)";
|
private const string GameMessageEntryPattern = @"\[BloxstrapRPC\] (.*)";
|
||||||
|
|
||||||
private int _gameClientPid;
|
|
||||||
private int _logEntriesRead = 0;
|
private int _logEntriesRead = 0;
|
||||||
private bool _teleportMarker = false;
|
private bool _teleportMarker = false;
|
||||||
private bool _reservedTeleportMarker = false;
|
private bool _reservedTeleportMarker = false;
|
||||||
@ -29,6 +28,7 @@
|
|||||||
public event EventHandler<string>? OnLogEntry;
|
public event EventHandler<string>? OnLogEntry;
|
||||||
public event EventHandler? OnGameJoin;
|
public event EventHandler? OnGameJoin;
|
||||||
public event EventHandler? OnGameLeave;
|
public event EventHandler? OnGameLeave;
|
||||||
|
public event EventHandler? OnLogOpen;
|
||||||
public event EventHandler? OnAppClose;
|
public event EventHandler? OnAppClose;
|
||||||
public event EventHandler<Message>? OnRPCMessage;
|
public event EventHandler<Message>? OnRPCMessage;
|
||||||
|
|
||||||
@ -50,14 +50,9 @@
|
|||||||
|
|
||||||
public bool IsDisposed = false;
|
public bool IsDisposed = false;
|
||||||
|
|
||||||
public ActivityWatcher(int gameClientPid)
|
public async void Start()
|
||||||
{
|
{
|
||||||
_gameClientPid = gameClientPid;
|
const string LOG_IDENT = "ActivityWatcher::Start";
|
||||||
}
|
|
||||||
|
|
||||||
public async void StartWatcher()
|
|
||||||
{
|
|
||||||
const string LOG_IDENT = "ActivityWatcher::StartWatcher";
|
|
||||||
|
|
||||||
// okay, here's the process:
|
// okay, here's the process:
|
||||||
//
|
//
|
||||||
@ -87,23 +82,26 @@
|
|||||||
{
|
{
|
||||||
logFileInfo = new DirectoryInfo(logDirectory)
|
logFileInfo = new DirectoryInfo(logDirectory)
|
||||||
.GetFiles()
|
.GetFiles()
|
||||||
.Where(x => x.CreationTime <= DateTime.Now)
|
.Where(x => x.Name.Contains("Player", StringComparison.OrdinalIgnoreCase) && x.CreationTime <= DateTime.Now)
|
||||||
.OrderByDescending(x => x.CreationTime)
|
.OrderByDescending(x => x.CreationTime)
|
||||||
.First();
|
.First();
|
||||||
|
|
||||||
if (logFileInfo.CreationTime.AddSeconds(15) > DateTime.Now)
|
if (logFileInfo.CreationTime.AddSeconds(15) > DateTime.Now)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// TODO: report failure after 10 seconds of no log file
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Could not find recent enough log file, waiting... (newest is {logFileInfo.Name})");
|
App.Logger.WriteLine(LOG_IDENT, $"Could not find recent enough log file, waiting... (newest is {logFileInfo.Name})");
|
||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OnLogOpen?.Invoke(this, EventArgs.Empty);
|
||||||
|
|
||||||
LogLocation = logFileInfo.FullName;
|
LogLocation = logFileInfo.FullName;
|
||||||
FileStream logFileStream = logFileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
FileStream logFileStream = logFileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Opened {LogLocation}");
|
App.Logger.WriteLine(LOG_IDENT, $"Opened {LogLocation}");
|
||||||
|
|
||||||
AutoResetEvent logUpdatedEvent = new(false);
|
var logUpdatedEvent = new AutoResetEvent(false);
|
||||||
FileSystemWatcher logWatcher = new()
|
var logWatcher = new FileSystemWatcher()
|
||||||
{
|
{
|
||||||
Path = logDirectory,
|
Path = logDirectory,
|
||||||
Filter = Path.GetFileName(logFileInfo.FullName),
|
Filter = Path.GetFileName(logFileInfo.FullName),
|
||||||
@ -111,7 +109,7 @@
|
|||||||
};
|
};
|
||||||
logWatcher.Changed += (s, e) => logUpdatedEvent.Set();
|
logWatcher.Changed += (s, e) => logUpdatedEvent.Set();
|
||||||
|
|
||||||
using StreamReader sr = new(logFileStream);
|
using var sr = new StreamReader(logFileStream);
|
||||||
|
|
||||||
while (!IsDisposed)
|
while (!IsDisposed)
|
||||||
{
|
{
|
||||||
@ -120,13 +118,13 @@
|
|||||||
if (log is null)
|
if (log is null)
|
||||||
logUpdatedEvent.WaitOne(250);
|
logUpdatedEvent.WaitOne(250);
|
||||||
else
|
else
|
||||||
ExamineLogEntry(log);
|
ReadLogEntry(log);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExamineLogEntry(string entry)
|
private void ReadLogEntry(string entry)
|
||||||
{
|
{
|
||||||
const string LOG_IDENT = "ActivityWatcher::ExamineLogEntry";
|
const string LOG_IDENT = "ActivityWatcher::ReadLogEntry";
|
||||||
|
|
||||||
OnLogEntry?.Invoke(this, entry);
|
OnLogEntry?.Invoke(this, entry);
|
||||||
|
|
||||||
@ -319,7 +317,7 @@
|
|||||||
var ipInfo = await Http.GetJson<IPInfoResponse>($"https://ipinfo.io/{ActivityMachineAddress}/json");
|
var ipInfo = await Http.GetJson<IPInfoResponse>($"https://ipinfo.io/{ActivityMachineAddress}/json");
|
||||||
|
|
||||||
if (ipInfo is null)
|
if (ipInfo is null)
|
||||||
return $"? ({Resources.Strings.ActivityTracker_LookupFailed})";
|
return $"? ({Strings.ActivityTracker_LookupFailed})";
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(ipInfo.Country))
|
if (string.IsNullOrEmpty(ipInfo.Country))
|
||||||
location = "?";
|
location = "?";
|
||||||
@ -329,7 +327,7 @@
|
|||||||
location = $"{ipInfo.City}, {ipInfo.Region}, {ipInfo.Country}";
|
location = $"{ipInfo.City}, {ipInfo.Region}, {ipInfo.Country}";
|
||||||
|
|
||||||
if (!ActivityInGame)
|
if (!ActivityInGame)
|
||||||
return $"? ({Resources.Strings.ActivityTracker_LeftGame})";
|
return $"? ({Strings.ActivityTracker_LeftGame})";
|
||||||
|
|
||||||
GeolocationCache[ActivityMachineAddress] = location;
|
GeolocationCache[ActivityMachineAddress] = location;
|
||||||
|
|
||||||
@ -340,7 +338,7 @@
|
|||||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to get server location for {ActivityMachineAddress}");
|
App.Logger.WriteLine(LOG_IDENT, $"Failed to get server location for {ActivityMachineAddress}");
|
||||||
App.Logger.WriteException(LOG_IDENT, ex);
|
App.Logger.WriteException(LOG_IDENT, ex);
|
||||||
|
|
||||||
return $"? ({Resources.Strings.ActivityTracker_LookupFailed})";
|
return $"? ({Strings.ActivityTracker_LookupFailed})";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,6 +198,8 @@ namespace Bloxstrap.Integrations
|
|||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Setting presence for Place ID {placeId}");
|
App.Logger.WriteLine(LOG_IDENT, $"Setting presence for Place ID {placeId}");
|
||||||
|
|
||||||
|
// TODO: move this to its own function under the activity watcher?
|
||||||
|
// TODO: show error if information cannot be queried instead of silently failing
|
||||||
var universeIdResponse = await Http.GetJson<UniverseIdResponse>($"https://apis.roblox.com/universes/v1/places/{placeId}/universe");
|
var universeIdResponse = await Http.GetJson<UniverseIdResponse>($"https://apis.roblox.com/universes/v1/places/{placeId}/universe");
|
||||||
if (universeIdResponse is null)
|
if (universeIdResponse is null)
|
||||||
{
|
{
|
||||||
@ -312,6 +314,7 @@ namespace Bloxstrap.Integrations
|
|||||||
// this is used for configuration from BloxstrapRPC
|
// this is used for configuration from BloxstrapRPC
|
||||||
_currentPresenceCopy = _currentPresence.Clone();
|
_currentPresenceCopy = _currentPresence.Clone();
|
||||||
|
|
||||||
|
// TODO: use queue for stashing messages
|
||||||
if (_stashedRPCMessage is not null)
|
if (_stashedRPCMessage is not null)
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Found stashed RPC message, invoking presence set command now");
|
App.Logger.WriteLine(LOG_IDENT, "Found stashed RPC message, invoking presence set command now");
|
||||||
|
@ -4,6 +4,8 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
public class JsonManager<T> where T : class, new()
|
public class JsonManager<T> where T : class, new()
|
||||||
{
|
{
|
||||||
|
public T OriginalProp { get; set; } = new();
|
||||||
|
|
||||||
public T Prop { get; set; } = new();
|
public T Prop { get; set; } = new();
|
||||||
|
|
||||||
public virtual string FileLocation => Path.Combine(Paths.Base, $"{typeof(T).Name}.json");
|
public virtual string FileLocation => Path.Combine(Paths.Base, $"{typeof(T).Name}.json");
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
using Bloxstrap.UI.Elements.Dialogs;
|
|
||||||
|
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using Windows.Win32;
|
using Windows.Win32;
|
||||||
using Windows.Win32.Foundation;
|
using Windows.Win32.Foundation;
|
||||||
|
|
||||||
|
using Bloxstrap.UI.Elements.Dialogs;
|
||||||
|
|
||||||
namespace Bloxstrap
|
namespace Bloxstrap
|
||||||
{
|
{
|
||||||
public static class LaunchHandler
|
public static class LaunchHandler
|
||||||
@ -19,6 +19,7 @@ namespace Bloxstrap
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NextAction.LaunchRoblox:
|
case NextAction.LaunchRoblox:
|
||||||
|
App.LaunchSettings.RobloxLaunchMode = LaunchMode.Player;
|
||||||
LaunchRoblox();
|
LaunchRoblox();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -120,6 +121,8 @@ namespace Bloxstrap
|
|||||||
Installer.DoUninstall(keepData);
|
Installer.DoUninstall(keepData);
|
||||||
|
|
||||||
Frontend.ShowMessageBox(Strings.Bootstrapper_SuccessfullyUninstalled, MessageBoxImage.Information);
|
Frontend.ShowMessageBox(Strings.Bootstrapper_SuccessfullyUninstalled, MessageBoxImage.Information);
|
||||||
|
|
||||||
|
App.Terminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void LaunchSettings()
|
public static void LaunchSettings()
|
||||||
@ -131,7 +134,7 @@ namespace Bloxstrap
|
|||||||
if (interlock.IsAcquired)
|
if (interlock.IsAcquired)
|
||||||
{
|
{
|
||||||
bool showAlreadyRunningWarning = Process.GetProcessesByName(App.ProjectName).Length > 1;
|
bool showAlreadyRunningWarning = Process.GetProcessesByName(App.ProjectName).Length > 1;
|
||||||
new UI.Elements.Settings.MainWindow(showAlreadyRunningWarning).ShowDialog();
|
new UI.Elements.Settings.MainWindow(showAlreadyRunningWarning).Show();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -156,7 +159,6 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
const string LOG_IDENT = "LaunchHandler::LaunchRoblox";
|
const string LOG_IDENT = "LaunchHandler::LaunchRoblox";
|
||||||
|
|
||||||
|
|
||||||
if (!File.Exists(Path.Combine(Paths.System, "mfplat.dll")))
|
if (!File.Exists(Path.Combine(Paths.System, "mfplat.dll")))
|
||||||
{
|
{
|
||||||
Frontend.ShowMessageBox(Strings.Bootstrapper_WMFNotFound, MessageBoxImage.Error);
|
Frontend.ShowMessageBox(Strings.Bootstrapper_WMFNotFound, MessageBoxImage.Error);
|
||||||
@ -191,8 +193,6 @@ namespace Bloxstrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
App.NotifyIcon = new();
|
|
||||||
|
|
||||||
// start bootstrapper and show the bootstrapper modal if we're not running silently
|
// start bootstrapper and show the bootstrapper modal if we're not running silently
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper");
|
App.Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper");
|
||||||
var bootstrapper = new Bootstrapper(installWebView2);
|
var bootstrapper = new Bootstrapper(installWebView2);
|
||||||
@ -206,45 +206,53 @@ namespace Bloxstrap
|
|||||||
dialog.Bootstrapper = bootstrapper;
|
dialog.Bootstrapper = bootstrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task bootstrapperTask = Task.Run(async () => await bootstrapper.Run()).ContinueWith(t =>
|
Task.Run(bootstrapper.Run).ContinueWith(t =>
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Bootstrapper task has finished");
|
App.Logger.WriteLine(LOG_IDENT, "Bootstrapper task has finished");
|
||||||
|
|
||||||
// notifyicon is blocking main thread, must be disposed here
|
|
||||||
App.NotifyIcon?.Dispose();
|
|
||||||
|
|
||||||
if (t.IsFaulted)
|
if (t.IsFaulted)
|
||||||
|
{
|
||||||
App.Logger.WriteLine(LOG_IDENT, "An exception occurred when running the bootstrapper");
|
App.Logger.WriteLine(LOG_IDENT, "An exception occurred when running the bootstrapper");
|
||||||
|
|
||||||
if (t.Exception is null)
|
if (t.Exception is not null)
|
||||||
return;
|
App.FinalizeExceptionHandling(t.Exception, false);
|
||||||
|
}
|
||||||
|
|
||||||
App.Logger.WriteException(LOG_IDENT, t.Exception);
|
App.Terminate();
|
||||||
|
|
||||||
Exception exception = t.Exception;
|
|
||||||
|
|
||||||
#if !DEBUG
|
|
||||||
if (t.Exception.GetType().ToString() == "System.AggregateException")
|
|
||||||
exception = t.Exception.InnerException!;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
App.FinalizeExceptionHandling(exception, false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// this ordering is very important as all wpf windows are shown as modal dialogs, mess it up and you'll end up blocking input to one of them
|
|
||||||
dialog?.ShowBootstrapper();
|
dialog?.ShowBootstrapper();
|
||||||
|
|
||||||
if (!App.LaunchSettings.NoLaunchFlag.Active && App.Settings.Prop.EnableActivityTracking)
|
|
||||||
App.NotifyIcon?.InitializeContextMenu();
|
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Waiting for bootstrapper task to finish");
|
|
||||||
|
|
||||||
bootstrapperTask.Wait();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void LaunchWatcher()
|
public static void LaunchWatcher()
|
||||||
{
|
{
|
||||||
|
const string LOG_IDENT = "LaunchHandler::LaunchWatcher";
|
||||||
|
|
||||||
|
// this whole topology is a bit confusing, bear with me:
|
||||||
|
// main thread: strictly UI only, handles showing of the notification area icon, context menu, server details dialog
|
||||||
|
// - server information task: queries server location, invoked if either the explorer notification is shown or the server details dialog is opened
|
||||||
|
// - discord rpc thread: handles rpc connection with discord
|
||||||
|
// - discord rich presence tasks: handles querying and displaying of game information, invoked on activity watcher events
|
||||||
|
// - watcher task: runs activity watcher + waiting for roblox to close, terminates when it has
|
||||||
|
|
||||||
|
var watcher = new Watcher();
|
||||||
|
|
||||||
|
Task.Run(watcher.Run).ContinueWith(t =>
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Watcher task has finished");
|
||||||
|
|
||||||
|
watcher.Dispose();
|
||||||
|
|
||||||
|
if (t.IsFaulted)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "An exception occurred when running the watcher");
|
||||||
|
|
||||||
|
if (t.Exception is not null)
|
||||||
|
App.FinalizeExceptionHandling(t.Exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
App.Terminate();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
public LaunchFlag StudioFlag { get; } = new("studio");
|
public LaunchFlag StudioFlag { get; } = new("studio");
|
||||||
|
|
||||||
public LaunchMode RobloxLaunchMode { get; private set; } = LaunchMode.None;
|
public LaunchMode RobloxLaunchMode { get; set; } = LaunchMode.None;
|
||||||
|
|
||||||
public string RobloxLaunchArgs { get; private set; } = "";
|
public string RobloxLaunchArgs { get; private set; } = "";
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
private readonly SemaphoreSlim _semaphore = new(1, 1);
|
private readonly SemaphoreSlim _semaphore = new(1, 1);
|
||||||
private FileStream? _filestream;
|
private FileStream? _filestream;
|
||||||
|
|
||||||
public readonly List<string> Backlog = new();
|
public readonly List<string> History = new();
|
||||||
public bool Initialized = false;
|
public bool Initialized = false;
|
||||||
public bool NoWriteMode = false;
|
public bool NoWriteMode = false;
|
||||||
public string? FileLocation;
|
public string? FileLocation;
|
||||||
@ -55,7 +55,7 @@
|
|||||||
WriteLine(LOG_IDENT, $"Failed to initialize because Bloxstrap cannot write to {directory}");
|
WriteLine(LOG_IDENT, $"Failed to initialize because Bloxstrap cannot write to {directory}");
|
||||||
|
|
||||||
Frontend.ShowMessageBox(
|
Frontend.ShowMessageBox(
|
||||||
String.Format(Resources.Strings.Logger_NoWriteMode, directory),
|
String.Format(Strings.Logger_NoWriteMode, directory),
|
||||||
System.Windows.MessageBoxImage.Warning,
|
System.Windows.MessageBoxImage.Warning,
|
||||||
System.Windows.MessageBoxButton.OK
|
System.Windows.MessageBoxButton.OK
|
||||||
);
|
);
|
||||||
@ -68,8 +68,8 @@
|
|||||||
|
|
||||||
Initialized = true;
|
Initialized = true;
|
||||||
|
|
||||||
if (Backlog.Count > 0)
|
if (History.Count > 0)
|
||||||
WriteToLog(string.Join("\r\n", Backlog));
|
WriteToLog(string.Join("\r\n", History));
|
||||||
|
|
||||||
WriteLine(LOG_IDENT, "Finished initializing!");
|
WriteLine(LOG_IDENT, "Finished initializing!");
|
||||||
|
|
||||||
@ -102,10 +102,12 @@
|
|||||||
{
|
{
|
||||||
string timestamp = DateTime.UtcNow.ToString("s") + "Z";
|
string timestamp = DateTime.UtcNow.ToString("s") + "Z";
|
||||||
string outcon = $"{timestamp} {message}";
|
string outcon = $"{timestamp} {message}";
|
||||||
string outlog = outcon.Replace(Paths.UserProfile, "%UserProfile%");
|
string outlog = outcon.Replace(Paths.UserProfile, "%UserProfile%", StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
|
||||||
Debug.WriteLine(outcon);
|
Debug.WriteLine(outcon);
|
||||||
WriteToLog(outlog);
|
WriteToLog(outlog);
|
||||||
|
|
||||||
|
History.Add(outlog);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WriteLine(string identifier, string message) => WriteLine($"[{identifier}] {message}");
|
public void WriteLine(string identifier, string message) => WriteLine($"[{identifier}] {message}");
|
||||||
@ -122,10 +124,7 @@
|
|||||||
private async void WriteToLog(string message)
|
private async void WriteToLog(string message)
|
||||||
{
|
{
|
||||||
if (!Initialized)
|
if (!Initialized)
|
||||||
{
|
|
||||||
Backlog.Add(message);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -29,12 +29,16 @@ namespace Bloxstrap.Models.SettingTasks.Base
|
|||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
App.PendingSettingTasks[Name] = this;
|
|
||||||
_newState = value;
|
_newState = value;
|
||||||
|
|
||||||
|
if (Changed)
|
||||||
|
App.PendingSettingTasks[Name] = this;
|
||||||
|
else
|
||||||
|
App.PendingSettingTasks.Remove(Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Changed => NewState != OriginalState;
|
public override bool Changed => _newState != OriginalState;
|
||||||
|
|
||||||
public BoolBaseTask(string prefix, string name) : base(prefix, name) { }
|
public BoolBaseTask(string prefix, string name) : base(prefix, name) { }
|
||||||
}
|
}
|
||||||
|
@ -23,12 +23,16 @@
|
|||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
App.PendingSettingTasks[Name] = this;
|
|
||||||
_newState = value;
|
_newState = value;
|
||||||
|
|
||||||
|
if (Changed)
|
||||||
|
App.PendingSettingTasks[Name] = this;
|
||||||
|
else
|
||||||
|
App.PendingSettingTasks.Remove(Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Changed => !NewState.Equals(OriginalState);
|
public override bool Changed => !_newState.Equals(OriginalState);
|
||||||
|
|
||||||
public IEnumerable<T> Selections { get; private set; }
|
public IEnumerable<T> Selections { get; private set; }
|
||||||
= Enum.GetValues(typeof(T)).Cast<T>().OrderBy(x =>
|
= Enum.GetValues(typeof(T)).Cast<T>().OrderBy(x =>
|
||||||
|
@ -29,12 +29,16 @@ namespace Bloxstrap.Models.SettingTasks.Base
|
|||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
App.PendingSettingTasks[Name] = this;
|
|
||||||
_newState = value;
|
_newState = value;
|
||||||
|
|
||||||
|
if (Changed)
|
||||||
|
App.PendingSettingTasks[Name] = this;
|
||||||
|
else
|
||||||
|
App.PendingSettingTasks.Remove(Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Changed => NewState != OriginalState;
|
public override bool Changed => _newState != OriginalState;
|
||||||
|
|
||||||
public StringBaseTask(string prefix, string name) : base(prefix, name) { }
|
public StringBaseTask(string prefix, string name) : base(prefix, name) { }
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,10 @@
|
|||||||
"Bloxstrap (Studio Launch)": {
|
"Bloxstrap (Studio Launch)": {
|
||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"commandLineArgs": "-studio"
|
"commandLineArgs": "-studio"
|
||||||
|
},
|
||||||
|
"Bloxstrap (Watcher)": {
|
||||||
|
"commandName": "Project",
|
||||||
|
"commandLineArgs": "-watcher"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
74
Bloxstrap/Resources/Strings.Designer.cs
generated
74
Bloxstrap/Resources/Strings.Designer.cs
generated
@ -60,6 +60,33 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Licenses.
|
||||||
|
/// </summary>
|
||||||
|
public static string About_Licenses_Title {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("About.Licenses.Title", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to About Bloxstrap.
|
||||||
|
/// </summary>
|
||||||
|
public static string About_Title {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("About.Title", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Translators.
|
||||||
|
/// </summary>
|
||||||
|
public static string About_Translators_Title {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("About.Translators.Title", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to left game.
|
/// Looks up a localized string similar to left game.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -422,15 +449,6 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Locate log file.
|
|
||||||
/// </summary>
|
|
||||||
public static string Common_LocateLogFile {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("Common.LocateLogFile", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Miscellaneous.
|
/// Looks up a localized string similar to Miscellaneous.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -494,6 +512,15 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Open log file.
|
||||||
|
/// </summary>
|
||||||
|
public static string Common_OpenLogFile {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Common.OpenLogFile", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Presets.
|
/// Looks up a localized string similar to Presets.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -602,15 +629,6 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Open log file.
|
|
||||||
/// </summary>
|
|
||||||
public static string ContextMenu_OpenLogFile {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("ContextMenu.OpenLogFile", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Roblox is still launching. A log file will only be available once Roblox launches..
|
/// Looks up a localized string similar to Roblox is still launching. A log file will only be available once Roblox launches..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1249,6 +1267,17 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The version of Bloxstrap you've launched is older than the version you currently have installed.
|
||||||
|
///Issues may occur and your settings may be altered. A reinstall is recommended.
|
||||||
|
///Are you sure you want to continue?.
|
||||||
|
/// </summary>
|
||||||
|
public static string InstallChecker_VersionLessThanInstalled {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InstallChecker.VersionLessThanInstalled", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Will drop you into the desktop app once everything's done.
|
/// Looks up a localized string similar to Will drop you into the desktop app once everything's done.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -2960,6 +2989,15 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to You have unsaved changes. Are you sure you want to close without saving?.
|
||||||
|
/// </summary>
|
||||||
|
public static string Menu_UnsavedChanges {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Menu.UnsavedChanges", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to They'll be kept where Bloxstrap was installed, and will automatically be restored on a reinstall..
|
/// Looks up a localized string similar to They'll be kept where Bloxstrap was installed, and will automatically be restored on a reinstall..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -226,8 +226,8 @@ Your ReShade configuration files will still be saved, and you can locate them by
|
|||||||
<data name="Common.ImportJson" xml:space="preserve">
|
<data name="Common.ImportJson" xml:space="preserve">
|
||||||
<value>Import JSON</value>
|
<value>Import JSON</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Common.LocateLogFile" xml:space="preserve">
|
<data name="Common.OpenLogFile" xml:space="preserve">
|
||||||
<value>Locate log file</value>
|
<value>Open log file</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Common.Miscellaneous" xml:space="preserve">
|
<data name="Common.Miscellaneous" xml:space="preserve">
|
||||||
<value>Miscellaneous</value>
|
<value>Miscellaneous</value>
|
||||||
@ -268,9 +268,6 @@ Your ReShade configuration files will still be saved, and you can locate them by
|
|||||||
<data name="ContextMenu.CopyDeeplinkInvite" xml:space="preserve">
|
<data name="ContextMenu.CopyDeeplinkInvite" xml:space="preserve">
|
||||||
<value>Copy invite deeplink</value>
|
<value>Copy invite deeplink</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ContextMenu.OpenLogFile" xml:space="preserve">
|
|
||||||
<value>Open log file</value>
|
|
||||||
</data>
|
|
||||||
<data name="ContextMenu.SeeServerDetails" xml:space="preserve">
|
<data name="ContextMenu.SeeServerDetails" xml:space="preserve">
|
||||||
<value>See server details</value>
|
<value>See server details</value>
|
||||||
</data>
|
</data>
|
||||||
@ -1136,4 +1133,21 @@ If not, then please report this exception to the maintainers of this fork. Do NO
|
|||||||
<data name="Dialog.AlreadyRunning.Uninstaller" xml:space="preserve">
|
<data name="Dialog.AlreadyRunning.Uninstaller" xml:space="preserve">
|
||||||
<value>Please wait for uninstallation to finish.</value>
|
<value>Please wait for uninstallation to finish.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="About.Title" xml:space="preserve">
|
||||||
|
<value>About Bloxstrap</value>
|
||||||
|
</data>
|
||||||
|
<data name="About.Licenses.Title" xml:space="preserve">
|
||||||
|
<value>Licenses</value>
|
||||||
|
</data>
|
||||||
|
<data name="About.Translators.Title" xml:space="preserve">
|
||||||
|
<value>Translators</value>
|
||||||
|
</data>
|
||||||
|
<data name="Menu.UnsavedChanges" xml:space="preserve">
|
||||||
|
<value>You have unsaved changes. Are you sure you want to close without saving?</value>
|
||||||
|
</data>
|
||||||
|
<data name="InstallChecker.VersionLessThanInstalled" xml:space="preserve">
|
||||||
|
<value>The version of Bloxstrap you've launched is older than the version you currently have installed.
|
||||||
|
Issues may occur and your settings may be altered. A reinstall is recommended.
|
||||||
|
Are you sure you want to continue?</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
{
|
{
|
||||||
public const string DefaultChannel = "production";
|
public const string DefaultChannel = "production";
|
||||||
|
|
||||||
|
private const string VersionStudioHash = "version-012732894899482c";
|
||||||
|
|
||||||
public static string BaseUrl { get; private set; } = null!;
|
public static string BaseUrl { get; private set; } = null!;
|
||||||
|
|
||||||
private static readonly Dictionary<string, ClientVersion> ClientVersionCache = new();
|
private static readonly Dictionary<string, ClientVersion> ClientVersionCache = new();
|
||||||
@ -18,23 +20,31 @@
|
|||||||
{ "https://s3.amazonaws.com/setup.roblox.com", 4 }
|
{ "https://s3.amazonaws.com/setup.roblox.com", 4 }
|
||||||
};
|
};
|
||||||
|
|
||||||
private static async Task<string?> TestConnection(string url, int priority)
|
private static async Task<string?> TestConnection(string url, int priority, CancellationToken token)
|
||||||
{
|
{
|
||||||
string LOG_IDENT = $"RobloxDeployment::TestConnection.{url}";
|
string LOG_IDENT = $"RobloxDeployment::TestConnection.{url}";
|
||||||
|
|
||||||
await Task.Delay(priority * 1000);
|
await Task.Delay(priority * 1000, token);
|
||||||
|
|
||||||
if (BaseUrl is not null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Connecting...");
|
App.Logger.WriteLine(LOG_IDENT, "Connecting...");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = await App.HttpClient.GetAsync($"{url}/version");
|
var response = await App.HttpClient.GetAsync($"{url}/versionStudio", token);
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
if (!response.IsSuccessStatusCode)
|
||||||
throw new HttpResponseException(response);
|
throw new HttpResponseException(response);
|
||||||
|
|
||||||
|
// versionStudio is the version hash for the last MFC studio to be deployed.
|
||||||
|
// the response body should always be "version-012732894899482c".
|
||||||
|
string content = await response.Content.ReadAsStringAsync(token);
|
||||||
|
if (content != VersionStudioHash)
|
||||||
|
throw new Exception($"versionStudio response does not match (expected \"{VersionStudioHash}\", got \"{content}\")");
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Connectivity test cancelled.");
|
||||||
|
throw;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -56,11 +66,11 @@
|
|||||||
|
|
||||||
// returns null for success
|
// returns null for success
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(BaseUrl))
|
CancellationTokenSource tokenSource = new CancellationTokenSource();
|
||||||
return null;
|
CancellationToken token = tokenSource.Token;
|
||||||
|
|
||||||
var exceptions = new List<Exception>();
|
var exceptions = new List<Exception>();
|
||||||
var tasks = (from entry in BaseUrls select TestConnection(entry.Key, entry.Value)).ToList();
|
var tasks = (from entry in BaseUrls select TestConnection(entry.Key, entry.Value, token)).ToList();
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Testing connectivity...");
|
App.Logger.WriteLine(LOG_IDENT, "Testing connectivity...");
|
||||||
|
|
||||||
@ -79,6 +89,9 @@
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// stop other running connectivity tests
|
||||||
|
tokenSource.Cancel();
|
||||||
|
|
||||||
if (String.IsNullOrEmpty(BaseUrl))
|
if (String.IsNullOrEmpty(BaseUrl))
|
||||||
return exceptions[0];
|
return exceptions[0];
|
||||||
|
|
||||||
|
48
Bloxstrap/UI/Elements/About/MainWindow.xaml
Normal file
48
Bloxstrap/UI/Elements/About/MainWindow.xaml
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<base:WpfUiWindow x:Class="Bloxstrap.UI.Elements.About.MainWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:pages="clr-namespace:Bloxstrap.UI.Elements.About.Pages"
|
||||||
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||||
|
xmlns:base="clr-namespace:Bloxstrap.UI.Elements.Base"
|
||||||
|
xmlns:resources="clr-namespace:Bloxstrap.Resources"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="{x:Static resources:Strings.About_Title}"
|
||||||
|
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
|
||||||
|
MinWidth="740"
|
||||||
|
Width="740"
|
||||||
|
Height="440"
|
||||||
|
ExtendsContentIntoTitleBar="True"
|
||||||
|
WindowBackdropType="Mica"
|
||||||
|
WindowStartupLocation="CenterScreen">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<ui:TitleBar Padding="8" x:Name="RootTitleBar" Grid.Row="0" ForceShutdown="False" MinimizeToTray="False" UseSnapLayout="True" Title="{x:Static resources:Strings.About_Title}" Icon="pack://application:,,,/Bloxstrap.ico" />
|
||||||
|
|
||||||
|
<Grid x:Name="RootGrid" Grid.Row="1" Margin="12,12,0,0" Visibility="Visible">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<ui:NavigationStore x:Name="RootNavigation" Grid.Row="1" Grid.Column="0" Margin="0,0,12,0" Frame="{Binding ElementName=RootFrame}" SelectedPageIndex="0">
|
||||||
|
<ui:NavigationStore.Items>
|
||||||
|
<ui:NavigationItem Content="{x:Static resources:Strings.Menu_About_Title}" PageType="{x:Type pages:AboutPage}" Icon="QuestionCircle48" Tag="about" Margin="0,0,0,12" />
|
||||||
|
<ui:NavigationItem Content="{x:Static resources:Strings.About_Translators_Title}" PageType="{x:Type pages:TranslatorsPage}" Icon="Translate24" Tag="translators" Margin="0,0,0,12" />
|
||||||
|
<ui:NavigationItem Content="{x:Static resources:Strings.About_Licenses_Title}" PageType="{x:Type pages:LicensesPage}" Icon="Code24" Tag="licenses" Margin="0,0,0,12" />
|
||||||
|
</ui:NavigationStore.Items>
|
||||||
|
</ui:NavigationStore>
|
||||||
|
|
||||||
|
<Frame x:Name="RootFrame" Grid.Row="0" Grid.RowSpan="2" Grid.Column="1" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</base:WpfUiWindow>
|
35
Bloxstrap/UI/Elements/About/MainWindow.xaml.cs
Normal file
35
Bloxstrap/UI/Elements/About/MainWindow.xaml.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
using Wpf.Ui.Controls.Interfaces;
|
||||||
|
using Wpf.Ui.Mvvm.Contracts;
|
||||||
|
|
||||||
|
namespace Bloxstrap.UI.Elements.About
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for MainWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class MainWindow : INavigationWindow
|
||||||
|
{
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
App.Logger.WriteLine("MainWindow::MainWindow", "Initializing menu");
|
||||||
|
}
|
||||||
|
|
||||||
|
#region INavigationWindow methods
|
||||||
|
|
||||||
|
public Frame GetFrame() => RootFrame;
|
||||||
|
|
||||||
|
public INavigation GetNavigation() => RootNavigation;
|
||||||
|
|
||||||
|
public bool Navigate(Type pageType) => RootNavigation.Navigate(pageType);
|
||||||
|
|
||||||
|
public void SetPageService(IPageService pageService) => RootNavigation.PageService = pageService;
|
||||||
|
|
||||||
|
public void ShowWindow() => Show();
|
||||||
|
|
||||||
|
public void CloseWindow() => Close();
|
||||||
|
|
||||||
|
#endregion INavigationWindow methods
|
||||||
|
}
|
||||||
|
}
|
134
Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml
Normal file
134
Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
<ui:UiPage x:Class="Bloxstrap.UI.Elements.About.Pages.AboutPage"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:models="clr-namespace:Bloxstrap.UI.ViewModels"
|
||||||
|
xmlns:controls="clr-namespace:Bloxstrap.UI.Elements.Controls"
|
||||||
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||||
|
xmlns:resources="clr-namespace:Bloxstrap.Resources"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="1500" d:DesignWidth="800"
|
||||||
|
Title="AboutPage"
|
||||||
|
Scrollable="True">
|
||||||
|
<StackPanel Margin="0,0,14,14">
|
||||||
|
<Grid Margin="0,0,0,24" HorizontalAlignment="Center">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Image Grid.Column="0" Width="72" Height="72" VerticalAlignment="Center" Source="pack://application:,,,/Bloxstrap.ico" RenderOptions.BitmapScalingMode="HighQuality" />
|
||||||
|
<StackPanel Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Grid.Column="0" Text="Bloxstrap" Margin="0,0,4,0" FontSize="24" FontWeight="Medium" />
|
||||||
|
<TextBlock Grid.Column="1" Text="{Binding Version, Mode=OneTime}" Margin="4,0,0,2" VerticalAlignment="Bottom" FontSize="16" FontWeight="Medium" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</Grid>
|
||||||
|
<TextBlock Text="{x:Static resources:Strings.Menu_About_Description}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<WrapPanel HorizontalAlignment="Center" Orientation="Horizontal">
|
||||||
|
<ui:Anchor Margin="0,0,8,8" Content="{x:Static resources:Strings.Menu_About_GithubRepository}" Icon="Code24" NavigateUri="https://github.com/pizzaboxer/bloxstrap" />
|
||||||
|
<ui:Anchor Margin="0,0,8,8" Content="{x:Static resources:Strings.Menu_About_HelpInformation}" Icon="BookQuestionMark24" NavigateUri="https://github.com/pizzaboxer/bloxstrap/wiki" />
|
||||||
|
<ui:Anchor Margin="0,0,8,8" Content="{x:Static resources:Strings.Menu_About_ReportIssue}" Icon="BookExclamationMark24" NavigateUri="https://github.com/pizzaboxer/bloxstrap/issues" />
|
||||||
|
<ui:Anchor Margin="0,0,0,8" Content="{x:Static resources:Strings.Menu_About_DiscordServer}" Icon="Chat48" NavigateUri="https://discord.gg/nKjV3mGq6R" />
|
||||||
|
</WrapPanel>
|
||||||
|
|
||||||
|
<StackPanel Visibility="{Binding BuildInformationVisibility, Mode=OneTime}">
|
||||||
|
<TextBlock Text="Build Information" FontWeight="Medium" FontSize="20" Margin="0,16,0,0" />
|
||||||
|
<TextBlock Text="hmmmm" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
|
||||||
|
<Grid Column="0" Margin="0,8,0,0">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,4,16,4" FontSize="14" FontWeight="Medium" Text="Timestamp" />
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="1" Margin="0,0,0,4" VerticalAlignment="Bottom" Text="{Binding BuildTimestamp, Mode=OneTime}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,4,16,4" FontSize="14" FontWeight="Medium" Text="Machine" />
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="1" Margin="0,0,0,4" VerticalAlignment="Bottom" Text="{Binding BuildMetadata.Machine, Mode=OneTime}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,4,16,4" FontSize="14" FontWeight="Medium" Text="Commit Hash" Visibility="{Binding BuildCommitVisibility, Mode=OneTime}" />
|
||||||
|
<TextBlock Grid.Row="2" Grid.Column="1" Margin="0,0,0,4" VerticalAlignment="Bottom" Foreground="{DynamicResource TextFillColorTertiaryBrush}" Visibility="{Binding BuildCommitVisibility, Mode=OneTime}">
|
||||||
|
<Hyperlink Foreground="{DynamicResource TextFillColorTertiaryBrush}" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="{Binding BuildCommitHashUrl, Mode=OneTime}">
|
||||||
|
<TextBlock Text="{Binding BuildMetadata.CommitHash, Mode=OneTime}" />
|
||||||
|
</Hyperlink>
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="3" Grid.Column="0" Margin="0,4,16,4" FontSize="14" FontWeight="Medium" Text="Commit Ref" Visibility="{Binding BuildCommitVisibility, Mode=OneTime}" />
|
||||||
|
<TextBlock Grid.Row="3" Grid.Column="1" Margin="0,0,0,4" VerticalAlignment="Bottom" Text="{Binding BuildMetadata.CommitRef, Mode=OneTime}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" Visibility="{Binding BuildCommitVisibility, Mode=OneTime}" />
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock Text="{x:Static resources:Strings.Menu_About_Contributors}" FontWeight="Medium" FontSize="20" Margin="0,16,0,0" />
|
||||||
|
<TextBlock Text="{x:Static resources:Strings.Menu_About_Contributors_Description}" TextWrapping="Wrap" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
<Grid Margin="0,8,0,0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<controls:Expander Grid.Column="0" Margin="0,0,4,0" HeaderIcon="Code24" HeaderText="{x:Static resources:Strings.Menu_About_Contributors_Code}" IsExpanded="True">
|
||||||
|
<StackPanel>
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[Matt](https://github.com/bluepilledgreat)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[1011025m](https://github.com/1011025m)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[EasternBloxxer](https://github.com/EasternBloxxer)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[sitiom](https://github.com/sitiom)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[Extravi](https://github.com/Extravi)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[EpixScripts](https://github.com/EpixScripts)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[swatTurret](https://github.com/swatTurret)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[fxeP1](https://github.com/fxeP1)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[Redusofficial](https://github.com/Redusofficial)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[srthMD](https://github.com/srthMD)" />
|
||||||
|
</StackPanel>
|
||||||
|
</controls:Expander>
|
||||||
|
|
||||||
|
<controls:Expander Grid.Column="1" Margin="4,0,4,0" HeaderIcon="AppsAddIn28" HeaderText="{x:Static resources:Strings.Menu_About_Contributors_FeatureIdeas}" IsExpanded="True">
|
||||||
|
<StackPanel>
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[he3als](https://github.com/he3als)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[NikSavchenk0](https://github.com/NikSavchenk0)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[carter0nline](https://github.com/carter0nline)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[lolmanurfunny](https://github.com/lolmanurfunny)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[MehKako](https://github.com/MehKako)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[EpixScripts](https://github.com/EpixScripts)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[knivesofeylis](https://github.com/knivesofeylis)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[sha4owz](https://github.com/sha4owz)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[DaMlgNoodle](https://github.com/DaMlgNoodle)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[nakoyasha](https://github.com/nakoyasha)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[exurd](https://github.com/exurd)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[0xFE0F](https://github.com/0xFE0F)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[Tezos](https://github.com/GoingCrazyDude)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[CfwSky](https://www.roblox.com/users/129425241/profile)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[ruubloo](https://www.roblox.com/users/158082266/profile)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[toyoda165](https://www.roblox.com/users/923416649/profile)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[ShadowCodeX](https://github.com/ShadowCodeX-debug)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[cub-has-injected](https://github.com/cub-has-injected)" />
|
||||||
|
</StackPanel>
|
||||||
|
</controls:Expander>
|
||||||
|
|
||||||
|
<controls:Expander Grid.Column="2" Margin="4,0,0,0" HeaderIcon="Heart16" HeaderText="{x:Static resources:Strings.Menu_About_Contributors_SpecialThanks}" IsExpanded="True">
|
||||||
|
<StackPanel>
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[MaximumADHD](https://github.com/MaximumADHD)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[Multako](https://www.roblox.com/users/2485612194/profile)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[axstin](https://github.com/axstin)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[taskmanager](https://github.com/Mantaraix)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[apprehensions](https://github.com/apprehensions)" />
|
||||||
|
</StackPanel>
|
||||||
|
</controls:Expander>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</ui:UiPage>
|
@ -1,6 +1,6 @@
|
|||||||
using Bloxstrap.UI.ViewModels.Settings;
|
using Bloxstrap.UI.ViewModels.Settings;
|
||||||
|
|
||||||
namespace Bloxstrap.UI.Elements.Settings.Pages
|
namespace Bloxstrap.UI.Elements.About.Pages
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for AboutPage.xaml
|
/// Interaction logic for AboutPage.xaml
|
72
Bloxstrap/UI/Elements/About/Pages/LicensesPage.xaml
Normal file
72
Bloxstrap/UI/Elements/About/Pages/LicensesPage.xaml
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<ui:UiPage x:Class="Bloxstrap.UI.Elements.About.Pages.LicensesPage"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:models="clr-namespace:Bloxstrap.UI.ViewModels"
|
||||||
|
xmlns:controls="clr-namespace:Bloxstrap.UI.Elements.Controls"
|
||||||
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||||
|
xmlns:resources="clr-namespace:Bloxstrap.Resources"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="1500" d:DesignWidth="800"
|
||||||
|
Title="AboutPage"
|
||||||
|
Scrollable="True">
|
||||||
|
<StackPanel Margin="0,0,14,14">
|
||||||
|
<TextBlock Text="{x:Static resources:Strings.Menu_About_Licenses}" FontWeight="Medium" FontSize="24" Margin="0,0,0,16" />
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<ui:CardAction Grid.Row="0" Grid.Column="0" Margin="0,8,8,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/blob/main/LICENSE">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock FontSize="14" Text="Bloxstrap" />
|
||||||
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:CardAction>
|
||||||
|
<ui:CardAction Grid.Row="0" Grid.Column="1" Margin="0,8,8,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/lepoco/wpfui/blob/main/LICENSE">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock FontSize="14" Text="WPF-UI" />
|
||||||
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:CardAction>
|
||||||
|
<ui:CardAction Grid.Row="0" Grid.Column="2" Margin="0,8,0,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/securifybv/ShellLink/blob/master/LICENSE.txt">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock FontSize="14" Text="ShellLink" />
|
||||||
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:CardAction>
|
||||||
|
<ui:CardAction Grid.Row="1" Grid.Column="0" Margin="0,8,8,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/Lachee/discord-rpc-csharp/blob/master/LICENSE">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock FontSize="14" Text="DiscordRPC" />
|
||||||
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:CardAction>
|
||||||
|
<ui:CardAction Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,8,0,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/MaximumADHD/Roblox-Studio-Mod-Manager/blob/main/LICENSE">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock FontSize="13" Text="Roblox Studio Mod Manager" />
|
||||||
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:CardAction>
|
||||||
|
<ui:CardAction Grid.Row="2" Grid.Column="0" Margin="0,8,8,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/icsharpcode/SharpZipLib/blob/master/LICENSE.txt">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock FontSize="13" Text="SharpZipLib" />
|
||||||
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:CardAction>
|
||||||
|
<ui:CardAction Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,8,0,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/xoofx/markdig/blob/master/license.txt">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock FontSize="14" Text="Markdig" />
|
||||||
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_BSD2}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:CardAction>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</ui:UiPage>
|
13
Bloxstrap/UI/Elements/About/Pages/LicensesPage.xaml.cs
Normal file
13
Bloxstrap/UI/Elements/About/Pages/LicensesPage.xaml.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Bloxstrap.UI.Elements.About.Pages
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for LicensesPage.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class LicensesPage
|
||||||
|
{
|
||||||
|
public LicensesPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
484
Bloxstrap/UI/Elements/About/Pages/TranslatorsPage.xaml
Normal file
484
Bloxstrap/UI/Elements/About/Pages/TranslatorsPage.xaml
Normal file
@ -0,0 +1,484 @@
|
|||||||
|
<ui:UiPage x:Class="Bloxstrap.UI.Elements.About.Pages.TranslatorsPage"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:models="clr-namespace:Bloxstrap.UI.ViewModels"
|
||||||
|
xmlns:controls="clr-namespace:Bloxstrap.UI.Elements.Controls"
|
||||||
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||||
|
xmlns:resources="clr-namespace:Bloxstrap.Resources"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="1500" d:DesignWidth="800"
|
||||||
|
Title="AboutPage"
|
||||||
|
Scrollable="True">
|
||||||
|
<StackPanel Margin="0,0,14,14">
|
||||||
|
<TextBlock Text="{x:Static resources:Strings.About_Translators_Title}" FontWeight="Medium" FontSize="24" Margin="0,0,0,16" />
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="0">
|
||||||
|
<TextBlock Text="Bahasa Indonesia" FontSize="16" FontWeight="Medium">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="e7leopard" />
|
||||||
|
<TextBlock Text="hfzrk" />
|
||||||
|
<TextBlock Text="soudblox" />
|
||||||
|
|
||||||
|
<TextBlock Text="Bokmål" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="darkevilmage" />
|
||||||
|
<TextBlock Text="endsouls" />
|
||||||
|
<TextBlock Text="letoek" />
|
||||||
|
|
||||||
|
<!--<TextBlock Text="Čeština" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="Chusaak" />
|
||||||
|
<TextBlock Text="DanyCraftCZ" />
|
||||||
|
<TextBlock Text="Franklin_Surten" />
|
||||||
|
<TextBlock Text="Galaxy_Gangster6" />
|
||||||
|
<TextBlock Text="jasperholo" />
|
||||||
|
<TextBlock Text="letoek" />
|
||||||
|
<TextBlock Text="noobkid4545" />
|
||||||
|
<TextBlock Text="radim776" />-->
|
||||||
|
|
||||||
|
<!-- <TextBlock Text="Dansk" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="Momslayer98" />
|
||||||
|
<TextBlock Text="SirBlue" /> -->
|
||||||
|
|
||||||
|
<TextBlock Text="Deutsch" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="agent_phoenix" />
|
||||||
|
<TextBlock Text="avoidr" />
|
||||||
|
<TextBlock Text="hcjohnsgd" />
|
||||||
|
<TextBlock Text="hxmbt" />
|
||||||
|
<TextBlock Text="kale123" />
|
||||||
|
<TextBlock Text="Marvin_Chu" />
|
||||||
|
<TextBlock Text="nzxt_xll" />
|
||||||
|
<TextBlock Text="Nlx095" />
|
||||||
|
<TextBlock Text="Ph1lwtf" />
|
||||||
|
<TextBlock Text="sxckqerz" />
|
||||||
|
<TextBlock Text="TEAM_LILA" />
|
||||||
|
<TextBlock Text="xDevoidx" />
|
||||||
|
|
||||||
|
<TextBlock Text="Español" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="4Xisty" />
|
||||||
|
<TextBlock Text="Botkid" />
|
||||||
|
<TextBlock Text="colocky" />
|
||||||
|
<TextBlock Text="D0N-B0T" />
|
||||||
|
<TextBlock Text="Dasp" />
|
||||||
|
<TextBlock Text="devyyxn" />
|
||||||
|
<TextBlock Text="ItzzExcel" />
|
||||||
|
<TextBlock Text="Ilayhlinda" />
|
||||||
|
<TextBlock Text="Ilushiouss" />
|
||||||
|
<TextBlock Text="jayces." />
|
||||||
|
<TextBlock Text="kroesufos" />
|
||||||
|
<TextBlock Text="LaiyLiod" />
|
||||||
|
<TextBlock Text="lyalekin" />
|
||||||
|
<TextBlock Text="NezumiDS" />
|
||||||
|
<TextBlock Text="NimuruDP" />
|
||||||
|
<TextBlock Text="NescafeCL" />
|
||||||
|
<TextBlock Text="Sw7gger" />
|
||||||
|
<TextBlock Text="sxckqerz" />
|
||||||
|
<TextBlock Text="Urzy" />
|
||||||
|
|
||||||
|
<TextBlock Text="Filipino" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="alphjectiom" />
|
||||||
|
<TextBlock Text="FlaminDaPotato" />
|
||||||
|
<TextBlock Text="RobiTheRobloxxer" />
|
||||||
|
<TextBlock Text="shadow01148" />
|
||||||
|
|
||||||
|
<TextBlock Text="Français" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="At0zDx" />
|
||||||
|
<TextBlock Text="built4aiming" />
|
||||||
|
<TextBlock Text="hahaloserz360" />
|
||||||
|
<TextBlock Text="K0ga" />
|
||||||
|
<TextBlock Text="Marcssebaa" />
|
||||||
|
<TextBlock Text="MommySernox" />
|
||||||
|
<TextBlock Text="owentempest8" />
|
||||||
|
<TextBlock Text="Subsical" />
|
||||||
|
<TextBlock Text="thatsirwaffles" />
|
||||||
|
<TextBlock Text="tyundrai" />
|
||||||
|
<TextBlock Text="Waza80" />
|
||||||
|
|
||||||
|
<TextBlock Text="Hindi (Latin)" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="kunaljainop" />
|
||||||
|
<TextBlock Text="marathedonroblox" />
|
||||||
|
<TextBlock Text="Sur_" />
|
||||||
|
<TextBlock Text="Tezos" />
|
||||||
|
<TextBlock Text="TheTakuo" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="1">
|
||||||
|
<TextBlock Text="Hrvatski" FontSize="16" FontWeight="Medium">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="Dzigos" />
|
||||||
|
<TextBlock Text="Koyroii" />
|
||||||
|
<TextBlock Text="Nemznja" />
|
||||||
|
|
||||||
|
<TextBlock Text="Italiano" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="crow_zxcr" />
|
||||||
|
<TextBlock Text="devyyxn" />
|
||||||
|
<TextBlock Text="domenicoiacono" />
|
||||||
|
<TextBlock Text="hulabulaseop" />
|
||||||
|
<TextBlock Text="lord_moth" />
|
||||||
|
<TextBlock Text="loridori" />
|
||||||
|
<TextBlock Text="Lupo01" />
|
||||||
|
<TextBlock Text="Mogunars" />
|
||||||
|
<TextBlock Text="pave08" />
|
||||||
|
<TextBlock Text="spectrumbruh" />
|
||||||
|
|
||||||
|
<TextBlock Text="Lietuvių" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="cr0000142" />
|
||||||
|
<TextBlock Text="Duexo" />
|
||||||
|
<TextBlock Text="jessethedev" />
|
||||||
|
<TextBlock Text="Vac31." />
|
||||||
|
|
||||||
|
<TextBlock Text="Magyar" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="DynoPlays" />
|
||||||
|
<TextBlock Text="Elotomka" />
|
||||||
|
<TextBlock Text="xM4rk1" />
|
||||||
|
|
||||||
|
<!--<TextBlock Text="Nederlands" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="Cosmix" />
|
||||||
|
<TextBlock Text="Miwwzy" />
|
||||||
|
<TextBlock Text="Quickvision1" />
|
||||||
|
<TextBlock Text="ydboss" />-->
|
||||||
|
|
||||||
|
<TextBlock Text="Polski" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="Eztaru" />
|
||||||
|
<TextBlock Text="lunar" />
|
||||||
|
<TextBlock Text="markontm" />
|
||||||
|
<TextBlock Text="my5q" />
|
||||||
|
<TextBlock Text="nemzik2137" />
|
||||||
|
<TextBlock Text="plexar" />
|
||||||
|
<TextBlock Text="r.efil" />
|
||||||
|
|
||||||
|
<TextBlock Text="Português (Brasil)" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="anormalevis" />
|
||||||
|
<TextBlock Text="ErisvaldoBalbino" />
|
||||||
|
<TextBlock Text="G3xneric" />
|
||||||
|
<TextBlock Text="hnter" />
|
||||||
|
<TextBlock Text="issei_" />
|
||||||
|
<TextBlock Text="iyto.lk" />
|
||||||
|
<TextBlock Text="jhermesn" />
|
||||||
|
<TextBlock Text="JorgeDaPelada" />
|
||||||
|
<TextBlock Text="LwgoDev" />
|
||||||
|
<TextBlock Text="nunk7" />
|
||||||
|
<TextBlock Text="peke7374" />
|
||||||
|
<TextBlock Text="SeeF" />
|
||||||
|
<TextBlock Text="Snowzin1" />
|
||||||
|
<TextBlock Text="storm930" />
|
||||||
|
<TextBlock Text="toofastforboo" />
|
||||||
|
<TextBlock Text="VMOICE" />
|
||||||
|
<TextBlock Text="Ye4" />
|
||||||
|
<TextBlock Text="ZaPeZaPe" />
|
||||||
|
|
||||||
|
<TextBlock Text="Română" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="Externalkinetics" />
|
||||||
|
<TextBlock Text="MonochromeAlex" />
|
||||||
|
<TextBlock Text="PlayerValley" />
|
||||||
|
<TextBlock Text="Smuki" />
|
||||||
|
<TextBlock Text="theflopperguy" />
|
||||||
|
|
||||||
|
<TextBlock Text="Suomi" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="gelaxiz" />
|
||||||
|
<TextBlock Text="jes5" />
|
||||||
|
<TextBlock Text="retromaxwell" />
|
||||||
|
<TextBlock Text="SomePinglord" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="2">
|
||||||
|
<TextBlock Text="Svenska" FontSize="16" FontWeight="Medium">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="Axellse" />
|
||||||
|
<TextBlock Text="CroppingFlea479" />
|
||||||
|
<TextBlock Text="FishySpelar" />
|
||||||
|
<TextBlock Text="PineappleSnackz" />
|
||||||
|
<TextBlock Text="simonixen" />
|
||||||
|
<TextBlock Text="thatgurkangurk" />
|
||||||
|
|
||||||
|
<TextBlock Text="Tiếng Việt" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="alexking2068" />
|
||||||
|
<TextBlock Text="baterblx" />
|
||||||
|
<TextBlock Text="Elytronn" />
|
||||||
|
<TextBlock Text="fox810891" />
|
||||||
|
<TextBlock Text="ItsPoofy" />
|
||||||
|
<TextBlock Text="Limer1" />
|
||||||
|
<TextBlock Text="makayu203332" />
|
||||||
|
<TextBlock Text="MEx2/j7x6" />
|
||||||
|
<TextBlock Text="NguyenDat208" />
|
||||||
|
<TextBlock Text="quanmequankk" />
|
||||||
|
<TextBlock Text="SomeRandomGuy175" />
|
||||||
|
<TextBlock Text="SonThanhVN" />
|
||||||
|
<TextBlock Text="teaanguyenn" />
|
||||||
|
<TextBlock Text="Veiiorra" />
|
||||||
|
|
||||||
|
<TextBlock Text="Türkçe" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="canny19133" />
|
||||||
|
<TextBlock Text="cfors55" />
|
||||||
|
<TextBlock Text="drakfreddy" />
|
||||||
|
<TextBlock Text="enisify" />
|
||||||
|
<TextBlock Text="jayces." />
|
||||||
|
<TextBlock Text="nyatie" />
|
||||||
|
<TextBlock Text="PixelArmy" />
|
||||||
|
<TextBlock Text="plants8332" />
|
||||||
|
<TextBlock Text="r02" />
|
||||||
|
<TextBlock Text="siyamicik" />
|
||||||
|
<TextBlock Text="ydboss" />
|
||||||
|
|
||||||
|
<TextBlock Text="Українська" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="9zh" />
|
||||||
|
<TextBlock Text="andrey3569s" />
|
||||||
|
<TextBlock Text="DexterBloxxer" />
|
||||||
|
<TextBlock Text="Externalkinetics" />
|
||||||
|
<TextBlock Text="maksimvlad7" />
|
||||||
|
|
||||||
|
<TextBlock Text="Босански" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="Cortex_1" />
|
||||||
|
<TextBlock Text="Nemznja" />
|
||||||
|
<TextBlock Text="Ren" />
|
||||||
|
|
||||||
|
<TextBlock Text="Български" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="GrafitNiki" />
|
||||||
|
<TextBlock Text="sidefrappe" />
|
||||||
|
|
||||||
|
<TextBlock Text="Русский" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="3tcy" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
||||||
|
<TextBlock Text="andBroz" />
|
||||||
|
<TextBlock Text="alexneonwithglue" />
|
||||||
|
<TextBlock Text="AnonymousDudeLOL123" />
|
||||||
|
<TextBlock Text="aperna_of_the_ticks" />
|
||||||
|
<TextBlock Text="arsenijveselov77" />
|
||||||
|
<TextBlock Text="Art3mLapa" />
|
||||||
|
<TextBlock Text="cherkash" />
|
||||||
|
<TextBlock Text="cub-has-injected" />
|
||||||
|
<TextBlock Text="dallyuser" />
|
||||||
|
<TextBlock Text="Dr1mG" />
|
||||||
|
<TextBlock Text="Externalkinetics" />
|
||||||
|
<TextBlock Text="fxstyxx" />
|
||||||
|
<TextBlock Text="Gustodd4202" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
||||||
|
<TextBlock Text="harababura" />
|
||||||
|
<TextBlock Text="ImperialRhyme" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
||||||
|
<TextBlock Text="IStoleYourCheese" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
||||||
|
<TextBlock Text="khat7" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
||||||
|
<TextBlock Text="kostyan" />
|
||||||
|
<TextBlock Text="Maks" />
|
||||||
|
<TextBlock Text="niktoyou" />
|
||||||
|
<TextBlock Text="nurgament2" />
|
||||||
|
<TextBlock Text="poflexim" />
|
||||||
|
<TextBlock Text="Prob1rka" />
|
||||||
|
<TextBlock Text="Provo" />
|
||||||
|
<TextBlock Text="Quenevelly" />
|
||||||
|
<TextBlock Text="sally13249" />
|
||||||
|
<TextBlock Text="simmon8800" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
||||||
|
<TextBlock Text="Skylan031" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
||||||
|
<TextBlock Text="Spuffio" />
|
||||||
|
<TextBlock Text="StraiF" />
|
||||||
|
<TextBlock Text="StrayCatSimb" />
|
||||||
|
<TextBlock Text="Voxel" />
|
||||||
|
<TextBlock Text="XonaShera" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
||||||
|
<TextBlock Text="Ziio123" />
|
||||||
|
<TextBlock Text="zor9na90000" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="3">
|
||||||
|
<TextBlock Text="עברית" FontSize="16" FontWeight="Medium">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="1cur1" />
|
||||||
|
<TextBlock Text="ilan0098" />
|
||||||
|
<TextBlock Text="koerga" />
|
||||||
|
<TextBlock Text="Sezei" />
|
||||||
|
|
||||||
|
<TextBlock Text="العربية" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="busguesjshbahsj" />
|
||||||
|
<TextBlock Text="cq2i" />
|
||||||
|
<TextBlock Text="mmiky" />
|
||||||
|
<TextBlock Text="mostafagamingx1" />
|
||||||
|
<TextBlock Text="RoRed" />
|
||||||
|
<TextBlock Text="Sakupen" />
|
||||||
|
<TextBlock Text="streoic" />
|
||||||
|
<TextBlock Text="uvq18" />
|
||||||
|
<TextBlock Text="wyfast" />
|
||||||
|
<TextBlock Text="Zida" />
|
||||||
|
|
||||||
|
<TextBlock Text="বাংলা" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="Arnian" />
|
||||||
|
<TextBlock Text="Hydrated_panda" />
|
||||||
|
<TextBlock Text="marathedonroblox" />
|
||||||
|
<TextBlock Text="red_hi" />
|
||||||
|
|
||||||
|
<TextBlock Text="ภาษาไทย" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="._bonus_." />
|
||||||
|
<TextBlock Text="marc15772" />
|
||||||
|
<TextBlock Text="arthurwagon" />
|
||||||
|
<TextBlock Text="Sem1z" />
|
||||||
|
<TextBlock Text="xAom" />
|
||||||
|
|
||||||
|
<TextBlock Text="한국어" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="ADVI50R" />
|
||||||
|
<TextBlock Text="asd123456fghqwerty" />
|
||||||
|
<TextBlock Text="bacon1295" />
|
||||||
|
<TextBlock Text="NightPlay" />
|
||||||
|
|
||||||
|
<TextBlock Text="中文 (简体)" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="14TQD" />
|
||||||
|
<TextBlock Text="Aling00" />
|
||||||
|
<TextBlock Text="Clock" />
|
||||||
|
<TextBlock Text="ERSN_CERROR" />
|
||||||
|
<TextBlock Text="Kirxvil" />
|
||||||
|
<TextBlock Text="Typel" />
|
||||||
|
<TextBlock Text="yuhaodatt" />
|
||||||
|
|
||||||
|
<TextBlock Text="中文 (廣東話)" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="henrychu1125" />
|
||||||
|
<TextBlock Text="kitzure" />
|
||||||
|
<TextBlock Text="Kimina898" />
|
||||||
|
<TextBlock Text="shhh_op" />
|
||||||
|
|
||||||
|
<TextBlock Text="中文 (繁體)" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="14TQD" />
|
||||||
|
<TextBlock Text="DXuwu" />
|
||||||
|
<TextBlock Text="kitzure" />
|
||||||
|
<TextBlock Text="Kimina898" />
|
||||||
|
|
||||||
|
<TextBlock Text="日本語" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
||||||
|
<TextBlock.Foreground>
|
||||||
|
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
||||||
|
</TextBlock.Foreground>
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock Text="MintJapan" />
|
||||||
|
<TextBlock Text="pimeja7" />
|
||||||
|
<TextBlock Text="yixhuaa" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</ui:UiPage>
|
13
Bloxstrap/UI/Elements/About/Pages/TranslatorsPage.xaml.cs
Normal file
13
Bloxstrap/UI/Elements/About/Pages/TranslatorsPage.xaml.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Bloxstrap.UI.Elements.About.Pages
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for TranslatorsPage.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class TranslatorsPage
|
||||||
|
{
|
||||||
|
public TranslatorsPage()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -61,7 +61,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem x:Name="CloseRobloxMenuItem" Visibility="Collapsed" Click="CloseRobloxMenuItem_Click">
|
<MenuItem Click="CloseRobloxMenuItem_Click">
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@ -73,7 +73,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem x:Name="LogTracerMenuItem" Click="LogTracerMenuItem_Click">
|
<MenuItem x:Name="LogTracerMenuItem" Visibility="Collapsed" Click="LogTracerMenuItem_Click">
|
||||||
<MenuItem.Header>
|
<MenuItem.Header>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@ -81,7 +81,7 @@
|
|||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<ui:SymbolIcon Grid.Column="0" Symbol="DocumentCatchUp20"/>
|
<ui:SymbolIcon Grid.Column="0" Symbol="DocumentCatchUp20"/>
|
||||||
<TextBlock Grid.Column="1" VerticalAlignment="Center" Margin="4,0,0,0" Text="{x:Static resources:Strings.ContextMenu_OpenLogFile}" />
|
<TextBlock Grid.Column="1" VerticalAlignment="Center" Margin="4,0,0,0" Text="{x:Static resources:Strings.Common_OpenLogFile}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
@ -22,32 +22,28 @@ namespace Bloxstrap.UI.Elements.ContextMenu
|
|||||||
{
|
{
|
||||||
// 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
|
// 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
|
||||||
|
|
||||||
private readonly ActivityWatcher? _activityWatcher;
|
private readonly Watcher _watcher;
|
||||||
private readonly DiscordRichPresence? _richPresenceHandler;
|
|
||||||
|
private ActivityWatcher? _activityWatcher => _watcher.ActivityWatcher;
|
||||||
|
|
||||||
private ServerInformation? _serverInformationWindow;
|
private ServerInformation? _serverInformationWindow;
|
||||||
private int? _processId;
|
|
||||||
|
|
||||||
public MenuContainer(ActivityWatcher? activityWatcher, DiscordRichPresence? richPresenceHandler, int? processId)
|
public MenuContainer(Watcher watcher)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
_activityWatcher = activityWatcher;
|
_watcher = watcher;
|
||||||
_richPresenceHandler = richPresenceHandler;
|
|
||||||
_processId = processId;
|
|
||||||
|
|
||||||
if (_activityWatcher is not null)
|
if (_activityWatcher is not null)
|
||||||
{
|
{
|
||||||
|
_activityWatcher.OnLogOpen += ActivityWatcher_OnLogOpen;
|
||||||
_activityWatcher.OnGameJoin += ActivityWatcher_OnGameJoin;
|
_activityWatcher.OnGameJoin += ActivityWatcher_OnGameJoin;
|
||||||
_activityWatcher.OnGameLeave += ActivityWatcher_OnGameLeave;
|
_activityWatcher.OnGameLeave += ActivityWatcher_OnGameLeave;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_richPresenceHandler is not null)
|
if (_watcher.RichPresence is not null)
|
||||||
RichPresenceMenuItem.Visibility = Visibility.Visible;
|
RichPresenceMenuItem.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
if (_processId is not null)
|
|
||||||
CloseRobloxMenuItem.Visibility = Visibility.Visible;
|
|
||||||
|
|
||||||
VersionTextBlock.Text = $"{App.ProjectName} v{App.Version}";
|
VersionTextBlock.Text = $"{App.ProjectName} v{App.Version}";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +51,7 @@ namespace Bloxstrap.UI.Elements.ContextMenu
|
|||||||
{
|
{
|
||||||
if (_serverInformationWindow is null)
|
if (_serverInformationWindow is null)
|
||||||
{
|
{
|
||||||
_serverInformationWindow = new ServerInformation(_activityWatcher!);
|
_serverInformationWindow = new ServerInformation(_watcher);
|
||||||
_serverInformationWindow.Closed += (_, _) => _serverInformationWindow = null;
|
_serverInformationWindow.Closed += (_, _) => _serverInformationWindow = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,17 +61,23 @@ namespace Bloxstrap.UI.Elements.ContextMenu
|
|||||||
_serverInformationWindow.Activate();
|
_serverInformationWindow.Activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ActivityWatcher_OnGameJoin(object? sender, EventArgs e)
|
public void ActivityWatcher_OnLogOpen(object? sender, EventArgs e) =>
|
||||||
|
Dispatcher.Invoke(() => LogTracerMenuItem.Visibility = Visibility.Visible);
|
||||||
|
|
||||||
|
public void ActivityWatcher_OnGameJoin(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_activityWatcher is null)
|
||||||
|
return;
|
||||||
|
|
||||||
Dispatcher.Invoke(() => {
|
Dispatcher.Invoke(() => {
|
||||||
if (_activityWatcher?.ActivityServerType == ServerType.Public)
|
if (_activityWatcher.ActivityServerType == ServerType.Public)
|
||||||
InviteDeeplinkMenuItem.Visibility = Visibility.Visible;
|
InviteDeeplinkMenuItem.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
ServerDetailsMenuItem.Visibility = Visibility.Visible;
|
ServerDetailsMenuItem.Visibility = Visibility.Visible;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ActivityWatcher_OnGameLeave(object? sender, EventArgs e)
|
public void ActivityWatcher_OnGameLeave(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(() => {
|
Dispatcher.Invoke(() => {
|
||||||
InviteDeeplinkMenuItem.Visibility = Visibility.Collapsed;
|
InviteDeeplinkMenuItem.Visibility = Visibility.Collapsed;
|
||||||
@ -100,7 +102,7 @@ namespace Bloxstrap.UI.Elements.ContextMenu
|
|||||||
|
|
||||||
private void Window_Closed(object sender, EventArgs e) => App.Logger.WriteLine("MenuContainer::Window_Closed", "Context menu container closed");
|
private void Window_Closed(object sender, EventArgs e) => App.Logger.WriteLine("MenuContainer::Window_Closed", "Context menu container closed");
|
||||||
|
|
||||||
private void RichPresenceMenuItem_Click(object sender, RoutedEventArgs e) => _richPresenceHandler?.SetVisibility(((MenuItem)sender).IsChecked);
|
private void RichPresenceMenuItem_Click(object sender, RoutedEventArgs e) => _watcher.RichPresence?.SetVisibility(((MenuItem)sender).IsChecked);
|
||||||
|
|
||||||
private void InviteDeeplinkMenuItem_Click(object sender, RoutedEventArgs e) => Clipboard.SetDataObject($"roblox://experiences/start?placeId={_activityWatcher?.ActivityPlaceId}&gameInstanceId={_activityWatcher?.ActivityJobId}");
|
private void InviteDeeplinkMenuItem_Click(object sender, RoutedEventArgs e) => Clipboard.SetDataObject($"roblox://experiences/start?placeId={_activityWatcher?.ActivityPlaceId}&gameInstanceId={_activityWatcher?.ActivityJobId}");
|
||||||
|
|
||||||
@ -110,12 +112,7 @@ namespace Bloxstrap.UI.Elements.ContextMenu
|
|||||||
{
|
{
|
||||||
string? location = _activityWatcher?.LogLocation;
|
string? location = _activityWatcher?.LogLocation;
|
||||||
|
|
||||||
if (location is null)
|
if (location is not null)
|
||||||
{
|
|
||||||
Frontend.ShowMessageBox(Strings.ContextMenu_RobloxNotRunning, MessageBoxImage.Information);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Utilities.ShellExecute(location);
|
Utilities.ShellExecute(location);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,9 +127,7 @@ namespace Bloxstrap.UI.Elements.ContextMenu
|
|||||||
if (result != MessageBoxResult.Yes)
|
if (result != MessageBoxResult.Yes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using Process process = Process.GetProcessById((int)_processId!);
|
_watcher.KillRobloxProcess();
|
||||||
process.Kill();
|
|
||||||
process.Close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,13 @@ namespace Bloxstrap.UI.Elements.ContextMenu
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class ServerInformation
|
public partial class ServerInformation
|
||||||
{
|
{
|
||||||
public ServerInformation(ActivityWatcher activityWatcher)
|
public ServerInformation(Watcher watcher)
|
||||||
{
|
{
|
||||||
DataContext = new ServerInformationViewModel(this, activityWatcher);
|
var viewModel = new ServerInformationViewModel(watcher);
|
||||||
|
|
||||||
|
viewModel.RequestCloseEvent += (_, _) => Close();
|
||||||
|
|
||||||
|
DataContext = viewModel;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
<Border Grid.Row="2" Padding="15" Background="{ui:ThemeResource SolidBackgroundFillColorSecondaryBrush}">
|
<Border Grid.Row="2" Padding="15" Background="{ui:ThemeResource SolidBackgroundFillColorSecondaryBrush}">
|
||||||
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight" HorizontalAlignment="Right">
|
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight" HorizontalAlignment="Right">
|
||||||
<Button x:Name="LocateLogFileButton" Content="{x:Static resources:Strings.Common_LocateLogFile}" />
|
<Button x:Name="LocateLogFileButton" Content="{x:Static resources:Strings.Common_OpenLogFile}" />
|
||||||
<Button x:Name="CloseButton" MinWidth="100" Content="{x:Static resources:Strings.Common_Close}" Margin="12,0,0,0" />
|
<Button x:Name="CloseButton" MinWidth="100" Content="{x:Static resources:Strings.Common_Close}" Margin="12,0,0,0" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
using System.Media;
|
using System.Media;
|
||||||
|
using System.Web;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
|
|
||||||
using Windows.Win32;
|
using Windows.Win32;
|
||||||
using Windows.Win32.Foundation;
|
using Windows.Win32.Foundation;
|
||||||
|
|
||||||
using Bloxstrap.Resources;
|
|
||||||
|
|
||||||
namespace Bloxstrap.UI.Elements.Dialogs
|
namespace Bloxstrap.UI.Elements.Dialogs
|
||||||
{
|
{
|
||||||
// hmm... do i use MVVM for this?
|
// hmm... do i use MVVM for this?
|
||||||
@ -26,19 +24,29 @@ namespace Bloxstrap.UI.Elements.Dialogs
|
|||||||
if (!App.Logger.Initialized)
|
if (!App.Logger.Initialized)
|
||||||
LocateLogFileButton.Content = Strings.Dialog_Exception_CopyLogContents;
|
LocateLogFileButton.Content = Strings.Dialog_Exception_CopyLogContents;
|
||||||
|
|
||||||
string helpMessage = String.Format(Strings.Dialog_Exception_Info_2, "https://github.com/pizzaboxer/bloxstrap/wiki", "https://github.com/pizzaboxer/bloxstrap/issues/new?template=bug_report.yaml");
|
string repoUrl = $"https://github.com/{App.ProjectRepository}";
|
||||||
|
string wikiUrl = $"{repoUrl}/wiki";
|
||||||
|
|
||||||
if (String.IsNullOrEmpty(App.BuildMetadata.CommitHash))
|
string issueUrl = String.Format(
|
||||||
helpMessage = String.Format(Strings.Dialog_Exception_Info_2_Alt, "https://github.com/pizzaboxer/bloxstrap/wiki");
|
"{0}/issues/new?template=bug_report.yaml&title={1}&log={2}",
|
||||||
|
repoUrl,
|
||||||
|
HttpUtility.UrlEncode($"[BUG] {exception.GetType()}: {exception.Message}"),
|
||||||
|
HttpUtility.UrlEncode(String.Join('\n', App.Logger.History))
|
||||||
|
);
|
||||||
|
|
||||||
|
string helpMessage = String.Format(Strings.Dialog_Exception_Info_2, wikiUrl, issueUrl);
|
||||||
|
|
||||||
|
if (!App.IsActionBuild && !App.BuildMetadata.Machine.Contains("pizzaboxer", StringComparison.Ordinal))
|
||||||
|
helpMessage = String.Format(Strings.Dialog_Exception_Info_2_Alt, wikiUrl);
|
||||||
|
|
||||||
HelpMessageMDTextBlock.MarkdownText = helpMessage;
|
HelpMessageMDTextBlock.MarkdownText = helpMessage;
|
||||||
|
|
||||||
LocateLogFileButton.Click += delegate
|
LocateLogFileButton.Click += delegate
|
||||||
{
|
{
|
||||||
if (App.Logger.Initialized)
|
if (App.Logger.Initialized && !String.IsNullOrEmpty(App.Logger.FileLocation))
|
||||||
Process.Start("explorer.exe", $"/select,\"{App.Logger.FileLocation}\"");
|
Utilities.ShellExecute(App.Logger.FileLocation);
|
||||||
else
|
else
|
||||||
Clipboard.SetDataObject(String.Join("\r\n", App.Logger.Backlog));
|
Clipboard.SetDataObject(String.Join("\r\n", App.Logger.History));
|
||||||
};
|
};
|
||||||
|
|
||||||
CloseButton.Click += delegate
|
CloseButton.Click += delegate
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
Title="Bloxstrap"
|
Title="Bloxstrap"
|
||||||
MinWidth="0"
|
MinWidth="0"
|
||||||
MinHeight="0"
|
MinHeight="0"
|
||||||
Width="320"
|
Width="580"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
ResizeMode="NoResize"
|
ResizeMode="NoResize"
|
||||||
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
|
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
|
||||||
@ -24,11 +24,40 @@
|
|||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<ui:TitleBar Grid.Row="0" Grid.ColumnSpan="2" Padding="8" Title="Bloxstrap" ShowMinimize="False" ShowMaximize="False" CanMaximize="False" KeyboardNavigation.TabNavigation="None" Icon="pack://application:,,,/Bloxstrap.ico" />
|
<ui:TitleBar Grid.Row="0" Grid.ColumnSpan="2" Padding="8" ShowMinimize="False" ShowMaximize="False" CanMaximize="False" KeyboardNavigation.TabNavigation="None" />
|
||||||
|
|
||||||
<StackPanel Grid.Row="1" Margin="12">
|
<Grid Grid.Row="1">
|
||||||
<TextBlock FontSize="24" Text="{x:Static resources:Strings.LaunchMenu_Title}" HorizontalAlignment="Center" Margin="0,0,0,16" />
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Grid Grid.Column="0" VerticalAlignment="Center">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid Grid.Row="0" HorizontalAlignment="Center" Margin="0,0,0,32">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Image Grid.Column="0" Width="64" Height="64" Source="pack://application:,,,/Bloxstrap.ico" RenderOptions.BitmapScalingMode="HighQuality" />
|
||||||
|
<StackPanel Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center">
|
||||||
|
<TextBlock Text="Bloxstrap" FontSize="24" />
|
||||||
|
<TextBlock Text="{Binding Version, Mode=OneTime}" VerticalAlignment="Bottom" FontSize="12" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="1" HorizontalAlignment="Center">
|
||||||
|
<ui:Hyperlink Icon="QuestionCircle48" Content="About Bloxstrap" Margin="0,0,0,8" Command="{Binding LaunchAboutCommand, Mode=OneTime}" />
|
||||||
|
<ui:Hyperlink Icon="WindowNew16" Content="Support us on Ko-fi!" NavigateUri="https://ko-fi.com/boxerpizza" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<StackPanel Grid.Column="1" Margin="16">
|
||||||
<ui:CardAction Icon="ArrowRight12" Command="{Binding LaunchRobloxCommand, Mode=OneTime}">
|
<ui:CardAction Icon="ArrowRight12" Command="{Binding LaunchRobloxCommand, Mode=OneTime}">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock FontSize="14" Text="{x:Static resources:Strings.LaunchMenu_LaunchRoblox}" />
|
<TextBlock FontSize="14" Text="{x:Static resources:Strings.LaunchMenu_LaunchRoblox}" />
|
||||||
@ -41,14 +70,15 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ui:CardAction>
|
</ui:CardAction>
|
||||||
|
|
||||||
|
<Border Margin="16" />
|
||||||
|
|
||||||
<ui:CardAction Margin="0,8,0,0" Icon="BookQuestionMark24" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/">
|
<ui:CardAction Margin="0,8,0,0" Icon="BookQuestionMark24" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock FontSize="14" Text="{x:Static resources:Strings.LaunchMenu_Wiki_Title}" />
|
<TextBlock FontSize="14" Text="{x:Static resources:Strings.LaunchMenu_Wiki_Title}" />
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.LaunchMenu_Wiki_Description}" Padding="0,0,16,0" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.LaunchMenu_Wiki_Description}" Padding="0,0,16,0" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ui:CardAction>
|
</ui:CardAction>
|
||||||
|
|
||||||
<TextBlock Margin="0,16,0,0" FontSize="12" Text="{Binding Version, Mode=OneTime}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Grid>
|
||||||
</base:WpfUiWindow>
|
</base:WpfUiWindow>
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
|
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
|
||||||
ExtendsContentIntoTitleBar="True"
|
ExtendsContentIntoTitleBar="True"
|
||||||
WindowBackdropType="Mica"
|
WindowBackdropType="Mica"
|
||||||
WindowStartupLocation="CenterScreen">
|
WindowStartupLocation="CenterScreen"
|
||||||
|
Closing="WpfUiWindow_Closing">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@ -60,7 +61,7 @@
|
|||||||
<ui:NavigationItem Content="" PageType="{x:Type pages:FastFlagEditorWarningPage}" Tag="fastflageditorwarning" Visibility="Collapsed" x:Name="EditorWarningNavItem" />
|
<ui:NavigationItem Content="" PageType="{x:Type pages:FastFlagEditorWarningPage}" Tag="fastflageditorwarning" Visibility="Collapsed" x:Name="EditorWarningNavItem" />
|
||||||
</ui:NavigationFluent.Items>
|
</ui:NavigationFluent.Items>
|
||||||
<ui:NavigationFluent.Footer>
|
<ui:NavigationFluent.Footer>
|
||||||
<ui:NavigationItem Content="{x:Static resources:Strings.Menu_About_Title}" PageType="{x:Type pages:AboutPage}" Icon="QuestionCircle48" Tag="about" Margin="0,0,0,12" />
|
<ui:NavigationItem Content="{x:Static resources:Strings.Menu_About_Title}" Icon="QuestionCircle48" Margin="0,0,0,12" Command="{Binding OpenAboutCommand, Mode=OneTime}" />
|
||||||
</ui:NavigationFluent.Footer>
|
</ui:NavigationFluent.Footer>
|
||||||
</ui:NavigationFluent>
|
</ui:NavigationFluent>
|
||||||
|
|
||||||
@ -93,7 +94,7 @@
|
|||||||
<ui:Button Content="{x:Static resources:Strings.Menu_Save}" Appearance="Primary" Command="{Binding SaveSettingsCommand, Mode=OneWay}" />
|
<ui:Button Content="{x:Static resources:Strings.Menu_Save}" Appearance="Primary" Command="{Binding SaveSettingsCommand, Mode=OneWay}" />
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
<StatusBarItem Grid.Column="2" Padding="4,0,0,0">
|
<StatusBarItem Grid.Column="2" Padding="4,0,0,0">
|
||||||
<ui:Button Content="{x:Static resources:Strings.Common_Close}" IsCancel="True" />
|
<ui:Button Content="{x:Static resources:Strings.Common_Close}" Command="{Binding CloseWindowCommand, Mode=OneWay}" />
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
</StatusBar>
|
</StatusBar>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
using System.Windows.Controls;
|
using System.ComponentModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
using Wpf.Ui.Controls.Interfaces;
|
using Wpf.Ui.Controls.Interfaces;
|
||||||
using Wpf.Ui.Mvvm.Contracts;
|
using Wpf.Ui.Mvvm.Contracts;
|
||||||
|
|
||||||
using Bloxstrap.UI.ViewModels.Settings;
|
using Bloxstrap.UI.ViewModels.Settings;
|
||||||
|
|
||||||
namespace Bloxstrap.UI.Elements.Settings
|
namespace Bloxstrap.UI.Elements.Settings
|
||||||
@ -13,7 +17,9 @@ namespace Bloxstrap.UI.Elements.Settings
|
|||||||
public MainWindow(bool showAlreadyRunningWarning)
|
public MainWindow(bool showAlreadyRunningWarning)
|
||||||
{
|
{
|
||||||
var viewModel = new MainWindowViewModel();
|
var viewModel = new MainWindowViewModel();
|
||||||
|
|
||||||
viewModel.RequestSaveNoticeEvent += (_, _) => SettingsSavedSnackbar.Show();
|
viewModel.RequestSaveNoticeEvent += (_, _) => SettingsSavedSnackbar.Show();
|
||||||
|
viewModel.RequestCloseWindowEvent += (_, _) => Close();
|
||||||
|
|
||||||
DataContext = viewModel;
|
DataContext = viewModel;
|
||||||
|
|
||||||
@ -22,7 +28,7 @@ namespace Bloxstrap.UI.Elements.Settings
|
|||||||
App.Logger.WriteLine("MainWindow::MainWindow", "Initializing menu");
|
App.Logger.WriteLine("MainWindow::MainWindow", "Initializing menu");
|
||||||
|
|
||||||
#if DEBUG // easier access
|
#if DEBUG // easier access
|
||||||
EditorWarningNavItem.Visibility = System.Windows.Visibility.Visible;
|
EditorWarningNavItem.Visibility = Visibility.Visible;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (showAlreadyRunningWarning)
|
if (showAlreadyRunningWarning)
|
||||||
@ -50,5 +56,19 @@ namespace Bloxstrap.UI.Elements.Settings
|
|||||||
public void CloseWindow() => Close();
|
public void CloseWindow() => Close();
|
||||||
|
|
||||||
#endregion INavigationWindow methods
|
#endregion INavigationWindow methods
|
||||||
|
|
||||||
|
private void WpfUiWindow_Closing(object sender, CancelEventArgs e)
|
||||||
|
{
|
||||||
|
if (App.FastFlags.Changed || App.PendingSettingTasks.Any())
|
||||||
|
{
|
||||||
|
var result = Frontend.ShowMessageBox(Strings.Menu_UnsavedChanges, MessageBoxImage.Warning, MessageBoxButton.YesNo);
|
||||||
|
|
||||||
|
if (result != MessageBoxResult.Yes)
|
||||||
|
e.Cancel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!e.Cancel)
|
||||||
|
App.Terminate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,665 +0,0 @@
|
|||||||
<ui:UiPage x:Class="Bloxstrap.UI.Elements.Settings.Pages.AboutPage"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:models="clr-namespace:Bloxstrap.UI.ViewModels"
|
|
||||||
xmlns:controls="clr-namespace:Bloxstrap.UI.Elements.Controls"
|
|
||||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
|
||||||
xmlns:resources="clr-namespace:Bloxstrap.Resources"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
d:DesignHeight="1500" d:DesignWidth="800"
|
|
||||||
Title="AboutPage"
|
|
||||||
Scrollable="True">
|
|
||||||
<StackPanel Margin="0,0,14,14">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<Image Grid.Column="0" Width="60" Height="60" VerticalAlignment="Center" Source="pack://application:,,,/Bloxstrap.ico" RenderOptions.BitmapScalingMode="HighQuality" />
|
|
||||||
<StackPanel Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBlock Grid.Column="0" Text="Bloxstrap" Margin="0,0,4,0" FontSize="24" FontWeight="Medium" />
|
|
||||||
<TextBlock Grid.Column="1" Text="{Binding Version, Mode=OneTime}" Margin="4,0,0,2" VerticalAlignment="Bottom" FontSize="16" FontWeight="Medium" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</Grid>
|
|
||||||
<TextBlock Text="{x:Static resources:Strings.Menu_About_Description}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
<WrapPanel Orientation="Horizontal">
|
|
||||||
<ui:Anchor Margin="0,16,8,0" Content="{x:Static resources:Strings.Menu_About_GithubRepository}" Icon="Code24" NavigateUri="https://github.com/pizzaboxer/bloxstrap" />
|
|
||||||
<ui:Anchor Margin="0,16,8,0" Content="{x:Static resources:Strings.Menu_About_ReportIssue}" Icon="Chat48" NavigateUri="https://github.com/pizzaboxer/bloxstrap/issues" />
|
|
||||||
<ui:Anchor Margin="0,16,8,0" Content="{x:Static resources:Strings.Menu_About_HelpInformation}" Icon="BookQuestionMark24" NavigateUri="https://github.com/pizzaboxer/bloxstrap/wiki" />
|
|
||||||
<ui:Anchor Margin="0,16,0,0" Content="{x:Static resources:Strings.Menu_About_DiscordServer}" Icon="Chat48" NavigateUri="https://discord.gg/nKjV3mGq6R" />
|
|
||||||
</WrapPanel>
|
|
||||||
|
|
||||||
<StackPanel Visibility="{Binding BuildInformationVisibility, Mode=OneTime}">
|
|
||||||
<TextBlock Text="Build Information" FontWeight="Medium" FontSize="20" Margin="0,16,0,0" />
|
|
||||||
<TextBlock Text="hmmmm" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
|
|
||||||
<Grid Column="0" Margin="0,8,0,0">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,4,16,4" FontSize="14" FontWeight="Medium" Text="Timestamp" />
|
|
||||||
<TextBlock Grid.Row="0" Grid.Column="1" Margin="0,0,0,4" VerticalAlignment="Bottom" Text="{Binding BuildTimestamp, Mode=OneTime}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,4,16,4" FontSize="14" FontWeight="Medium" Text="Machine" />
|
|
||||||
<TextBlock Grid.Row="1" Grid.Column="1" Margin="0,0,0,4" VerticalAlignment="Bottom" Text="{Binding BuildMetadata.Machine, Mode=OneTime}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,4,16,4" FontSize="14" FontWeight="Medium" Text="Commit Hash" Visibility="{Binding BuildCommitVisibility, Mode=OneTime}" />
|
|
||||||
<TextBlock Grid.Row="2" Grid.Column="1" Margin="0,0,0,4" VerticalAlignment="Bottom" Foreground="{DynamicResource TextFillColorTertiaryBrush}" Visibility="{Binding BuildCommitVisibility, Mode=OneTime}">
|
|
||||||
<Hyperlink Foreground="{DynamicResource TextFillColorTertiaryBrush}" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="{Binding BuildCommitHashUrl, Mode=OneTime}">
|
|
||||||
<TextBlock Text="{Binding BuildMetadata.CommitHash, Mode=OneTime}" />
|
|
||||||
</Hyperlink>
|
|
||||||
</TextBlock>
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="3" Grid.Column="0" Margin="0,4,16,4" FontSize="14" FontWeight="Medium" Text="Commit Ref" Visibility="{Binding BuildCommitVisibility, Mode=OneTime}" />
|
|
||||||
<TextBlock Grid.Row="3" Grid.Column="1" Margin="0,0,0,4" VerticalAlignment="Bottom" Text="{Binding BuildMetadata.CommitRef, Mode=OneTime}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" Visibility="{Binding BuildCommitVisibility, Mode=OneTime}" />
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<TextBlock Text="{x:Static resources:Strings.Menu_About_Contributors}" FontWeight="Medium" FontSize="20" Margin="0,16,0,0" />
|
|
||||||
<TextBlock Text="{x:Static resources:Strings.Menu_About_Contributors_Description}" TextWrapping="Wrap" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
<Grid Margin="0,8,0,0">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<controls:Expander Grid.Row="0" Grid.ColumnSpan="3" Margin="0,0,0,8" HeaderIcon="Translate24" HeaderText="{x:Static resources:Strings.Menu_About_Contributors_Translations}">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="0">
|
|
||||||
<TextBlock Text="Bahasa Indonesia" FontSize="16" FontWeight="Medium">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="e7leopard" />
|
|
||||||
<TextBlock Text="hfzrk" />
|
|
||||||
<TextBlock Text="soudblox" />
|
|
||||||
|
|
||||||
<TextBlock Text="Bokmål" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="darkevilmage" />
|
|
||||||
<TextBlock Text="endsouls" />
|
|
||||||
<TextBlock Text="letoek" />
|
|
||||||
|
|
||||||
<!--<TextBlock Text="Čeština" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="Chusaak" />
|
|
||||||
<TextBlock Text="DanyCraftCZ" />
|
|
||||||
<TextBlock Text="Franklin_Surten" />
|
|
||||||
<TextBlock Text="Galaxy_Gangster6" />
|
|
||||||
<TextBlock Text="jasperholo" />
|
|
||||||
<TextBlock Text="letoek" />
|
|
||||||
<TextBlock Text="noobkid4545" />
|
|
||||||
<TextBlock Text="radim776" />-->
|
|
||||||
|
|
||||||
<!-- <TextBlock Text="Dansk" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="Momslayer98" />
|
|
||||||
<TextBlock Text="SirBlue" /> -->
|
|
||||||
|
|
||||||
<TextBlock Text="Deutsch" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="agent_phoenix" />
|
|
||||||
<TextBlock Text="avoidr" />
|
|
||||||
<TextBlock Text="hcjohnsgd" />
|
|
||||||
<TextBlock Text="hxmbt" />
|
|
||||||
<TextBlock Text="kale123" />
|
|
||||||
<TextBlock Text="Marvin_Chu" />
|
|
||||||
<TextBlock Text="nzxt_xll" />
|
|
||||||
<TextBlock Text="Nlx095" />
|
|
||||||
<TextBlock Text="Ph1lwtf" />
|
|
||||||
<TextBlock Text="sxckqerz" />
|
|
||||||
<TextBlock Text="TEAM_LILA" />
|
|
||||||
<TextBlock Text="xDevoidx" />
|
|
||||||
|
|
||||||
<TextBlock Text="Español" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="4Xisty" />
|
|
||||||
<TextBlock Text="Botkid" />
|
|
||||||
<TextBlock Text="colocky" />
|
|
||||||
<TextBlock Text="D0N-B0T" />
|
|
||||||
<TextBlock Text="Dasp" />
|
|
||||||
<TextBlock Text="devyyxn" />
|
|
||||||
<TextBlock Text="ItzzExcel" />
|
|
||||||
<TextBlock Text="Ilayhlinda" />
|
|
||||||
<TextBlock Text="Ilushiouss" />
|
|
||||||
<TextBlock Text="jayces." />
|
|
||||||
<TextBlock Text="kroesufos" />
|
|
||||||
<TextBlock Text="LaiyLiod" />
|
|
||||||
<TextBlock Text="lyalekin" />
|
|
||||||
<TextBlock Text="NezumiDS" />
|
|
||||||
<TextBlock Text="NimuruDP" />
|
|
||||||
<TextBlock Text="NescafeCL" />
|
|
||||||
<TextBlock Text="Sw7gger" />
|
|
||||||
<TextBlock Text="sxckqerz" />
|
|
||||||
<TextBlock Text="Urzy" />
|
|
||||||
|
|
||||||
<TextBlock Text="Filipino" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="alphjectiom" />
|
|
||||||
<TextBlock Text="FlaminDaPotato" />
|
|
||||||
<TextBlock Text="RobiTheRobloxxer" />
|
|
||||||
<TextBlock Text="shadow01148" />
|
|
||||||
|
|
||||||
<TextBlock Text="Français" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="At0zDx" />
|
|
||||||
<TextBlock Text="built4aiming" />
|
|
||||||
<TextBlock Text="hahaloserz360" />
|
|
||||||
<TextBlock Text="K0ga" />
|
|
||||||
<TextBlock Text="Marcssebaa" />
|
|
||||||
<TextBlock Text="MommySernox" />
|
|
||||||
<TextBlock Text="owentempest8" />
|
|
||||||
<TextBlock Text="Subsical" />
|
|
||||||
<TextBlock Text="thatsirwaffles" />
|
|
||||||
<TextBlock Text="tyundrai" />
|
|
||||||
<TextBlock Text="Waza80" />
|
|
||||||
|
|
||||||
<TextBlock Text="Hindi (Latin)" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="kunaljainop" />
|
|
||||||
<TextBlock Text="marathedonroblox" />
|
|
||||||
<TextBlock Text="Sur_" />
|
|
||||||
<TextBlock Text="Tezos" />
|
|
||||||
<TextBlock Text="TheTakuo" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="1">
|
|
||||||
<TextBlock Text="Hrvatski" FontSize="16" FontWeight="Medium">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="Dzigos" />
|
|
||||||
<TextBlock Text="Koyroii" />
|
|
||||||
<TextBlock Text="Nemznja" />
|
|
||||||
|
|
||||||
<TextBlock Text="Italiano" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="crow_zxcr" />
|
|
||||||
<TextBlock Text="devyyxn" />
|
|
||||||
<TextBlock Text="domenicoiacono" />
|
|
||||||
<TextBlock Text="hulabulaseop" />
|
|
||||||
<TextBlock Text="lord_moth" />
|
|
||||||
<TextBlock Text="loridori" />
|
|
||||||
<TextBlock Text="Lupo01" />
|
|
||||||
<TextBlock Text="Mogunars" />
|
|
||||||
<TextBlock Text="pave08" />
|
|
||||||
<TextBlock Text="spectrumbruh" />
|
|
||||||
|
|
||||||
<TextBlock Text="Lietuvių" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="cr0000142" />
|
|
||||||
<TextBlock Text="Duexo" />
|
|
||||||
<TextBlock Text="jessethedev" />
|
|
||||||
<TextBlock Text="Vac31." />
|
|
||||||
|
|
||||||
<TextBlock Text="Magyar" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="DynoPlays" />
|
|
||||||
<TextBlock Text="Elotomka" />
|
|
||||||
<TextBlock Text="xM4rk1" />
|
|
||||||
|
|
||||||
<!--<TextBlock Text="Nederlands" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="Cosmix" />
|
|
||||||
<TextBlock Text="Miwwzy" />
|
|
||||||
<TextBlock Text="Quickvision1" />
|
|
||||||
<TextBlock Text="ydboss" />-->
|
|
||||||
|
|
||||||
<TextBlock Text="Polski" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="Eztaru" />
|
|
||||||
<TextBlock Text="lunar" />
|
|
||||||
<TextBlock Text="markontm" />
|
|
||||||
<TextBlock Text="my5q" />
|
|
||||||
<TextBlock Text="nemzik2137" />
|
|
||||||
<TextBlock Text="plexar" />
|
|
||||||
<TextBlock Text="r.efil" />
|
|
||||||
|
|
||||||
<TextBlock Text="Português (Brasil)" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="anormalevis" />
|
|
||||||
<TextBlock Text="ErisvaldoBalbino" />
|
|
||||||
<TextBlock Text="G3xneric" />
|
|
||||||
<TextBlock Text="hnter" />
|
|
||||||
<TextBlock Text="issei_" />
|
|
||||||
<TextBlock Text="iyto.lk" />
|
|
||||||
<TextBlock Text="jhermesn" />
|
|
||||||
<TextBlock Text="JorgeDaPelada" />
|
|
||||||
<TextBlock Text="LwgoDev" />
|
|
||||||
<TextBlock Text="nunk7" />
|
|
||||||
<TextBlock Text="peke7374" />
|
|
||||||
<TextBlock Text="SeeF" />
|
|
||||||
<TextBlock Text="Snowzin1" />
|
|
||||||
<TextBlock Text="storm930" />
|
|
||||||
<TextBlock Text="toofastforboo" />
|
|
||||||
<TextBlock Text="VMOICE" />
|
|
||||||
<TextBlock Text="Ye4" />
|
|
||||||
<TextBlock Text="ZaPeZaPe" />
|
|
||||||
|
|
||||||
<TextBlock Text="Română" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="Externalkinetics" />
|
|
||||||
<TextBlock Text="MonochromeAlex" />
|
|
||||||
<TextBlock Text="PlayerValley" />
|
|
||||||
<TextBlock Text="Smuki" />
|
|
||||||
<TextBlock Text="theflopperguy" />
|
|
||||||
|
|
||||||
<TextBlock Text="Suomi" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="gelaxiz" />
|
|
||||||
<TextBlock Text="jes5" />
|
|
||||||
<TextBlock Text="retromaxwell" />
|
|
||||||
<TextBlock Text="SomePinglord" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="2">
|
|
||||||
<TextBlock Text="Svenska" FontSize="16" FontWeight="Medium">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="Axellse" />
|
|
||||||
<TextBlock Text="CroppingFlea479" />
|
|
||||||
<TextBlock Text="FishySpelar" />
|
|
||||||
<TextBlock Text="PineappleSnackz" />
|
|
||||||
<TextBlock Text="simonixen" />
|
|
||||||
<TextBlock Text="thatgurkangurk" />
|
|
||||||
|
|
||||||
<TextBlock Text="Tiếng Việt" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="alexking2068" />
|
|
||||||
<TextBlock Text="baterblx" />
|
|
||||||
<TextBlock Text="Elytronn" />
|
|
||||||
<TextBlock Text="fox810891" />
|
|
||||||
<TextBlock Text="ItsPoofy" />
|
|
||||||
<TextBlock Text="Limer1" />
|
|
||||||
<TextBlock Text="makayu203332" />
|
|
||||||
<TextBlock Text="MEx2/j7x6" />
|
|
||||||
<TextBlock Text="NguyenDat208" />
|
|
||||||
<TextBlock Text="quanmequankk" />
|
|
||||||
<TextBlock Text="SomeRandomGuy175" />
|
|
||||||
<TextBlock Text="SonThanhVN" />
|
|
||||||
<TextBlock Text="teaanguyenn" />
|
|
||||||
<TextBlock Text="Veiiorra" />
|
|
||||||
|
|
||||||
<TextBlock Text="Türkçe" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="canny19133" />
|
|
||||||
<TextBlock Text="cfors55" />
|
|
||||||
<TextBlock Text="drakfreddy" />
|
|
||||||
<TextBlock Text="enisify" />
|
|
||||||
<TextBlock Text="jayces." />
|
|
||||||
<TextBlock Text="nyatie" />
|
|
||||||
<TextBlock Text="PixelArmy" />
|
|
||||||
<TextBlock Text="plants8332" />
|
|
||||||
<TextBlock Text="r02" />
|
|
||||||
<TextBlock Text="siyamicik" />
|
|
||||||
<TextBlock Text="ydboss" />
|
|
||||||
|
|
||||||
<TextBlock Text="Українська" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="9zh" />
|
|
||||||
<TextBlock Text="andrey3569s" />
|
|
||||||
<TextBlock Text="DexterBloxxer" />
|
|
||||||
<TextBlock Text="Externalkinetics" />
|
|
||||||
<TextBlock Text="maksimvlad7" />
|
|
||||||
|
|
||||||
<TextBlock Text="Босански" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="Cortex_1" />
|
|
||||||
<TextBlock Text="Nemznja" />
|
|
||||||
<TextBlock Text="Ren" />
|
|
||||||
|
|
||||||
<TextBlock Text="Български" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="GrafitNiki" />
|
|
||||||
<TextBlock Text="sidefrappe" />
|
|
||||||
|
|
||||||
<TextBlock Text="Русский" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="3tcy" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
|
||||||
<TextBlock Text="andBroz" />
|
|
||||||
<TextBlock Text="alexneonwithglue" />
|
|
||||||
<TextBlock Text="AnonymousDudeLOL123" />
|
|
||||||
<TextBlock Text="aperna_of_the_ticks" />
|
|
||||||
<TextBlock Text="arsenijveselov77" />
|
|
||||||
<TextBlock Text="Art3mLapa" />
|
|
||||||
<TextBlock Text="cherkash" />
|
|
||||||
<TextBlock Text="cub-has-injected" />
|
|
||||||
<TextBlock Text="dallyuser" />
|
|
||||||
<TextBlock Text="Dr1mG" />
|
|
||||||
<TextBlock Text="Externalkinetics" />
|
|
||||||
<TextBlock Text="fxstyxx" />
|
|
||||||
<TextBlock Text="Gustodd4202" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
|
||||||
<TextBlock Text="harababura" />
|
|
||||||
<TextBlock Text="ImperialRhyme" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
|
||||||
<TextBlock Text="IStoleYourCheese" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
|
||||||
<TextBlock Text="khat7" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
|
||||||
<TextBlock Text="kostyan" />
|
|
||||||
<TextBlock Text="Maks" />
|
|
||||||
<TextBlock Text="niktoyou" />
|
|
||||||
<TextBlock Text="nurgament2" />
|
|
||||||
<TextBlock Text="poflexim" />
|
|
||||||
<TextBlock Text="Prob1rka" />
|
|
||||||
<TextBlock Text="Provo" />
|
|
||||||
<TextBlock Text="Quenevelly" />
|
|
||||||
<TextBlock Text="sally13249" />
|
|
||||||
<TextBlock Text="simmon8800" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
|
||||||
<TextBlock Text="Skylan031" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
|
||||||
<TextBlock Text="Spuffio" />
|
|
||||||
<TextBlock Text="StraiF" />
|
|
||||||
<TextBlock Text="StrayCatSimb" />
|
|
||||||
<TextBlock Text="Voxel" />
|
|
||||||
<TextBlock Text="XonaShera" Foreground="{DynamicResource SystemFillColorCriticalBrush}" />
|
|
||||||
<TextBlock Text="Ziio123" />
|
|
||||||
<TextBlock Text="zor9na90000" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="3">
|
|
||||||
<TextBlock Text="עברית" FontSize="16" FontWeight="Medium">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="1cur1" />
|
|
||||||
<TextBlock Text="ilan0098" />
|
|
||||||
<TextBlock Text="koerga" />
|
|
||||||
<TextBlock Text="Sezei" />
|
|
||||||
|
|
||||||
<TextBlock Text="العربية" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="busguesjshbahsj" />
|
|
||||||
<TextBlock Text="cq2i" />
|
|
||||||
<TextBlock Text="mmiky" />
|
|
||||||
<TextBlock Text="mostafagamingx1" />
|
|
||||||
<TextBlock Text="RoRed" />
|
|
||||||
<TextBlock Text="Sakupen" />
|
|
||||||
<TextBlock Text="streoic" />
|
|
||||||
<TextBlock Text="uvq18" />
|
|
||||||
<TextBlock Text="wyfast" />
|
|
||||||
<TextBlock Text="Zida" />
|
|
||||||
|
|
||||||
<TextBlock Text="বাংলা" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="Arnian" />
|
|
||||||
<TextBlock Text="Hydrated_panda" />
|
|
||||||
<TextBlock Text="marathedonroblox" />
|
|
||||||
<TextBlock Text="red_hi" />
|
|
||||||
|
|
||||||
<TextBlock Text="ภาษาไทย" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="._bonus_." />
|
|
||||||
<TextBlock Text="marc15772" />
|
|
||||||
<TextBlock Text="arthurwagon" />
|
|
||||||
<TextBlock Text="Sem1z" />
|
|
||||||
<TextBlock Text="xAom" />
|
|
||||||
|
|
||||||
<TextBlock Text="한국어" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="ADVI50R" />
|
|
||||||
<TextBlock Text="asd123456fghqwerty" />
|
|
||||||
<TextBlock Text="bacon1295" />
|
|
||||||
<TextBlock Text="NightPlay" />
|
|
||||||
|
|
||||||
<TextBlock Text="中文 (简体)" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="14TQD" />
|
|
||||||
<TextBlock Text="Aling00" />
|
|
||||||
<TextBlock Text="Clock" />
|
|
||||||
<TextBlock Text="ERSN_CERROR" />
|
|
||||||
<TextBlock Text="Kirxvil" />
|
|
||||||
<TextBlock Text="Typel" />
|
|
||||||
<TextBlock Text="yuhaodatt" />
|
|
||||||
|
|
||||||
<TextBlock Text="中文 (廣東話)" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="henrychu1125" />
|
|
||||||
<TextBlock Text="kitzure" />
|
|
||||||
<TextBlock Text="Kimina898" />
|
|
||||||
<TextBlock Text="shhh_op" />
|
|
||||||
|
|
||||||
<TextBlock Text="中文 (繁體)" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="14TQD" />
|
|
||||||
<TextBlock Text="DXuwu" />
|
|
||||||
<TextBlock Text="kitzure" />
|
|
||||||
<TextBlock Text="Kimina898" />
|
|
||||||
|
|
||||||
<TextBlock Text="日本語" FontSize="16" FontWeight="Medium" Margin="0,16,0,0">
|
|
||||||
<TextBlock.Foreground>
|
|
||||||
<SolidColorBrush Color="{DynamicResource SystemAccentColorSecondary}" />
|
|
||||||
</TextBlock.Foreground>
|
|
||||||
</TextBlock>
|
|
||||||
<TextBlock Text="MintJapan" />
|
|
||||||
<TextBlock Text="pimeja7" />
|
|
||||||
<TextBlock Text="yixhuaa" />
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</controls:Expander>
|
|
||||||
|
|
||||||
<controls:Expander Grid.Row="1" Grid.Column="0" Margin="0,0,4,0" HeaderIcon="Code24" HeaderText="{x:Static resources:Strings.Menu_About_Contributors_Code}" IsExpanded="True">
|
|
||||||
<StackPanel>
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[Matt](https://github.com/bluepilledgreat)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[1011025m](https://github.com/1011025m)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[EasternBloxxer](https://github.com/EasternBloxxer)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[sitiom](https://github.com/sitiom)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[Extravi](https://github.com/Extravi)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[EpixScripts](https://github.com/EpixScripts)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[swatTurret](https://github.com/swatTurret)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[fxeP1](https://github.com/fxeP1)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[Redusofficial](https://github.com/Redusofficial)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[srthMD](https://github.com/srthMD)" />
|
|
||||||
</StackPanel>
|
|
||||||
</controls:Expander>
|
|
||||||
|
|
||||||
<controls:Expander Grid.Row="1" Grid.Column="1" Margin="4,0,4,0" HeaderIcon="AppsAddIn28" HeaderText="{x:Static resources:Strings.Menu_About_Contributors_FeatureIdeas}" IsExpanded="True">
|
|
||||||
<StackPanel>
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[he3als](https://github.com/he3als)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[NikSavchenk0](https://github.com/NikSavchenk0)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[carter0nline](https://github.com/carter0nline)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[lolmanurfunny](https://github.com/lolmanurfunny)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[MehKako](https://github.com/MehKako)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[EpixScripts](https://github.com/EpixScripts)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[knivesofeylis](https://github.com/knivesofeylis)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[sha4owz](https://github.com/sha4owz)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[DaMlgNoodle](https://github.com/DaMlgNoodle)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[nakoyasha](https://github.com/nakoyasha)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[exurd](https://github.com/exurd)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[0xFE0F](https://github.com/0xFE0F)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[Tezos](https://github.com/GoingCrazyDude)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[CfwSky](https://www.roblox.com/users/129425241/profile)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[ruubloo](https://www.roblox.com/users/158082266/profile)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[toyoda165](https://www.roblox.com/users/923416649/profile)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[ShadowCodeX](https://github.com/ShadowCodeX-debug)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[cub-has-injected](https://github.com/cub-has-injected)" />
|
|
||||||
</StackPanel>
|
|
||||||
</controls:Expander>
|
|
||||||
|
|
||||||
<controls:Expander Grid.Row="1" Grid.Column="2" Margin="4,0,0,0" HeaderIcon="Heart16" HeaderText="{x:Static resources:Strings.Menu_About_Contributors_SpecialThanks}" IsExpanded="True">
|
|
||||||
<StackPanel>
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[MaximumADHD](https://github.com/MaximumADHD)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[Multako](https://www.roblox.com/users/2485612194/profile)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[axstin](https://github.com/axstin)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[taskmanager](https://github.com/Mantaraix)" />
|
|
||||||
<controls:MarkdownTextBlock MarkdownText="[apprehensions](https://github.com/apprehensions)" />
|
|
||||||
</StackPanel>
|
|
||||||
</controls:Expander>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<TextBlock Text="{x:Static resources:Strings.Menu_About_Licenses}" FontWeight="Medium" FontSize="20" Margin="0,16,0,0" />
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<ui:CardAction Grid.Row="0" Grid.Column="0" Margin="0,8,8,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/blob/main/LICENSE">
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock FontSize="14" Text="Bloxstrap" />
|
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</StackPanel>
|
|
||||||
</ui:CardAction>
|
|
||||||
<ui:CardAction Grid.Row="0" Grid.Column="1" Margin="0,8,8,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/lepoco/wpfui/blob/main/LICENSE">
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock FontSize="14" Text="WPF-UI" />
|
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</StackPanel>
|
|
||||||
</ui:CardAction>
|
|
||||||
<ui:CardAction Grid.Row="0" Grid.Column="2" Margin="0,8,0,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/securifybv/ShellLink/blob/master/LICENSE.txt">
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock FontSize="14" Text="ShellLink" />
|
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</StackPanel>
|
|
||||||
</ui:CardAction>
|
|
||||||
<ui:CardAction Grid.Row="1" Grid.Column="0" Margin="0,8,8,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/Lachee/discord-rpc-csharp/blob/master/LICENSE">
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock FontSize="14" Text="DiscordRPC" />
|
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</StackPanel>
|
|
||||||
</ui:CardAction>
|
|
||||||
<ui:CardAction Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,8,0,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/MaximumADHD/Roblox-Studio-Mod-Manager/blob/main/LICENSE">
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock FontSize="13" Text="Roblox Studio Mod Manager" />
|
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</StackPanel>
|
|
||||||
</ui:CardAction>
|
|
||||||
<ui:CardAction Grid.Row="2" Grid.Column="0" Margin="0,8,8,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/icsharpcode/SharpZipLib/blob/master/LICENSE.txt">
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock FontSize="13" Text="SharpZipLib" />
|
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_MIT}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</StackPanel>
|
|
||||||
</ui:CardAction>
|
|
||||||
<ui:CardAction Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,8,0,0" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/xoofx/markdig/blob/master/license.txt">
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock FontSize="14" Text="Markdig" />
|
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="{x:Static resources:Strings.Menu_About_Licenses_BSD2}" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</StackPanel>
|
|
||||||
</ui:CardAction>
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
</ui:UiPage>
|
|
@ -137,7 +137,7 @@ namespace Bloxstrap.UI.Elements.Settings.Pages
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Frontend.ShowMessageBox(Bloxstrap.Resources.Strings.Menu_FastFlagEditor_AlreadyExists, MessageBoxImage.Information);
|
Frontend.ShowMessageBox(Strings.Menu_FastFlagEditor_AlreadyExists, MessageBoxImage.Information);
|
||||||
|
|
||||||
bool refresh = false;
|
bool refresh = false;
|
||||||
|
|
||||||
@ -175,7 +175,14 @@ namespace Bloxstrap.UI.Elements.Settings.Pages
|
|||||||
json = '{' + json;
|
json = '{' + json;
|
||||||
|
|
||||||
if (!json.EndsWith('}'))
|
if (!json.EndsWith('}'))
|
||||||
|
{
|
||||||
|
int lastIndex = json.LastIndexOf('}');
|
||||||
|
|
||||||
|
if (lastIndex == -1)
|
||||||
json += '}';
|
json += '}';
|
||||||
|
else
|
||||||
|
json = json.Substring(0, lastIndex+1);
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -193,7 +200,7 @@ namespace Bloxstrap.UI.Elements.Settings.Pages
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Frontend.ShowMessageBox(
|
Frontend.ShowMessageBox(
|
||||||
String.Format(Bloxstrap.Resources.Strings.Menu_FastFlagEditor_InvalidJSON, ex.Message),
|
String.Format(Strings.Menu_FastFlagEditor_InvalidJSON, ex.Message),
|
||||||
MessageBoxImage.Error
|
MessageBoxImage.Error
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -205,7 +212,7 @@ namespace Bloxstrap.UI.Elements.Settings.Pages
|
|||||||
if (list.Count > 16)
|
if (list.Count > 16)
|
||||||
{
|
{
|
||||||
var result = Frontend.ShowMessageBox(
|
var result = Frontend.ShowMessageBox(
|
||||||
Bloxstrap.Resources.Strings.Menu_FastFlagEditor_LargeConfig,
|
Strings.Menu_FastFlagEditor_LargeConfig,
|
||||||
MessageBoxImage.Warning,
|
MessageBoxImage.Warning,
|
||||||
MessageBoxButton.YesNo
|
MessageBoxButton.YesNo
|
||||||
);
|
);
|
||||||
@ -222,7 +229,7 @@ namespace Bloxstrap.UI.Elements.Settings.Pages
|
|||||||
int count = conflictingFlags.Count();
|
int count = conflictingFlags.Count();
|
||||||
|
|
||||||
string message = String.Format(
|
string message = String.Format(
|
||||||
Bloxstrap.Resources.Strings.Menu_FastFlagEditor_ConflictingImport,
|
Strings.Menu_FastFlagEditor_ConflictingImport,
|
||||||
count,
|
count,
|
||||||
String.Join(", ", conflictingFlags.Take(25))
|
String.Join(", ", conflictingFlags.Take(25))
|
||||||
);
|
);
|
||||||
@ -263,16 +270,16 @@ namespace Bloxstrap.UI.Elements.Settings.Pages
|
|||||||
string errorMessage = "";
|
string errorMessage = "";
|
||||||
|
|
||||||
if (!_validPrefixes.Any(name.StartsWith))
|
if (!_validPrefixes.Any(name.StartsWith))
|
||||||
errorMessage = Bloxstrap.Resources.Strings.Menu_FastFlagEditor_InvalidPrefix;
|
errorMessage = Strings.Menu_FastFlagEditor_InvalidPrefix;
|
||||||
else if (!name.All(x => char.IsLetterOrDigit(x) || x == '_'))
|
else if (!name.All(x => char.IsLetterOrDigit(x) || x == '_'))
|
||||||
errorMessage = Bloxstrap.Resources.Strings.Menu_FastFlagEditor_InvalidCharacter;
|
errorMessage = Strings.Menu_FastFlagEditor_InvalidCharacter;
|
||||||
|
|
||||||
if (name.EndsWith("_PlaceFilter") || name.EndsWith("_DataCenterFilter"))
|
if (name.EndsWith("_PlaceFilter") || name.EndsWith("_DataCenterFilter"))
|
||||||
errorMessage = !ValidateFilter(name, value) ? Bloxstrap.Resources.Strings.Menu_FastFlagEditor_InvalidPlaceFilter : "";
|
errorMessage = !ValidateFilter(name, value) ? Strings.Menu_FastFlagEditor_InvalidPlaceFilter : "";
|
||||||
else if ((name.StartsWith("FInt") || name.StartsWith("DFInt")) && !Int32.TryParse(value, out _))
|
else if ((name.StartsWith("FInt") || name.StartsWith("DFInt")) && !Int32.TryParse(value, out _))
|
||||||
errorMessage = Bloxstrap.Resources.Strings.Menu_FastFlagEditor_InvalidNumberValue;
|
errorMessage = Strings.Menu_FastFlagEditor_InvalidNumberValue;
|
||||||
else if ((name.StartsWith("FFlag") || name.StartsWith("DFFlag")) && lowerValue != "true" && lowerValue != "false")
|
else if ((name.StartsWith("FFlag") || name.StartsWith("DFFlag")) && lowerValue != "true" && lowerValue != "false")
|
||||||
errorMessage = Bloxstrap.Resources.Strings.Menu_FastFlagEditor_InvalidBoolValue;
|
errorMessage = Strings.Menu_FastFlagEditor_InvalidBoolValue;
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(errorMessage))
|
if (!String.IsNullOrEmpty(errorMessage))
|
||||||
{
|
{
|
||||||
@ -319,7 +326,7 @@ namespace Bloxstrap.UI.Elements.Settings.Pages
|
|||||||
|
|
||||||
if (App.FastFlags.GetValue(newName) is not null)
|
if (App.FastFlags.GetValue(newName) is not null)
|
||||||
{
|
{
|
||||||
Frontend.ShowMessageBox(Bloxstrap.Resources.Strings.Menu_FastFlagEditor_AlreadyExists, MessageBoxImage.Information);
|
Frontend.ShowMessageBox(Strings.Menu_FastFlagEditor_AlreadyExists, MessageBoxImage.Information);
|
||||||
e.Cancel = true;
|
e.Cancel = true;
|
||||||
textbox.Text = oldName;
|
textbox.Text = oldName;
|
||||||
return;
|
return;
|
||||||
@ -387,7 +394,7 @@ namespace Bloxstrap.UI.Elements.Settings.Pages
|
|||||||
{
|
{
|
||||||
string json = JsonSerializer.Serialize(App.FastFlags.Prop, new JsonSerializerOptions { WriteIndented = true });
|
string json = JsonSerializer.Serialize(App.FastFlags.Prop, new JsonSerializerOptions { WriteIndented = true });
|
||||||
Clipboard.SetDataObject(json);
|
Clipboard.SetDataObject(json);
|
||||||
Frontend.ShowMessageBox(Bloxstrap.Resources.Strings.Menu_FastFlagEditor_JsonCopiedToClipboard, MessageBoxImage.Information);
|
Frontend.ShowMessageBox(Strings.Menu_FastFlagEditor_JsonCopiedToClipboard, MessageBoxImage.Information);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bloxstrap.Integrations;
|
using Bloxstrap.Integrations;
|
||||||
|
using Bloxstrap.UI.Elements.About;
|
||||||
using Bloxstrap.UI.Elements.ContextMenu;
|
using Bloxstrap.UI.Elements.ContextMenu;
|
||||||
|
|
||||||
namespace Bloxstrap.UI
|
namespace Bloxstrap.UI
|
||||||
@ -10,18 +11,21 @@ namespace Bloxstrap.UI
|
|||||||
private bool _disposing = false;
|
private bool _disposing = false;
|
||||||
|
|
||||||
private readonly System.Windows.Forms.NotifyIcon _notifyIcon;
|
private readonly System.Windows.Forms.NotifyIcon _notifyIcon;
|
||||||
private MenuContainer? _menuContainer;
|
|
||||||
|
|
||||||
private ActivityWatcher? _activityWatcher;
|
private readonly MenuContainer _menuContainer;
|
||||||
private DiscordRichPresence? _richPresenceHandler;
|
|
||||||
private int? _processId;
|
private readonly Watcher _watcher;
|
||||||
|
|
||||||
|
private ActivityWatcher? _activityWatcher => _watcher.ActivityWatcher;
|
||||||
|
|
||||||
EventHandler? _alertClickHandler;
|
EventHandler? _alertClickHandler;
|
||||||
|
|
||||||
public NotifyIconWrapper()
|
public NotifyIconWrapper(Watcher watcher)
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine("NotifyIconWrapper::NotifyIconWrapper", "Initializing notification area icon");
|
App.Logger.WriteLine("NotifyIconWrapper::NotifyIconWrapper", "Initializing notification area icon");
|
||||||
|
|
||||||
|
_watcher = watcher;
|
||||||
|
|
||||||
_notifyIcon = new()
|
_notifyIcon = new()
|
||||||
{
|
{
|
||||||
Icon = Properties.Resources.IconBloxstrap,
|
Icon = Properties.Resources.IconBloxstrap,
|
||||||
@ -30,52 +34,18 @@ namespace Bloxstrap.UI
|
|||||||
};
|
};
|
||||||
|
|
||||||
_notifyIcon.MouseClick += MouseClickEventHandler;
|
_notifyIcon.MouseClick += MouseClickEventHandler;
|
||||||
}
|
|
||||||
|
|
||||||
#region Handler registers
|
|
||||||
public void SetRichPresenceHandler(DiscordRichPresence richPresenceHandler)
|
|
||||||
{
|
|
||||||
if (_richPresenceHandler is not null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_richPresenceHandler = richPresenceHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetActivityWatcher(ActivityWatcher activityWatcher)
|
|
||||||
{
|
|
||||||
if (_activityWatcher is not null)
|
if (_activityWatcher is not null)
|
||||||
return;
|
_activityWatcher.OnGameJoin += OnGameJoin;
|
||||||
|
|
||||||
_activityWatcher = activityWatcher;
|
_menuContainer = new(_watcher);
|
||||||
|
_menuContainer.Show();
|
||||||
if (App.Settings.Prop.ShowServerDetails)
|
|
||||||
_activityWatcher.OnGameJoin += (_, _) => Task.Run(OnGameJoin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetProcessId(int processId)
|
|
||||||
{
|
|
||||||
if (_processId is not null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
_processId = processId;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Context menu
|
#region Context menu
|
||||||
public void InitializeContextMenu()
|
|
||||||
{
|
|
||||||
if (_menuContainer is not null || _disposing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
App.Logger.WriteLine("NotifyIconWrapper::InitializeContextMenu", "Initializing context menu");
|
|
||||||
|
|
||||||
_menuContainer = new(_activityWatcher, _richPresenceHandler, _processId);
|
|
||||||
_menuContainer.ShowDialog();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MouseClickEventHandler(object? sender, System.Windows.Forms.MouseEventArgs e)
|
public void MouseClickEventHandler(object? sender, System.Windows.Forms.MouseEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Button != System.Windows.Forms.MouseButtons.Right || _menuContainer is null)
|
if (e.Button != System.Windows.Forms.MouseButtons.Right)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_menuContainer.Activate();
|
_menuContainer.Activate();
|
||||||
@ -84,9 +54,12 @@ namespace Bloxstrap.UI
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Activity handlers
|
#region Activity handlers
|
||||||
public async void OnGameJoin()
|
public async void OnGameJoin(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
string serverLocation = await _activityWatcher!.GetServerLocation();
|
if (_activityWatcher is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string serverLocation = await _activityWatcher.GetServerLocation();
|
||||||
string title = _activityWatcher.ActivityServerType switch
|
string title = _activityWatcher.ActivityServerType switch
|
||||||
{
|
{
|
||||||
ServerType.Public => Strings.ContextMenu_ServerInformation_Notification_Title_Public,
|
ServerType.Public => Strings.ContextMenu_ServerInformation_Notification_Title_Public,
|
||||||
@ -99,7 +72,7 @@ namespace Bloxstrap.UI
|
|||||||
title,
|
title,
|
||||||
String.Format(Strings.ContextMenu_ServerInformation_Notification_Text, serverLocation),
|
String.Format(Strings.ContextMenu_ServerInformation_Notification_Text, serverLocation),
|
||||||
10,
|
10,
|
||||||
(_, _) => _menuContainer?.ShowServerInformationWindow()
|
(_, _) => _menuContainer.ShowServerInformationWindow()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -151,9 +124,8 @@ namespace Bloxstrap.UI
|
|||||||
|
|
||||||
App.Logger.WriteLine("NotifyIconWrapper::Dispose", "Disposing NotifyIcon");
|
App.Logger.WriteLine("NotifyIconWrapper::Dispose", "Disposing NotifyIcon");
|
||||||
|
|
||||||
_menuContainer?.Dispatcher.Invoke(_menuContainer.Close);
|
_menuContainer.Dispatcher.Invoke(_menuContainer.Close);
|
||||||
_notifyIcon?.Dispose();
|
_notifyIcon.Dispose();
|
||||||
|
|
||||||
|
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
@ -7,20 +7,23 @@ namespace Bloxstrap.UI.ViewModels.ContextMenu
|
|||||||
{
|
{
|
||||||
internal class ServerInformationViewModel : NotifyPropertyChangedViewModel
|
internal class ServerInformationViewModel : NotifyPropertyChangedViewModel
|
||||||
{
|
{
|
||||||
private readonly Window _window;
|
|
||||||
private readonly ActivityWatcher _activityWatcher;
|
private readonly ActivityWatcher _activityWatcher;
|
||||||
|
|
||||||
public string InstanceId => _activityWatcher.ActivityJobId;
|
public string InstanceId => _activityWatcher.ActivityJobId;
|
||||||
public string ServerType => Resources.Strings.ResourceManager.GetStringSafe($"Enums.ServerType.{_activityWatcher.ActivityServerType}");
|
|
||||||
public string ServerLocation { get; private set; } = Resources.Strings.ContextMenu_ServerInformation_Loading;
|
public string ServerType => Strings.ResourceManager.GetStringSafe($"Enums.ServerType.{_activityWatcher.ActivityServerType}");
|
||||||
|
|
||||||
|
public string ServerLocation { get; private set; } = Strings.ContextMenu_ServerInformation_Loading;
|
||||||
|
|
||||||
public ICommand CopyInstanceIdCommand => new RelayCommand(CopyInstanceId);
|
public ICommand CopyInstanceIdCommand => new RelayCommand(CopyInstanceId);
|
||||||
public ICommand CloseWindowCommand => new RelayCommand(_window.Close);
|
|
||||||
|
|
||||||
public ServerInformationViewModel(Window window, ActivityWatcher activityWatcher)
|
public ICommand CloseWindowCommand => new RelayCommand(RequestClose);
|
||||||
|
|
||||||
|
public EventHandler? RequestCloseEvent;
|
||||||
|
|
||||||
|
public ServerInformationViewModel(Watcher watcher)
|
||||||
{
|
{
|
||||||
_window = window;
|
_activityWatcher = watcher.ActivityWatcher!;
|
||||||
_activityWatcher = activityWatcher;
|
|
||||||
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -30,5 +33,7 @@ namespace Bloxstrap.UI.ViewModels.ContextMenu
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void CopyInstanceId() => Clipboard.SetDataObject(InstanceId);
|
private void CopyInstanceId() => Clipboard.SetDataObject(InstanceId);
|
||||||
|
|
||||||
|
private void RequestClose() => RequestCloseEvent?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
using Bloxstrap.Resources;
|
using Bloxstrap.UI.Elements.About;
|
||||||
|
|
||||||
namespace Bloxstrap.UI.ViewModels.Installer
|
namespace Bloxstrap.UI.ViewModels.Installer
|
||||||
{
|
{
|
||||||
@ -14,10 +14,14 @@ namespace Bloxstrap.UI.ViewModels.Installer
|
|||||||
|
|
||||||
public ICommand LaunchRobloxCommand => new RelayCommand(LaunchRoblox);
|
public ICommand LaunchRobloxCommand => new RelayCommand(LaunchRoblox);
|
||||||
|
|
||||||
|
public ICommand LaunchAboutCommand => new RelayCommand(LaunchAbout);
|
||||||
|
|
||||||
public event EventHandler<NextAction>? CloseWindowRequest;
|
public event EventHandler<NextAction>? CloseWindowRequest;
|
||||||
|
|
||||||
private void LaunchSettings() => CloseWindowRequest?.Invoke(this, NextAction.LaunchSettings);
|
private void LaunchSettings() => CloseWindowRequest?.Invoke(this, NextAction.LaunchSettings);
|
||||||
|
|
||||||
private void LaunchRoblox() => CloseWindowRequest?.Invoke(this, NextAction.LaunchRoblox);
|
private void LaunchRoblox() => CloseWindowRequest?.Invoke(this, NextAction.LaunchRoblox);
|
||||||
|
|
||||||
|
private void LaunchAbout() => new MainWindow().ShowDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,14 +4,14 @@ namespace Bloxstrap.UI.ViewModels.Settings
|
|||||||
{
|
{
|
||||||
public class AboutViewModel
|
public class AboutViewModel
|
||||||
{
|
{
|
||||||
public string Version => string.Format(Resources.Strings.Menu_About_Version, App.Version);
|
public string Version => string.Format(Strings.Menu_About_Version, App.Version);
|
||||||
|
|
||||||
public BuildMetadataAttribute BuildMetadata => App.BuildMetadata;
|
public BuildMetadataAttribute BuildMetadata => App.BuildMetadata;
|
||||||
|
|
||||||
public string BuildTimestamp => BuildMetadata.Timestamp.ToFriendlyString();
|
public string BuildTimestamp => BuildMetadata.Timestamp.ToFriendlyString();
|
||||||
public string BuildCommitHashUrl => $"https://github.com/{App.ProjectRepository}/commit/{BuildMetadata.CommitHash}";
|
public string BuildCommitHashUrl => $"https://github.com/{App.ProjectRepository}/commit/{BuildMetadata.CommitHash}";
|
||||||
|
|
||||||
public Visibility BuildInformationVisibility => BuildMetadata.CommitRef.StartsWith("tag") ? Visibility.Collapsed : Visibility.Visible;
|
public Visibility BuildInformationVisibility => App.IsProductionBuild ? Visibility.Collapsed : Visibility.Visible;
|
||||||
public Visibility BuildCommitVisibility => string.IsNullOrEmpty(BuildMetadata.CommitHash) ? Visibility.Collapsed : Visibility.Visible;
|
public Visibility BuildCommitVisibility => App.IsActionBuild ? Visibility.Visible : Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,11 +87,7 @@ namespace Bloxstrap.UI.ViewModels.Settings
|
|||||||
public RenderingMode SelectedRenderingMode
|
public RenderingMode SelectedRenderingMode
|
||||||
{
|
{
|
||||||
get => App.FastFlags.GetPresetEnum(RenderingModes, "Rendering.Mode", "True");
|
get => App.FastFlags.GetPresetEnum(RenderingModes, "Rendering.Mode", "True");
|
||||||
set
|
set => App.FastFlags.SetPresetEnum("Rendering.Mode", RenderingModes[value], "True");
|
||||||
{
|
|
||||||
App.FastFlags.SetPresetEnum("Rendering.Mode", RenderingModes[value], "True");
|
|
||||||
App.FastFlags.CheckManualFullscreenPreset();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool FixDisplayScaling
|
public bool FixDisplayScaling
|
||||||
|
@ -1,15 +1,25 @@
|
|||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using Bloxstrap.UI.Elements.About;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
namespace Bloxstrap.UI.ViewModels.Settings
|
namespace Bloxstrap.UI.ViewModels.Settings
|
||||||
{
|
{
|
||||||
public class MainWindowViewModel : NotifyPropertyChangedViewModel
|
public class MainWindowViewModel : NotifyPropertyChangedViewModel
|
||||||
{
|
{
|
||||||
|
public ICommand OpenAboutCommand => new RelayCommand(OpenAbout);
|
||||||
|
|
||||||
public ICommand SaveSettingsCommand => new RelayCommand(SaveSettings);
|
public ICommand SaveSettingsCommand => new RelayCommand(SaveSettings);
|
||||||
|
|
||||||
|
public ICommand CloseWindowCommand => new RelayCommand(CloseWindow);
|
||||||
|
|
||||||
public EventHandler? RequestSaveNoticeEvent;
|
public EventHandler? RequestSaveNoticeEvent;
|
||||||
|
|
||||||
|
public EventHandler? RequestCloseWindowEvent;
|
||||||
|
|
||||||
|
private void OpenAbout() => new MainWindow().ShowDialog();
|
||||||
|
|
||||||
|
private void CloseWindow() => RequestCloseWindowEvent?.Invoke(this, EventArgs.Empty);
|
||||||
|
|
||||||
private void SaveSettings()
|
private void SaveSettings()
|
||||||
{
|
{
|
||||||
const string LOG_IDENT = "MainWindowViewModel::SaveSettings";
|
const string LOG_IDENT = "MainWindowViewModel::SaveSettings";
|
||||||
@ -31,7 +41,7 @@ namespace Bloxstrap.UI.ViewModels.Settings
|
|||||||
|
|
||||||
App.PendingSettingTasks.Clear();
|
App.PendingSettingTasks.Clear();
|
||||||
|
|
||||||
RequestSaveNoticeEvent?.Invoke(this, new EventArgs());
|
RequestSaveNoticeEvent?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
147
Bloxstrap/Watcher.cs
Normal file
147
Bloxstrap/Watcher.cs
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
using Bloxstrap.Integrations;
|
||||||
|
using System.CodeDom;
|
||||||
|
using System.Security.Permissions;
|
||||||
|
|
||||||
|
namespace Bloxstrap
|
||||||
|
{
|
||||||
|
public class Watcher : IDisposable
|
||||||
|
{
|
||||||
|
private int _gameClientPid = 0;
|
||||||
|
|
||||||
|
private readonly InterProcessLock _lock = new("Watcher");
|
||||||
|
|
||||||
|
private readonly List<int> _autoclosePids = new();
|
||||||
|
|
||||||
|
private readonly NotifyIconWrapper? _notifyIcon;
|
||||||
|
|
||||||
|
public readonly ActivityWatcher? ActivityWatcher;
|
||||||
|
|
||||||
|
public readonly DiscordRichPresence? RichPresence;
|
||||||
|
|
||||||
|
public Watcher()
|
||||||
|
{
|
||||||
|
const string LOG_IDENT = "Watcher";
|
||||||
|
|
||||||
|
if (!_lock.IsAcquired)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Watcher instance already exists");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string? watcherData = App.LaunchSettings.WatcherFlag.Data;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
if (String.IsNullOrEmpty(watcherData))
|
||||||
|
{
|
||||||
|
string path = Path.Combine(Paths.Versions, App.State.Prop.PlayerVersionGuid, "RobloxPlayerBeta.exe");
|
||||||
|
using var gameClientProcess = Process.Start(path);
|
||||||
|
_gameClientPid = gameClientProcess.Id;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (String.IsNullOrEmpty(watcherData))
|
||||||
|
throw new Exception("Watcher data not specified");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!String.IsNullOrEmpty(watcherData) && _gameClientPid == 0)
|
||||||
|
{
|
||||||
|
var split = watcherData.Split(';');
|
||||||
|
|
||||||
|
if (split.Length == 0)
|
||||||
|
_ = int.TryParse(watcherData, out _gameClientPid);
|
||||||
|
|
||||||
|
if (split.Length >= 1)
|
||||||
|
_ = int.TryParse(split[0], out _gameClientPid);
|
||||||
|
|
||||||
|
if (split.Length >= 2)
|
||||||
|
{
|
||||||
|
foreach (string strPid in split[0].Split(';'))
|
||||||
|
{
|
||||||
|
if (int.TryParse(strPid, out int pid) && pid != 0)
|
||||||
|
_autoclosePids.Add(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_gameClientPid == 0)
|
||||||
|
throw new Exception("Watcher data is invalid");
|
||||||
|
|
||||||
|
if (App.Settings.Prop.EnableActivityTracking)
|
||||||
|
{
|
||||||
|
ActivityWatcher = new();
|
||||||
|
|
||||||
|
if (App.Settings.Prop.UseDisableAppPatch)
|
||||||
|
{
|
||||||
|
ActivityWatcher.OnAppClose += (_, _) =>
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Received desktop app exit, closing Roblox");
|
||||||
|
using var process = Process.GetProcessById(_gameClientPid);
|
||||||
|
process.CloseMainWindow();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (App.Settings.Prop.UseDiscordRichPresence)
|
||||||
|
RichPresence = new(ActivityWatcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
_notifyIcon = new(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void KillRobloxProcess() => KillProcess(_gameClientPid);
|
||||||
|
|
||||||
|
public void KillProcess(int pid)
|
||||||
|
{
|
||||||
|
using var process = Process.GetProcessById(pid);
|
||||||
|
|
||||||
|
App.Logger.WriteLine("Watcher::KillProcess", $"Killing process '{process.ProcessName}' (PID {process.Id})");
|
||||||
|
|
||||||
|
if (process.HasExited)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine("Watcher::KillProcess", $"PID {process.Id} has already exited");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.Kill();
|
||||||
|
process.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CloseProcess(int pid)
|
||||||
|
{
|
||||||
|
using var process = Process.GetProcessById(pid);
|
||||||
|
|
||||||
|
App.Logger.WriteLine("Watcher::CloseProcess", $"Closing process '{process.ProcessName}' (PID {process.Id})");
|
||||||
|
|
||||||
|
if (process.HasExited)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine("Watcher::CloseProcess", $"PID {process.Id} has already exited");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.CloseMainWindow();
|
||||||
|
process.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Run()
|
||||||
|
{
|
||||||
|
if (!_lock.IsAcquired)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ActivityWatcher?.Start();
|
||||||
|
|
||||||
|
while (Utilities.GetProcessesSafe().Any(x => x.Id == _gameClientPid))
|
||||||
|
await Task.Delay(1000);
|
||||||
|
|
||||||
|
foreach (int pid in _autoclosePids)
|
||||||
|
CloseProcess(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine("Watcher::Dispose", "Disposing Watcher");
|
||||||
|
|
||||||
|
_notifyIcon?.Dispose();
|
||||||
|
RichPresence?.Dispose();
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
37
README.md
37
README.md
@ -10,14 +10,33 @@
|
|||||||
[](https://discord.gg/nKjV3mGq6R)
|
[](https://discord.gg/nKjV3mGq6R)
|
||||||
[](https://media.tenor.com/FIkSGbGycmAAAAAd/manly-roblox.gif)
|
[](https://media.tenor.com/FIkSGbGycmAAAAAd/manly-roblox.gif)
|
||||||
|
|
||||||
This is a drop-in replacement for the standard Roblox bootstrapper, providing additional useful features and improvements. Nothing more, nothing less.
|
Bloxstrap is a third-party replacement for the standard Roblox bootstrapper, providing additional useful features and improvements.
|
||||||
|
|
||||||
This does not touch or modify the game client itself, it's really just a launcher. So don't worry, there's [no risk of being banned](https://github.com/pizzaboxer/bloxstrap/wiki/Why-it%27s-not-reasonably-possible-for-you-to-be-banned-by-Bloxstrap) for using this.
|
Running into a problem or need help with something? [Check out the Wiki](https://github.com/pizzaboxer/bloxstrap/wiki). If you can't find anything, or would like to suggest something, please [submit an issue](https://github.com/pizzaboxer/bloxstrap/issues).
|
||||||
|
|
||||||
Running into a problem or need help with something? [Check out the Wiki](https://github.com/pizzaboxer/bloxstrap/wiki). If you can't find anything, or would like to suggest something, please [submit an issue](https://github.com/pizzaboxer/bloxstrap/issues) or report it in our [Discord server](https://discord.gg/nKjV3mGq6R).
|
|
||||||
|
|
||||||
Bloxstrap is only supported for PCs running Windows.
|
Bloxstrap is only supported for PCs running Windows.
|
||||||
|
|
||||||
|
## Frequently Asked Questions
|
||||||
|
|
||||||
|
**Q: Is this malware?**
|
||||||
|
|
||||||
|
**A:** No. The source code here is viewable to all, and it'd be impossible for us to slip anything malicious into the downloads without anyone noticing. Just be sure you're downloading it from an official source. The only two official sources are this GitHub repository and [bloxstrap.pizzaboxer.xyz](https://bloxstrap.pizzaboxer.xyz).
|
||||||
|
|
||||||
|
**Q: Can using this get me banned?**
|
||||||
|
|
||||||
|
**A:** No, it shouldn't. Bloxstrap doesn't interact with the Roblox client in the same way that exploits do. [Read more about that here.](https://github.com/pizzaboxer/bloxstrap/wiki/Why-it's-not-reasonably-possible-for-you-to-be-banned-by-Bloxstrap)
|
||||||
|
|
||||||
|
**Q: Why was multi-instance launching removed?**
|
||||||
|
|
||||||
|
**A:** It was removed starting with v2.6.0 for the [reasons stated here](https://github.com/pizzaboxer/bloxstrap/wiki/Plans-to-remove-multi%E2%80%90instance-launching-from-Bloxstrap). It may be added back in the future when there are less issues with doing so.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- Hassle-free Discord Rich Presence to let your friends know what you're playing at a glance
|
||||||
|
- Simple support for modding of content files for customizability (death sound, mouse cursor, etc)
|
||||||
|
- See where your server is geographically located (courtesy of [ipinfo.io](https://ipinfo.io))
|
||||||
|
- Ability to configure graphics fidelity and UI experience
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
Download the [latest release of Bloxstrap](https://github.com/pizzaboxer/bloxstrap/releases/latest), and run it. Configure your preferences if needed, and install. That's about it!
|
Download the [latest release of Bloxstrap](https://github.com/pizzaboxer/bloxstrap/releases/latest), and run it. Configure your preferences if needed, and install. That's about it!
|
||||||
|
|
||||||
@ -32,16 +51,6 @@ It's not unlikely that Windows Smartscreen will show a popup when you run Bloxst
|
|||||||
|
|
||||||
Once installed, Bloxstrap is added to your Start Menu, where you can access the menu and reconfigure your preferences if needed.
|
Once installed, Bloxstrap is added to your Start Menu, where you can access the menu and reconfigure your preferences if needed.
|
||||||
|
|
||||||
## Features
|
|
||||||
Here's some of the features that Bloxstrap provides over the stock Roblox bootstrapper:
|
|
||||||
|
|
||||||
* Persistent file modifications, includes re-adding the old death sound!
|
|
||||||
* Painless and seamless support for Discord Rich Presence
|
|
||||||
* A customizable launcher look
|
|
||||||
* Lets you see what region your current server is located in
|
|
||||||
|
|
||||||
All the available features are browsable through the Bloxstrap menu.
|
|
||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
<p float="left">
|
<p float="left">
|
||||||
|
Loading…
Reference in New Issue
Block a user