mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-06-23 23:00:23 -07:00
Merge branch 'main' of https://github.com/pizzaboxer/bloxstrap
This commit is contained in:
commit
bd2d8e58f6
5
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
5
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -7,9 +7,10 @@ body:
|
|||||||
value: |
|
value: |
|
||||||
### **Preliminary instructions**
|
### **Preliminary instructions**
|
||||||
- Before opening an issue, please [check the Wiki first](https://github.com/pizzaboxer/bloxstrap/wiki/) to see if your problem has been addressed there.
|
- Before opening an issue, please [check the Wiki first](https://github.com/pizzaboxer/bloxstrap/wiki/) to see if your problem has been addressed there.
|
||||||
- **[Read this if Roblox is crashing or not launching](https://github.com/pizzaboxer/bloxstrap/wiki/Roblox-crashes-or-does-not-launch).** Only open an issue for it if this does not address your problem.
|
- If it isn't, please confirm which pages that you read that were relevant to your issue.
|
||||||
|
- 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.
|
||||||
- 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.
|
||||||
- If your problem is with Roblox itself, [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 only happens with Bloxstrap, as anything else is out of my control.
|
|
||||||
- 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
|
||||||
|
8
.github/workflows/ci.yml
vendored
8
.github/workflows/ci.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
|
|
||||||
- uses: actions/setup-dotnet@v3
|
- uses: actions/setup-dotnet@v4
|
||||||
with:
|
with:
|
||||||
dotnet-version: '6.0.x'
|
dotnet-version: '6.0.x'
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ jobs:
|
|||||||
run: dotnet publish -p:PublishSingleFile=true -p:CommitHash=${{ github.sha }} -p:CommitRef=${{ github.ref_type }}/${{ github.ref_name }} -r win-x64 -c ${{ matrix.configuration }} --self-contained false .\Bloxstrap\Bloxstrap.csproj
|
run: dotnet publish -p:PublishSingleFile=true -p:CommitHash=${{ github.sha }} -p:CommitRef=${{ github.ref_type }}/${{ github.ref_name }} -r win-x64 -c ${{ matrix.configuration }} --self-contained false .\Bloxstrap\Bloxstrap.csproj
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Bloxstrap (${{ matrix.configuration }})
|
name: Bloxstrap (${{ matrix.configuration }})
|
||||||
path: |
|
path: |
|
||||||
@ -41,7 +41,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Download x64 release artifact
|
- name: Download x64 release artifact
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: Bloxstrap (Release)
|
name: Bloxstrap (Release)
|
||||||
path: x64
|
path: x64
|
||||||
@ -51,7 +51,7 @@ jobs:
|
|||||||
mv x64/Bloxstrap.exe Bloxstrap-${{ github.ref_name }}.exe
|
mv x64/Bloxstrap.exe Bloxstrap-${{ github.ref_name }}.exe
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
draft: true
|
draft: true
|
||||||
files: |
|
files: |
|
||||||
|
@ -27,12 +27,7 @@ namespace Bloxstrap
|
|||||||
public static bool IsSetupComplete { get; set; } = true;
|
public static bool IsSetupComplete { get; set; } = true;
|
||||||
public static bool IsFirstRun { get; set; } = true;
|
public static bool IsFirstRun { get; set; } = true;
|
||||||
|
|
||||||
public static bool IsQuiet { get; private set; } = false;
|
public static LaunchSettings LaunchSettings { get; private set; } = null!;
|
||||||
public static bool IsUninstall { get; private set; } = false;
|
|
||||||
public static bool IsNoLaunch { get; private set; } = false;
|
|
||||||
public static bool IsUpgrade { get; private set; } = false;
|
|
||||||
public static bool IsMenuLaunch { get; private set; } = false;
|
|
||||||
public static string[] LaunchArgs { get; private set; } = null!;
|
|
||||||
|
|
||||||
public static BuildMetadataAttribute BuildMetadata = Assembly.GetExecutingAssembly().GetCustomAttribute<BuildMetadataAttribute>()!;
|
public static BuildMetadataAttribute BuildMetadata = Assembly.GetExecutingAssembly().GetCustomAttribute<BuildMetadataAttribute>()!;
|
||||||
public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2];
|
public static string Version = Assembly.GetExecutingAssembly().GetName().Version!.ToString()[..^2];
|
||||||
@ -96,13 +91,22 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
_showingExceptionDialog = true;
|
_showingExceptionDialog = true;
|
||||||
|
|
||||||
if (!IsQuiet)
|
if (!LaunchSettings.IsQuiet)
|
||||||
Frontend.ShowExceptionDialog(exception);
|
Frontend.ShowExceptionDialog(exception);
|
||||||
|
|
||||||
Terminate(ErrorCode.ERROR_INSTALL_FAILURE);
|
Terminate(ErrorCode.ERROR_INSTALL_FAILURE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void StartupFinished()
|
||||||
|
{
|
||||||
|
const string LOG_IDENT = "App::StartupFinished";
|
||||||
|
|
||||||
|
Logger.WriteLine(LOG_IDENT, "Successfully reached end of main thread. Terminating...");
|
||||||
|
|
||||||
|
Terminate();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnStartup(StartupEventArgs e)
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
{
|
{
|
||||||
const string LOG_IDENT = "App::OnStartup";
|
const string LOG_IDENT = "App::OnStartup";
|
||||||
@ -122,47 +126,10 @@ namespace Bloxstrap
|
|||||||
// see https://aka.ms/applicationconfiguration.
|
// see https://aka.ms/applicationconfiguration.
|
||||||
ApplicationConfiguration.Initialize();
|
ApplicationConfiguration.Initialize();
|
||||||
|
|
||||||
LaunchArgs = e.Args;
|
LaunchSettings = new LaunchSettings(e.Args);
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
Logger.WriteLine(LOG_IDENT, $"Arguments: {string.Join(' ', LaunchArgs)}");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
HttpClient.Timeout = TimeSpan.FromSeconds(30);
|
HttpClient.Timeout = TimeSpan.FromSeconds(30);
|
||||||
HttpClient.DefaultRequestHeaders.Add("User-Agent", ProjectRepository);
|
HttpClient.DefaultRequestHeaders.Add("User-Agent", ProjectRepository);
|
||||||
|
|
||||||
if (LaunchArgs.Length > 0)
|
|
||||||
{
|
|
||||||
if (Array.IndexOf(LaunchArgs, "-preferences") != -1 || Array.IndexOf(LaunchArgs, "-menu") != -1)
|
|
||||||
{
|
|
||||||
Logger.WriteLine(LOG_IDENT, "Started with IsMenuLaunch flag");
|
|
||||||
IsMenuLaunch = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.IndexOf(LaunchArgs, "-quiet") != -1)
|
|
||||||
{
|
|
||||||
Logger.WriteLine(LOG_IDENT, "Started with IsQuiet flag");
|
|
||||||
IsQuiet = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.IndexOf(LaunchArgs, "-uninstall") != -1)
|
|
||||||
{
|
|
||||||
Logger.WriteLine(LOG_IDENT, "Started with IsUninstall flag");
|
|
||||||
IsUninstall = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.IndexOf(LaunchArgs, "-nolaunch") != -1)
|
|
||||||
{
|
|
||||||
Logger.WriteLine(LOG_IDENT, "Started with IsNoLaunch flag");
|
|
||||||
IsNoLaunch = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.IndexOf(LaunchArgs, "-upgrade") != -1)
|
|
||||||
{
|
|
||||||
Logger.WriteLine(LOG_IDENT, "Bloxstrap started with IsUpgrade flag");
|
|
||||||
IsUpgrade = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var checker = new InstallChecker())
|
using (var checker = new InstallChecker())
|
||||||
{
|
{
|
||||||
@ -175,7 +142,7 @@ namespace Bloxstrap
|
|||||||
// just in case the user decides to cancel the install
|
// just in case the user decides to cancel the install
|
||||||
if (!IsFirstRun)
|
if (!IsFirstRun)
|
||||||
{
|
{
|
||||||
Logger.Initialize(IsUninstall);
|
Logger.Initialize(LaunchSettings.IsUninstall);
|
||||||
|
|
||||||
if (!Logger.Initialized)
|
if (!Logger.Initialized)
|
||||||
{
|
{
|
||||||
@ -188,18 +155,15 @@ namespace Bloxstrap
|
|||||||
FastFlags.Load();
|
FastFlags.Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsUninstall && !IsMenuLaunch)
|
if (!LaunchSettings.IsUninstall && !LaunchSettings.IsMenuLaunch)
|
||||||
NotifyIcon = new();
|
NotifyIcon = new();
|
||||||
|
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
if (!IsUninstall && !IsFirstRun)
|
if (!LaunchSettings.IsUninstall && !IsFirstRun)
|
||||||
InstallChecker.CheckUpgrade();
|
InstallChecker.CheckUpgrade();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
string commandLine = "";
|
if (LaunchSettings.IsMenuLaunch)
|
||||||
LaunchMode? launchMode = null;
|
|
||||||
|
|
||||||
if (IsMenuLaunch)
|
|
||||||
{
|
{
|
||||||
Process? menuProcess = Process.GetProcesses().Where(x => x.MainWindowTitle == $"{ProjectName} Menu").FirstOrDefault();
|
Process? menuProcess = Process.GetProcesses().Where(x => x.MainWindowTitle == $"{ProjectName} Menu").FirstOrDefault();
|
||||||
|
|
||||||
@ -211,7 +175,7 @@ namespace Bloxstrap
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Process.GetProcessesByName(ProjectName).Length > 1 && !IsQuiet)
|
if (Process.GetProcessesByName(ProjectName).Length > 1 && !LaunchSettings.IsQuiet)
|
||||||
Frontend.ShowMessageBox(
|
Frontend.ShowMessageBox(
|
||||||
Bloxstrap.Resources.Strings.Menu_AlreadyRunning,
|
Bloxstrap.Resources.Strings.Menu_AlreadyRunning,
|
||||||
MessageBoxImage.Information
|
MessageBoxImage.Information
|
||||||
@ -219,152 +183,95 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
Frontend.ShowMenu();
|
Frontend.ShowMenu();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (LaunchArgs.Length > 0)
|
|
||||||
{
|
|
||||||
if (LaunchArgs[0].StartsWith("roblox-player:"))
|
|
||||||
{
|
|
||||||
commandLine = ProtocolHandler.ParseUri(LaunchArgs[0]);
|
|
||||||
|
|
||||||
launchMode = LaunchMode.Player;
|
StartupFinished();
|
||||||
}
|
return;
|
||||||
else if (LaunchArgs[0].StartsWith("roblox:"))
|
|
||||||
{
|
|
||||||
if (Settings.Prop.UseDisableAppPatch)
|
|
||||||
Frontend.ShowMessageBox(
|
|
||||||
Bloxstrap.Resources.Strings.Bootstrapper_DeeplinkTempEnabled,
|
|
||||||
MessageBoxImage.Information
|
|
||||||
);
|
|
||||||
|
|
||||||
commandLine = $"--app --deeplink {LaunchArgs[0]}";
|
|
||||||
|
|
||||||
launchMode = LaunchMode.Player;
|
|
||||||
}
|
|
||||||
else if (LaunchArgs[0].StartsWith("roblox-studio:"))
|
|
||||||
{
|
|
||||||
commandLine = ProtocolHandler.ParseUri(LaunchArgs[0]);
|
|
||||||
|
|
||||||
if (!commandLine.Contains("-startEvent"))
|
|
||||||
commandLine += " -startEvent www.roblox.com/robloxQTStudioStartedEvent";
|
|
||||||
|
|
||||||
launchMode = LaunchMode.Studio;
|
|
||||||
}
|
|
||||||
else if (LaunchArgs[0].StartsWith("roblox-studio-auth:"))
|
|
||||||
{
|
|
||||||
commandLine = HttpUtility.UrlDecode(LaunchArgs[0]);
|
|
||||||
|
|
||||||
launchMode = LaunchMode.StudioAuth;
|
|
||||||
}
|
|
||||||
else if (LaunchArgs[0] == "-ide")
|
|
||||||
{
|
|
||||||
launchMode = LaunchMode.Studio;
|
|
||||||
|
|
||||||
if (LaunchArgs.Length >= 2)
|
|
||||||
commandLine = $"-task EditFile -localPlaceFile \"{LaunchArgs[1]}\"";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
commandLine = "--app";
|
|
||||||
|
|
||||||
launchMode = LaunchMode.Player;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
commandLine = "--app";
|
|
||||||
|
|
||||||
launchMode = LaunchMode.Player;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (launchMode != null)
|
if (!IsFirstRun)
|
||||||
|
ShouldSaveConfigs = true;
|
||||||
|
|
||||||
|
// start bootstrapper and show the bootstrapper modal if we're not running silently
|
||||||
|
Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper");
|
||||||
|
Bootstrapper bootstrapper = new(LaunchSettings.RobloxLaunchArgs, LaunchSettings.RobloxLaunchMode);
|
||||||
|
IBootstrapperDialog? dialog = null;
|
||||||
|
|
||||||
|
if (!LaunchSettings.IsQuiet)
|
||||||
{
|
{
|
||||||
if (!IsFirstRun)
|
Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper dialog");
|
||||||
ShouldSaveConfigs = true;
|
dialog = Settings.Prop.BootstrapperStyle.GetNew();
|
||||||
|
bootstrapper.Dialog = dialog;
|
||||||
// start bootstrapper and show the bootstrapper modal if we're not running silently
|
dialog.Bootstrapper = bootstrapper;
|
||||||
Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper");
|
}
|
||||||
Bootstrapper bootstrapper = new(commandLine, (LaunchMode)launchMode);
|
|
||||||
IBootstrapperDialog? dialog = null;
|
|
||||||
|
|
||||||
if (!IsQuiet)
|
// handle roblox singleton mutex for multi-instance launching
|
||||||
|
// note we're handling it here in the main thread and NOT in the
|
||||||
|
// bootstrapper as handling mutexes in async contexts suuuuuucks
|
||||||
|
|
||||||
|
Mutex? singletonMutex = null;
|
||||||
|
|
||||||
|
if (Settings.Prop.MultiInstanceLaunching && LaunchSettings.RobloxLaunchMode == LaunchMode.Player)
|
||||||
|
{
|
||||||
|
Logger.WriteLine(LOG_IDENT, "Creating singleton mutex");
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper dialog");
|
Mutex.OpenExisting("ROBLOX_singletonMutex");
|
||||||
dialog = Settings.Prop.BootstrapperStyle.GetNew();
|
Logger.WriteLine(LOG_IDENT, "Warning - singleton mutex already exists!");
|
||||||
bootstrapper.Dialog = dialog;
|
|
||||||
dialog.Bootstrapper = bootstrapper;
|
|
||||||
}
|
}
|
||||||
|
catch
|
||||||
// handle roblox singleton mutex for multi-instance launching
|
|
||||||
// note we're handling it here in the main thread and NOT in the
|
|
||||||
// bootstrapper as handling mutexes in async contexts suuuuuucks
|
|
||||||
|
|
||||||
Mutex? singletonMutex = null;
|
|
||||||
|
|
||||||
if (Settings.Prop.MultiInstanceLaunching && launchMode == LaunchMode.Player)
|
|
||||||
{
|
{
|
||||||
Logger.WriteLine(LOG_IDENT, "Creating singleton mutex");
|
// create the singleton mutex before the game client does
|
||||||
|
singletonMutex = new Mutex(true, "ROBLOX_singletonMutex");
|
||||||
try
|
|
||||||
{
|
|
||||||
Mutex.OpenExisting("ROBLOX_singletonMutex");
|
|
||||||
Logger.WriteLine(LOG_IDENT, "Warning - singleton mutex already exists!");
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// create the singleton mutex before the game client does
|
|
||||||
singletonMutex = new Mutex(true, "ROBLOX_singletonMutex");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Task bootstrapperTask = Task.Run(async () => await bootstrapper.Run()).ContinueWith(t =>
|
Task bootstrapperTask = Task.Run(async () => await bootstrapper.Run()).ContinueWith(t =>
|
||||||
{
|
{
|
||||||
Logger.WriteLine(LOG_IDENT, "Bootstrapper task has finished");
|
Logger.WriteLine(LOG_IDENT, "Bootstrapper task has finished");
|
||||||
|
|
||||||
// notifyicon is blocking main thread, must be disposed here
|
// notifyicon is blocking main thread, must be disposed here
|
||||||
NotifyIcon?.Dispose();
|
NotifyIcon?.Dispose();
|
||||||
|
|
||||||
if (t.IsFaulted)
|
if (t.IsFaulted)
|
||||||
Logger.WriteLine(LOG_IDENT, "An exception occurred when running the bootstrapper");
|
Logger.WriteLine(LOG_IDENT, "An exception occurred when running the bootstrapper");
|
||||||
|
|
||||||
if (t.Exception is null)
|
if (t.Exception is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Logger.WriteException(LOG_IDENT, t.Exception);
|
Logger.WriteException(LOG_IDENT, t.Exception);
|
||||||
|
|
||||||
Exception exception = t.Exception;
|
Exception exception = t.Exception;
|
||||||
|
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
if (t.Exception.GetType().ToString() == "System.AggregateException")
|
if (t.Exception.GetType().ToString() == "System.AggregateException")
|
||||||
exception = t.Exception.InnerException!;
|
exception = t.Exception.InnerException!;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
FinalizeExceptionHandling(exception, false);
|
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
|
// 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 (!IsNoLaunch && Settings.Prop.EnableActivityTracking)
|
if (!LaunchSettings.IsNoLaunch && Settings.Prop.EnableActivityTracking)
|
||||||
NotifyIcon?.InitializeContextMenu();
|
NotifyIcon?.InitializeContextMenu();
|
||||||
|
|
||||||
Logger.WriteLine(LOG_IDENT, "Waiting for bootstrapper task to finish");
|
Logger.WriteLine(LOG_IDENT, "Waiting for bootstrapper task to finish");
|
||||||
|
|
||||||
bootstrapperTask.Wait();
|
bootstrapperTask.Wait();
|
||||||
|
|
||||||
if (singletonMutex is not null)
|
if (singletonMutex is not null)
|
||||||
{
|
{
|
||||||
Logger.WriteLine(LOG_IDENT, "We have singleton mutex ownership! Running in background until all Roblox processes are closed");
|
Logger.WriteLine(LOG_IDENT, "We have singleton mutex ownership! Running in background until all Roblox processes are closed");
|
||||||
|
|
||||||
// we've got ownership of the roblox singleton mutex!
|
// we've got ownership of the roblox singleton mutex!
|
||||||
// if we stop running, everything will screw up once any more roblox instances launched
|
// if we stop running, everything will screw up once any more roblox instances launched
|
||||||
while (Process.GetProcessesByName("RobloxPlayerBeta").Any())
|
while (Process.GetProcessesByName("RobloxPlayerBeta").Any())
|
||||||
Thread.Sleep(5000);
|
Thread.Sleep(5000);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.WriteLine(LOG_IDENT, "Successfully reached end of main thread. Terminating...");
|
StartupFinished();
|
||||||
|
|
||||||
Terminate();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<UseWindowsForms>True</UseWindowsForms>
|
<UseWindowsForms>True</UseWindowsForms>
|
||||||
<ApplicationIcon>Bloxstrap.ico</ApplicationIcon>
|
<ApplicationIcon>Bloxstrap.ico</ApplicationIcon>
|
||||||
<Version>2.5.3</Version>
|
<Version>2.6.0</Version>
|
||||||
<FileVersion>2.5.3.0</FileVersion>
|
<FileVersion>2.6.0.0</FileVersion>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
@ -40,7 +40,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||||
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
|
<PackageReference Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||||
<PackageReference Include="Markdig" Version="0.33.0" />
|
<PackageReference Include="Markdig" Version="0.35.0" />
|
||||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.18-beta">
|
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.18-beta">
|
||||||
<!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
|
<!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
@ -99,10 +99,6 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
message = message.Replace("{product}", productName);
|
message = message.Replace("{product}", productName);
|
||||||
|
|
||||||
// yea idk
|
|
||||||
if (App.Settings.Prop.BootstrapperStyle == BootstrapperStyle.ByfronDialog)
|
|
||||||
message = message.Replace("...", "");
|
|
||||||
|
|
||||||
if (Dialog is not null)
|
if (Dialog is not null)
|
||||||
Dialog.Message = message;
|
Dialog.Message = message;
|
||||||
}
|
}
|
||||||
@ -127,7 +123,7 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Running bootstrapper");
|
App.Logger.WriteLine(LOG_IDENT, "Running bootstrapper");
|
||||||
|
|
||||||
if (App.IsUninstall)
|
if (App.LaunchSettings.IsUninstall)
|
||||||
{
|
{
|
||||||
Uninstall();
|
Uninstall();
|
||||||
return;
|
return;
|
||||||
@ -230,9 +226,9 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
await mutex.ReleaseAsync();
|
await mutex.ReleaseAsync();
|
||||||
|
|
||||||
if (App.IsFirstRun && App.IsNoLaunch)
|
if (App.IsFirstRun && App.LaunchSettings.IsNoLaunch)
|
||||||
Dialog?.ShowSuccess(Resources.Strings.Bootstrapper_SuccessfullyInstalled);
|
Dialog?.ShowSuccess(Resources.Strings.Bootstrapper_SuccessfullyInstalled);
|
||||||
else if (!App.IsNoLaunch && !_cancelFired)
|
else if (!App.LaunchSettings.IsNoLaunch && !_cancelFired)
|
||||||
await StartRoblox();
|
await StartRoblox();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,7 +302,7 @@ namespace Bloxstrap
|
|||||||
MessageBoxImage.Error
|
MessageBoxImage.Error
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!App.IsQuiet)
|
if (!App.LaunchSettings.IsQuiet)
|
||||||
Utilities.ShellExecute("https://support.microsoft.com/en-us/topic/media-feature-pack-list-for-windows-n-editions-c1c6fffa-d052-8338-7a79-a4bb980a700a");
|
Utilities.ShellExecute("https://support.microsoft.com/en-us/topic/media-feature-pack-list-for-windows-n-editions-c1c6fffa-d052-8338-7a79-a4bb980a700a");
|
||||||
|
|
||||||
Dialog?.CloseBootstrapper();
|
Dialog?.CloseBootstrapper();
|
||||||
@ -659,7 +655,7 @@ namespace Bloxstrap
|
|||||||
FileName = downloadLocation,
|
FileName = downloadLocation,
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (string arg in App.LaunchArgs)
|
foreach (string arg in App.LaunchSettings.Args)
|
||||||
startInfo.ArgumentList.Add(arg);
|
startInfo.ArgumentList.Add(arg);
|
||||||
|
|
||||||
App.Settings.Save();
|
App.Settings.Save();
|
||||||
@ -703,13 +699,13 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
foreach (Process process in Process.GetProcessesByName(App.RobloxPlayerAppName))
|
foreach (Process process in Process.GetProcessesByName(App.RobloxPlayerAppName))
|
||||||
{
|
{
|
||||||
process.CloseMainWindow();
|
process.Kill();
|
||||||
process.Close();
|
process.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Process process in Process.GetProcessesByName(App.RobloxStudioAppName))
|
foreach (Process process in Process.GetProcessesByName(App.RobloxStudioAppName))
|
||||||
{
|
{
|
||||||
process.CloseMainWindow();
|
process.Kill();
|
||||||
process.Close();
|
process.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
LegacyDialog2011,
|
LegacyDialog2011,
|
||||||
ProgressDialog,
|
ProgressDialog,
|
||||||
FluentDialog,
|
FluentDialog,
|
||||||
ByfronDialog
|
ByfronDialog,
|
||||||
|
ProgressFluentDialog,
|
||||||
|
ProgressFluentAeroDialog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,16 @@
|
|||||||
static class BootstrapperStyleEx
|
static class BootstrapperStyleEx
|
||||||
{
|
{
|
||||||
public static IBootstrapperDialog GetNew(this BootstrapperStyle bootstrapperStyle) => Frontend.GetBootstrapperDialog(bootstrapperStyle);
|
public static IBootstrapperDialog GetNew(this BootstrapperStyle bootstrapperStyle) => Frontend.GetBootstrapperDialog(bootstrapperStyle);
|
||||||
|
|
||||||
|
public static IReadOnlyCollection<BootstrapperStyle> Selections => new BootstrapperStyle[]
|
||||||
|
{
|
||||||
|
BootstrapperStyle.FluentDialog,
|
||||||
|
BootstrapperStyle.ProgressFluentDialog,
|
||||||
|
BootstrapperStyle.ProgressFluentAeroDialog,
|
||||||
|
BootstrapperStyle.ByfronDialog,
|
||||||
|
BootstrapperStyle.LegacyDialog2011,
|
||||||
|
BootstrapperStyle.LegacyDialog2008,
|
||||||
|
BootstrapperStyle.VistaDialog
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ namespace Bloxstrap
|
|||||||
App.BaseDirectory = Path.Combine(Paths.LocalAppData, App.ProjectName);
|
App.BaseDirectory = Path.Combine(Paths.LocalAppData, App.ProjectName);
|
||||||
App.Logger.Initialize(true);
|
App.Logger.Initialize(true);
|
||||||
|
|
||||||
if (App.IsQuiet)
|
if (App.LaunchSettings.IsQuiet)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
App.IsSetupComplete = false;
|
App.IsSetupComplete = false;
|
||||||
@ -159,7 +159,7 @@ namespace Bloxstrap
|
|||||||
MessageBoxResult result;
|
MessageBoxResult result;
|
||||||
|
|
||||||
// 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.IsUpgrade || isAutoUpgrade)
|
if (App.LaunchSettings.IsUpgrade || isAutoUpgrade)
|
||||||
{
|
{
|
||||||
result = MessageBoxResult.Yes;
|
result = MessageBoxResult.Yes;
|
||||||
}
|
}
|
||||||
@ -238,7 +238,7 @@ namespace Bloxstrap
|
|||||||
(_, _) => Utilities.ShellExecute($"https://github.com/{App.ProjectRepository}/releases/tag/v{currentVersionInfo.ProductVersion}")
|
(_, _) => Utilities.ShellExecute($"https://github.com/{App.ProjectRepository}/releases/tag/v{currentVersionInfo.ProductVersion}")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (!App.IsQuiet)
|
else if (!App.LaunchSettings.IsQuiet)
|
||||||
{
|
{
|
||||||
Frontend.ShowMessageBox(
|
Frontend.ShowMessageBox(
|
||||||
string.Format(Resources.Strings.InstallChecker_Updated, currentVersionInfo.ProductVersion),
|
string.Format(Resources.Strings.InstallChecker_Updated, currentVersionInfo.ProductVersion),
|
||||||
|
@ -60,7 +60,7 @@
|
|||||||
|
|
||||||
int delay = 1000;
|
int delay = 1000;
|
||||||
|
|
||||||
if (App.Settings.Prop.OhHeyYouFoundMe)
|
if (App.Settings.Prop.PowerTools)
|
||||||
delay = 250;
|
delay = 250;
|
||||||
|
|
||||||
string logDirectory = Path.Combine(Paths.LocalAppData, "Roblox\\logs");
|
string logDirectory = Path.Combine(Paths.LocalAppData, "Roblox\\logs");
|
||||||
|
30
Bloxstrap/InterProcessLock.cs
Normal file
30
Bloxstrap/InterProcessLock.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bloxstrap
|
||||||
|
{
|
||||||
|
public class InterProcessLock : IDisposable
|
||||||
|
{
|
||||||
|
public Mutex Mutex { get; private set; }
|
||||||
|
|
||||||
|
public bool IsAcquired { get; private set; }
|
||||||
|
|
||||||
|
public InterProcessLock(string name, TimeSpan timeout)
|
||||||
|
{
|
||||||
|
Mutex = new Mutex(false, "Bloxstrap-" + name);
|
||||||
|
IsAcquired = Mutex.WaitOne(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (IsAcquired)
|
||||||
|
{
|
||||||
|
Mutex.ReleaseMutex();
|
||||||
|
IsAcquired = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
181
Bloxstrap/LaunchSettings.cs
Normal file
181
Bloxstrap/LaunchSettings.cs
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
using Bloxstrap.Enums;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Web;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace Bloxstrap
|
||||||
|
{
|
||||||
|
public class LaunchSettings
|
||||||
|
{
|
||||||
|
[LaunchFlag(new[] { "-preferences", "-menu" })]
|
||||||
|
public bool IsMenuLaunch { get; private set; } = false;
|
||||||
|
|
||||||
|
[LaunchFlag("-quiet")]
|
||||||
|
public bool IsQuiet { get; private set; } = false;
|
||||||
|
|
||||||
|
[LaunchFlag("-uninstall")]
|
||||||
|
public bool IsUninstall { get; private set; } = false;
|
||||||
|
|
||||||
|
[LaunchFlag("-nolaunch")]
|
||||||
|
public bool IsNoLaunch { get; private set; } = false;
|
||||||
|
|
||||||
|
[LaunchFlag("-upgrade")]
|
||||||
|
public bool IsUpgrade { get; private set; } = false;
|
||||||
|
|
||||||
|
public LaunchMode RobloxLaunchMode { get; private set; } = LaunchMode.Player;
|
||||||
|
|
||||||
|
public string RobloxLaunchArgs { get; private set; } = "--app";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Original launch arguments
|
||||||
|
/// </summary>
|
||||||
|
public string[] Args { get; private set; }
|
||||||
|
|
||||||
|
private Dictionary<string, PropertyInfo>? _flagMap;
|
||||||
|
|
||||||
|
// pizzaboxer wanted this
|
||||||
|
private void ParseLaunchFlagProps()
|
||||||
|
{
|
||||||
|
_flagMap = new Dictionary<string, PropertyInfo>();
|
||||||
|
|
||||||
|
foreach (var prop in typeof(LaunchSettings).GetProperties())
|
||||||
|
{
|
||||||
|
var attr = prop.GetCustomAttribute<LaunchFlagAttribute>();
|
||||||
|
|
||||||
|
if (attr == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(attr.Name))
|
||||||
|
{
|
||||||
|
_flagMap[attr.Name] = prop;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var name in attr.Names!)
|
||||||
|
_flagMap[name] = prop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseFlag(string arg)
|
||||||
|
{
|
||||||
|
const string LOG_IDENT = "LaunchSettings::ParseFlag";
|
||||||
|
|
||||||
|
arg = arg.ToLowerInvariant();
|
||||||
|
|
||||||
|
if (_flagMap!.ContainsKey(arg))
|
||||||
|
{
|
||||||
|
var prop = _flagMap[arg];
|
||||||
|
prop.SetValue(this, true);
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, $"Started with {prop.Name} flag");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseRoblox(string arg, ref int i)
|
||||||
|
{
|
||||||
|
if (arg.StartsWith("roblox-player:"))
|
||||||
|
{
|
||||||
|
RobloxLaunchArgs = ProtocolHandler.ParseUri(arg);
|
||||||
|
|
||||||
|
RobloxLaunchMode = LaunchMode.Player;
|
||||||
|
}
|
||||||
|
else if (arg.StartsWith("roblox:"))
|
||||||
|
{
|
||||||
|
if (App.Settings.Prop.UseDisableAppPatch)
|
||||||
|
Frontend.ShowMessageBox(
|
||||||
|
Resources.Strings.Bootstrapper_DeeplinkTempEnabled,
|
||||||
|
MessageBoxImage.Information
|
||||||
|
);
|
||||||
|
|
||||||
|
RobloxLaunchArgs = $"--app --deeplink {arg}";
|
||||||
|
|
||||||
|
RobloxLaunchMode = LaunchMode.Player;
|
||||||
|
}
|
||||||
|
else if (arg.StartsWith("roblox-studio:"))
|
||||||
|
{
|
||||||
|
RobloxLaunchArgs = ProtocolHandler.ParseUri(arg);
|
||||||
|
|
||||||
|
if (!RobloxLaunchArgs.Contains("-startEvent"))
|
||||||
|
RobloxLaunchArgs += " -startEvent www.roblox.com/robloxQTStudioStartedEvent";
|
||||||
|
|
||||||
|
RobloxLaunchMode = LaunchMode.Studio;
|
||||||
|
}
|
||||||
|
else if (arg.StartsWith("roblox-studio-auth:"))
|
||||||
|
{
|
||||||
|
RobloxLaunchArgs = HttpUtility.UrlDecode(arg);
|
||||||
|
|
||||||
|
RobloxLaunchMode = LaunchMode.StudioAuth;
|
||||||
|
}
|
||||||
|
else if (arg == "-ide")
|
||||||
|
{
|
||||||
|
RobloxLaunchMode = LaunchMode.Studio;
|
||||||
|
|
||||||
|
if (Args.Length >= 2)
|
||||||
|
{
|
||||||
|
string pathArg = Args[i + 1];
|
||||||
|
|
||||||
|
if (pathArg.StartsWith('-'))
|
||||||
|
return; // likely a launch flag, ignore it.
|
||||||
|
|
||||||
|
i++; // path arg
|
||||||
|
RobloxLaunchArgs = $"-task EditFile -localPlaceFile \"{pathArg}\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Parse()
|
||||||
|
{
|
||||||
|
const string LOG_IDENT = "LaunchSettings::Parse";
|
||||||
|
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Parsing launch arguments");
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, $"Launch arguments: {string.Join(' ', Args)}");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (Args.Length == 0)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "No launch arguments to parse");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
string firstArg = Args[0];
|
||||||
|
|
||||||
|
// check & handle roblox arg
|
||||||
|
if (!firstArg.StartsWith('-') || firstArg == "-ide")
|
||||||
|
{
|
||||||
|
ParseRoblox(firstArg, ref idx);
|
||||||
|
idx++; // roblox arg
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if there are any launch flags
|
||||||
|
if (idx > Args.Length - 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Parsing launch flags");
|
||||||
|
|
||||||
|
// map out launch flags
|
||||||
|
ParseLaunchFlagProps();
|
||||||
|
|
||||||
|
// parse any launch flags
|
||||||
|
for (int i = idx; i < Args.Length; i++)
|
||||||
|
ParseFlag(Args[i]);
|
||||||
|
|
||||||
|
// cleanup flag map
|
||||||
|
_flagMap!.Clear();
|
||||||
|
_flagMap = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LaunchSettings(string[] args)
|
||||||
|
{
|
||||||
|
Args = args;
|
||||||
|
Parse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
Bloxstrap/Models/Attributes/LaunchFlagAttribute.cs
Normal file
24
Bloxstrap/Models/Attributes/LaunchFlagAttribute.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bloxstrap.Models.Attributes
|
||||||
|
{
|
||||||
|
public class LaunchFlagAttribute : Attribute
|
||||||
|
{
|
||||||
|
public string? Name { get; private set; }
|
||||||
|
public string[]? Names { get; private set; }
|
||||||
|
|
||||||
|
public LaunchFlagAttribute(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LaunchFlagAttribute(string[] names)
|
||||||
|
{
|
||||||
|
Names = names;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,10 @@ namespace Bloxstrap.Models
|
|||||||
public bool CheckForUpdates { get; set; } = true;
|
public bool CheckForUpdates { get; set; } = true;
|
||||||
public bool CreateDesktopIcon { get; set; } = true;
|
public bool CreateDesktopIcon { get; set; } = true;
|
||||||
public bool MultiInstanceLaunching { get; set; } = false;
|
public bool MultiInstanceLaunching { get; set; } = false;
|
||||||
public bool OhHeyYouFoundMe { get; set; } = false;
|
|
||||||
|
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||||
|
[JsonPropertyName("OhHeyYouFoundMeAgain")]
|
||||||
|
public bool PowerTools { get; set; } = false;
|
||||||
|
|
||||||
// channel configuration
|
// channel configuration
|
||||||
public string Channel { get; set; } = RobloxDeployment.DefaultChannel;
|
public string Channel { get; set; } = RobloxDeployment.DefaultChannel;
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<!--
|
|
||||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
|
||||||
-->
|
|
||||||
<Project>
|
|
||||||
<PropertyGroup>
|
|
||||||
<Configuration>Release</Configuration>
|
|
||||||
<Platform>Any CPU</Platform>
|
|
||||||
<PublishDir>bin\Release\net6.0-windows\publish\win-x86\</PublishDir>
|
|
||||||
<PublishProtocol>FileSystem</PublishProtocol>
|
|
||||||
<_TargetId>Folder</_TargetId>
|
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
|
||||||
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
|
|
||||||
<SelfContained>false</SelfContained>
|
|
||||||
<PublishSingleFile>true</PublishSingleFile>
|
|
||||||
<PublishReadyToRun>false</PublishReadyToRun>
|
|
||||||
</PropertyGroup>
|
|
||||||
</Project>
|
|
38
Bloxstrap/Resources/Strings.Designer.cs
generated
38
Bloxstrap/Resources/Strings.Designer.cs
generated
@ -243,6 +243,24 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Style preview - Click the X button at the top right to close.
|
||||||
|
/// </summary>
|
||||||
|
public static string Bootstrapper_StylePreview_ImageCancel {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Bootstrapper.StylePreview.ImageCancel", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Style preview - Click Cancel to close.
|
||||||
|
/// </summary>
|
||||||
|
public static string Bootstrapper_StylePreview_TextCancel {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Bootstrapper.StylePreview.TextCancel", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Bloxstrap has successfully installed.
|
/// Looks up a localized string similar to Bloxstrap has successfully installed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -828,6 +846,24 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Fluent Progress (Aero).
|
||||||
|
/// </summary>
|
||||||
|
public static string Enums_BootstrapperStyle_ProgressFluentAeroDialog {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Enums.BootstrapperStyle.ProgressFluentAeroDialog", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Fluent Progress.
|
||||||
|
/// </summary>
|
||||||
|
public static string Enums_BootstrapperStyle_ProgressFluentDialog {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Enums.BootstrapperStyle.ProgressFluentDialog", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Vista (2008 - 2011).
|
/// Looks up a localized string similar to Vista (2008 - 2011).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1426,7 +1462,7 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Bloxstrap is currently running, likely as a background Roblox process. Please note that not all your changes will immediately apply until you close all currently open Roblox instances.".
|
/// Looks up a localized string similar to Bloxstrap is currently running, likely as a background Roblox process. Please note that not all your changes will immediately apply until you close all currently open Roblox instances..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string Menu_AlreadyRunning {
|
public static string Menu_AlreadyRunning {
|
||||||
get {
|
get {
|
||||||
|
@ -180,6 +180,14 @@ Your ReShade configuration files will still be saved, and you can locate them by
|
|||||||
<data name="Bootstrapper.Status.WaitingOtherInstances" xml:space="preserve">
|
<data name="Bootstrapper.Status.WaitingOtherInstances" xml:space="preserve">
|
||||||
<value>Waiting for other instances...</value>
|
<value>Waiting for other instances...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Bootstrapper.StylePreview.ImageCancel" xml:space="preserve">
|
||||||
|
<value>Style preview - Click the X button at the top right to close</value>
|
||||||
|
<comment>Text for style previews that use an X button. Currently only applies to Byfron</comment>
|
||||||
|
</data>
|
||||||
|
<data name="Bootstrapper.StylePreview.TextCancel" xml:space="preserve">
|
||||||
|
<value>Style preview - Click Cancel to close</value>
|
||||||
|
<comment>Text for style previews that use text button that says "Cancel"</comment>
|
||||||
|
</data>
|
||||||
<data name="Bootstrapper.SuccessfullyInstalled" xml:space="preserve">
|
<data name="Bootstrapper.SuccessfullyInstalled" xml:space="preserve">
|
||||||
<value>Bloxstrap has successfully installed</value>
|
<value>Bloxstrap has successfully installed</value>
|
||||||
</data>
|
</data>
|
||||||
@ -375,6 +383,12 @@ Your ReShade configuration files will still be saved, and you can locate them by
|
|||||||
<data name="Enums.BootstrapperStyle.ProgressDialog" xml:space="preserve">
|
<data name="Enums.BootstrapperStyle.ProgressDialog" xml:space="preserve">
|
||||||
<value>Progress (~2014)</value>
|
<value>Progress (~2014)</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Enums.BootstrapperStyle.ProgressFluentAeroDialog" xml:space="preserve">
|
||||||
|
<value>Fluent Progress (Aero)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Enums.BootstrapperStyle.ProgressFluentDialog" xml:space="preserve">
|
||||||
|
<value>Fluent Progress</value>
|
||||||
|
</data>
|
||||||
<data name="Enums.BootstrapperStyle.VistaDialog" xml:space="preserve">
|
<data name="Enums.BootstrapperStyle.VistaDialog" xml:space="preserve">
|
||||||
<value>Vista (2008 - 2011)</value>
|
<value>Vista (2008 - 2011)</value>
|
||||||
</data>
|
</data>
|
||||||
@ -577,7 +591,7 @@ Would you like to upgrade your currently installed version?</value>
|
|||||||
<value>All files</value>
|
<value>All files</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Menu.AlreadyRunning" xml:space="preserve">
|
<data name="Menu.AlreadyRunning" xml:space="preserve">
|
||||||
<value>Bloxstrap is currently running, likely as a background Roblox process. Please note that not all your changes will immediately apply until you close all currently open Roblox instances."</value>
|
<value>Bloxstrap is currently running, likely as a background Roblox process. Please note that not all your changes will immediately apply until you close all currently open Roblox instances.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Menu.Appearance.Bootstrapper.Description" xml:space="preserve">
|
<data name="Menu.Appearance.Bootstrapper.Description" xml:space="preserve">
|
||||||
<value>You can make it look different, retro, or even just like Roblox.</value>
|
<value>You can make it look different, retro, or even just like Roblox.</value>
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
Closing="Window_Closing">
|
Closing="Window_Closing">
|
||||||
<Border CornerRadius="10" BorderBrush="#33393B3D" Background="{Binding Background}" BorderThickness="{Binding DialogBorder}">
|
<Border CornerRadius="10" BorderBrush="#33393B3D" Background="{Binding Background}" BorderThickness="{Binding DialogBorder}">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Image Source="{Binding ByfronLogoLocation}" Width="114" Height="108" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="17,13,0,0" />
|
<Image Source="{Binding ByfronLogoLocation}" RenderOptions.BitmapScalingMode="HighQuality" Width="114" Height="108" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="17,13,0,0" />
|
||||||
<Button Margin="15" VerticalAlignment="Top" HorizontalAlignment="Right" Width="20" Height="20" BorderThickness="0" Padding="1" Background="Transparent" BorderBrush="Transparent" Visibility="{Binding CancelButtonVisibility, Mode=OneWay}" Command="{Binding CancelInstallCommand}">
|
<Button Margin="15" VerticalAlignment="Top" HorizontalAlignment="Right" Width="20" Height="20" BorderThickness="0" Padding="1" Background="Transparent" BorderBrush="Transparent" Visibility="{Binding CancelButtonVisibility, Mode=OneWay}" Command="{Binding CancelInstallCommand}">
|
||||||
<Path Fill="{Binding IconColor}" Stretch="Fill">
|
<Path Fill="{Binding IconColor}" Stretch="Fill">
|
||||||
<Path.Data>
|
<Path.Data>
|
||||||
|
@ -26,7 +26,11 @@ namespace Bloxstrap.UI.Elements.Bootstrapper
|
|||||||
get => _viewModel.Message;
|
get => _viewModel.Message;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_viewModel.Message = value;
|
string message = value;
|
||||||
|
if (message.EndsWith("..."))
|
||||||
|
message = message[..^3];
|
||||||
|
|
||||||
|
_viewModel.Message = message;
|
||||||
_viewModel.OnPropertyChanged(nameof(_viewModel.Message));
|
_viewModel.OnPropertyChanged(nameof(_viewModel.Message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,11 +30,7 @@
|
|||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Border Grid.Column="0" Margin="0,12,0,0" Width="48" Height="48" VerticalAlignment="Top">
|
<Image Grid.Column="0" Margin="0,12,0,0" Width="48" Height="48" VerticalAlignment="Top" Source="{Binding Icon, Mode=OneWay}" RenderOptions.BitmapScalingMode="HighQuality" />
|
||||||
<Border.Background>
|
|
||||||
<ImageBrush ImageSource="{Binding Icon, Mode=OneWay}" RenderOptions.BitmapScalingMode="HighQuality" />
|
|
||||||
</Border.Background>
|
|
||||||
</Border>
|
|
||||||
<StackPanel Grid.Column="1">
|
<StackPanel Grid.Column="1">
|
||||||
<TextBlock Margin="16,8,0,0" FontSize="20" Text="{Binding Message, Mode=OneWay}" Foreground="{DynamicResource TextFillColorPrimaryBrush}" />
|
<TextBlock Margin="16,8,0,0" FontSize="20" Text="{Binding Message, Mode=OneWay}" Foreground="{DynamicResource TextFillColorPrimaryBrush}" />
|
||||||
<ProgressBar Margin="16,16,0,16" IsIndeterminate="{Binding ProgressIndeterminate, Mode=OneWay}" Maximum="{Binding ProgressMaximum, Mode=OneWay}" Value="{Binding ProgressValue, Mode=OneWay}" />
|
<ProgressBar Margin="16,16,0,16" IsIndeterminate="{Binding ProgressIndeterminate, Mode=OneWay}" Maximum="{Binding ProgressMaximum, Mode=OneWay}" Value="{Binding ProgressValue, Mode=OneWay}" />
|
||||||
|
80
Bloxstrap/UI/Elements/Bootstrapper/ProgressFluentDialog.xaml
Normal file
80
Bloxstrap/UI/Elements/Bootstrapper/ProgressFluentDialog.xaml
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
<base:WpfUiWindow
|
||||||
|
x:Class="Bloxstrap.UI.Elements.Bootstrapper.ProgressFluentDialog"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:base="clr-namespace:Bloxstrap.UI.Elements.Base"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:resources="clr-namespace:Bloxstrap.Resources"
|
||||||
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||||
|
xmlns:vms="clr-namespace:Bloxstrap.UI.ViewModels.Bootstrapper"
|
||||||
|
Width="500"
|
||||||
|
Height="280"
|
||||||
|
MinHeight="0"
|
||||||
|
d:DataContext="{d:DesignInstance vms:ProgressFluentDialogViewModel,
|
||||||
|
IsDesignTimeCreatable=True}"
|
||||||
|
AllowsTransparency="True"
|
||||||
|
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
|
||||||
|
Closing="UiWindow_Closing"
|
||||||
|
ExtendsContentIntoTitleBar="True"
|
||||||
|
ResizeMode="NoResize"
|
||||||
|
WindowBackdropType="{Binding Path=WindowBackdropType, Mode=OneTime}"
|
||||||
|
WindowStartupLocation="CenterScreen"
|
||||||
|
WindowStyle="None"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<!-- Background is for Aero theme only -->
|
||||||
|
<Grid Background="{Binding Path=BackgroundColourBrush, Mode=OneTime}">
|
||||||
|
<!-- Allow for drag -->
|
||||||
|
<ui:TitleBar
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
CanMaximize="False"
|
||||||
|
ShowClose="False"
|
||||||
|
ShowMaximize="False"
|
||||||
|
ShowMinimize="False" />
|
||||||
|
|
||||||
|
<Grid Margin="32,16">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Image
|
||||||
|
Grid.Row="0"
|
||||||
|
Width="80"
|
||||||
|
Height="80"
|
||||||
|
Margin="0,30,0,0"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
RenderOptions.BitmapScalingMode="HighQuality"
|
||||||
|
Source="{Binding Icon, Mode=OneWay}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="0,0,0,8"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
FontSize="18"
|
||||||
|
Foreground="{DynamicResource TextFillColorPrimaryBrush}"
|
||||||
|
Text="{Binding Message, Mode=OneWay}" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
Grid.Row="2"
|
||||||
|
Margin="0,0,0,16"
|
||||||
|
IsIndeterminate="{Binding ProgressIndeterminate, Mode=OneWay}"
|
||||||
|
Maximum="{Binding ProgressMaximum, Mode=OneWay}"
|
||||||
|
Value="{Binding ProgressValue, Mode=OneWay}" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
Grid.Row="3"
|
||||||
|
Width="120"
|
||||||
|
Padding="4"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Command="{Binding CancelInstallCommand}"
|
||||||
|
Content="{x:Static resources:Strings.Common_Cancel}"
|
||||||
|
FontSize="14"
|
||||||
|
IsEnabled="{Binding CancelEnabled, Mode=OneWay}" />
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</base:WpfUiWindow>
|
117
Bloxstrap/UI/Elements/Bootstrapper/ProgressFluentDialog.xaml.cs
Normal file
117
Bloxstrap/UI/Elements/Bootstrapper/ProgressFluentDialog.xaml.cs
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
using Bloxstrap.UI.Elements.Bootstrapper.Base;
|
||||||
|
using Bloxstrap.UI.ViewModels.Bootstrapper;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace Bloxstrap.UI.Elements.Bootstrapper
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ProgressFluentDialog.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class ProgressFluentDialog : IBootstrapperDialog
|
||||||
|
{
|
||||||
|
private readonly ProgressFluentDialogViewModel _viewModel;
|
||||||
|
|
||||||
|
public Bloxstrap.Bootstrapper? Bootstrapper { get; set; }
|
||||||
|
|
||||||
|
private bool _isClosing;
|
||||||
|
|
||||||
|
#region UI Elements
|
||||||
|
public string Message
|
||||||
|
{
|
||||||
|
get => _viewModel.Message;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_viewModel.Message = value;
|
||||||
|
_viewModel.OnPropertyChanged(nameof(_viewModel.Message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgressBarStyle ProgressStyle
|
||||||
|
{
|
||||||
|
get => _viewModel.ProgressIndeterminate ? ProgressBarStyle.Marquee : ProgressBarStyle.Continuous;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_viewModel.ProgressIndeterminate = (value == ProgressBarStyle.Marquee);
|
||||||
|
_viewModel.OnPropertyChanged(nameof(_viewModel.ProgressIndeterminate));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ProgressMaximum
|
||||||
|
{
|
||||||
|
get => _viewModel.ProgressMaximum;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_viewModel.ProgressMaximum = value;
|
||||||
|
_viewModel.OnPropertyChanged(nameof(_viewModel.ProgressMaximum));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ProgressValue
|
||||||
|
{
|
||||||
|
get => _viewModel.ProgressValue;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_viewModel.ProgressValue = value;
|
||||||
|
_viewModel.OnPropertyChanged(nameof(_viewModel.ProgressValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CancelEnabled
|
||||||
|
{
|
||||||
|
get => _viewModel.CancelEnabled;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_viewModel.CancelEnabled = value;
|
||||||
|
|
||||||
|
_viewModel.OnPropertyChanged(nameof(_viewModel.CancelButtonVisibility));
|
||||||
|
_viewModel.OnPropertyChanged(nameof(_viewModel.CancelEnabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public ProgressFluentDialog(bool aero)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
ApplyTheme();
|
||||||
|
|
||||||
|
_viewModel = new ProgressFluentDialogViewModel(this, aero);
|
||||||
|
DataContext = _viewModel;
|
||||||
|
Title = App.Settings.Prop.BootstrapperTitle;
|
||||||
|
Icon = App.Settings.Prop.BootstrapperIcon.GetIcon().GetImageSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UiWindow_Closing(object sender, CancelEventArgs e)
|
||||||
|
{
|
||||||
|
if (!_isClosing)
|
||||||
|
Bootstrapper?.CancelInstall();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IBootstrapperDialog Methods
|
||||||
|
public void ShowBootstrapper() => this.ShowDialog();
|
||||||
|
|
||||||
|
public void CloseBootstrapper()
|
||||||
|
{
|
||||||
|
_isClosing = true;
|
||||||
|
Dispatcher.BeginInvoke(this.Close);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowSuccess(string message, Action? callback) => BaseFunctions.ShowSuccess(message, callback);
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,7 @@
|
|||||||
<ColumnDefinition Width="20" />
|
<ColumnDefinition Width="20" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Image Grid.Column="0" Source="pack://application:,,,/Bloxstrap.ico" />
|
<Image Grid.Column="0" Source="pack://application:,,,/Bloxstrap.ico" RenderOptions.BitmapScalingMode="HighQuality" />
|
||||||
<TextBlock x:Name="VersionTextBlock" Foreground="{DynamicResource TextFillColorSecondaryBrush}" Grid.Column="1" VerticalAlignment="Center" Margin="6,0,0,0" Text="Bloxstrap v2.4.1" />
|
<TextBlock x:Name="VersionTextBlock" Foreground="{DynamicResource TextFillColorSecondaryBrush}" Grid.Column="1" VerticalAlignment="Center" Margin="6,0,0,0" Text="Bloxstrap v2.4.1" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</MenuItem.Header>
|
</MenuItem.Header>
|
||||||
|
@ -39,7 +39,7 @@ namespace Bloxstrap.UI.Elements.ContextMenu
|
|||||||
|
|
||||||
if (_activityWatcher is not null)
|
if (_activityWatcher is not null)
|
||||||
{
|
{
|
||||||
if (App.Settings.Prop.OhHeyYouFoundMe)
|
if (App.Settings.Prop.PowerTools)
|
||||||
LogTracerMenuItem.Visibility = Visibility.Visible;
|
LogTracerMenuItem.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
_activityWatcher.OnGameJoin += ActivityWatcher_OnGameJoin;
|
_activityWatcher.OnGameJoin += ActivityWatcher_OnGameJoin;
|
||||||
@ -136,7 +136,7 @@ namespace Bloxstrap.UI.Elements.ContextMenu
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
using Process process = Process.GetProcessById((int)_processId!);
|
using Process process = Process.GetProcessById((int)_processId!);
|
||||||
process.CloseMainWindow();
|
process.Kill();
|
||||||
process.Close();
|
process.Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,28 +6,93 @@ using System.Windows;
|
|||||||
using Markdig.Syntax;
|
using Markdig.Syntax;
|
||||||
using Markdig.Syntax.Inlines;
|
using Markdig.Syntax.Inlines;
|
||||||
using Markdig;
|
using Markdig;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
namespace Bloxstrap.UI.Elements.Controls
|
namespace Bloxstrap.UI.Elements.Controls
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// TextBlock with markdown support. <br/>
|
/// TextBlock with markdown support.
|
||||||
/// Only supports text and urls.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ContentProperty("MarkdownText")]
|
[ContentProperty("MarkdownText")]
|
||||||
[Localizability(LocalizationCategory.Text)]
|
[Localizability(LocalizationCategory.Text)]
|
||||||
class MarkdownTextBlock : TextBlock
|
class MarkdownTextBlock : TextBlock
|
||||||
{
|
{
|
||||||
|
private static MarkdownPipeline _markdownPipeline;
|
||||||
|
|
||||||
public static readonly DependencyProperty MarkdownTextProperty =
|
public static readonly DependencyProperty MarkdownTextProperty =
|
||||||
DependencyProperty.Register(nameof(MarkdownText), typeof(string), typeof(MarkdownTextBlock),
|
DependencyProperty.Register(nameof(MarkdownText), typeof(string), typeof(MarkdownTextBlock),
|
||||||
new FrameworkPropertyMetadata(string.Empty,FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnTextMarkdownChanged));
|
new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, OnTextMarkdownChanged));
|
||||||
|
|
||||||
[Localizability(LocalizationCategory.Text)]
|
[Localizability(LocalizationCategory.Text)]
|
||||||
public string MarkdownText
|
public string MarkdownText
|
||||||
{
|
{
|
||||||
get => Inlines.ToString() ?? "";
|
get => (string)GetValue(MarkdownTextProperty);
|
||||||
set => SetValue(MarkdownTextProperty, value);
|
set => SetValue(MarkdownTextProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static System.Windows.Documents.Inline? GetWpfInlineFromMarkdownInline(Markdig.Syntax.Inlines.Inline? inline)
|
||||||
|
{
|
||||||
|
if (inline is LiteralInline literalInline)
|
||||||
|
{
|
||||||
|
return new Run(literalInline.ToString());
|
||||||
|
}
|
||||||
|
else if (inline is EmphasisInline emphasisInline)
|
||||||
|
{
|
||||||
|
switch (emphasisInline.DelimiterChar)
|
||||||
|
{
|
||||||
|
case '*':
|
||||||
|
case '_':
|
||||||
|
{
|
||||||
|
if (emphasisInline.DelimiterCount == 1) // 1 = italic
|
||||||
|
{
|
||||||
|
var childInline = new Italic(GetWpfInlineFromMarkdownInline(emphasisInline.FirstChild));
|
||||||
|
return childInline;
|
||||||
|
}
|
||||||
|
else // 2 = bold
|
||||||
|
{
|
||||||
|
var childInline = new Bold(GetWpfInlineFromMarkdownInline(emphasisInline.FirstChild));
|
||||||
|
return childInline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
case '=': // marked
|
||||||
|
{
|
||||||
|
var childInline = new Span(GetWpfInlineFromMarkdownInline(emphasisInline.FirstChild));
|
||||||
|
childInline.Background = new SolidColorBrush(Color.FromArgb(50, 255, 255, 255)); // TODO: better colour?
|
||||||
|
return childInline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (inline is LinkInline linkInline)
|
||||||
|
{
|
||||||
|
string? url = linkInline.Url;
|
||||||
|
var textInline = linkInline.FirstChild;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(url))
|
||||||
|
{
|
||||||
|
return GetWpfInlineFromMarkdownInline(textInline);
|
||||||
|
}
|
||||||
|
|
||||||
|
var childInline = GetWpfInlineFromMarkdownInline(textInline);
|
||||||
|
|
||||||
|
return new Hyperlink(childInline)
|
||||||
|
{
|
||||||
|
Command = GlobalViewModel.OpenWebpageCommand,
|
||||||
|
CommandParameter = url
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddMarkdownInline(Markdig.Syntax.Inlines.Inline? inline)
|
||||||
|
{
|
||||||
|
var wpfInline = GetWpfInlineFromMarkdownInline(inline);
|
||||||
|
if (wpfInline != null)
|
||||||
|
Inlines.Add(wpfInline);
|
||||||
|
}
|
||||||
|
|
||||||
private static void OnTextMarkdownChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
private static void OnTextMarkdownChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
||||||
{
|
{
|
||||||
if (dependencyObject is not MarkdownTextBlock markdownTextBlock)
|
if (dependencyObject is not MarkdownTextBlock markdownTextBlock)
|
||||||
@ -36,34 +101,26 @@ namespace Bloxstrap.UI.Elements.Controls
|
|||||||
if (dependencyPropertyChangedEventArgs.NewValue is not string rawDocument)
|
if (dependencyPropertyChangedEventArgs.NewValue is not string rawDocument)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
MarkdownDocument document = Markdown.Parse(rawDocument);
|
MarkdownDocument document = Markdown.Parse(rawDocument, _markdownPipeline);
|
||||||
|
|
||||||
markdownTextBlock.Inlines.Clear();
|
markdownTextBlock.Inlines.Clear();
|
||||||
|
|
||||||
if (document.FirstOrDefault() is not ParagraphBlock paragraphBlock || paragraphBlock.Inline == null)
|
if (document.FirstOrDefault() is not ParagraphBlock paragraphBlock || paragraphBlock.Inline == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foreach (var inline in paragraphBlock.Inline)
|
for (int i = 0; i < paragraphBlock.Inline.Count(); i++)
|
||||||
{
|
{
|
||||||
if (inline is LiteralInline literalInline)
|
var inline = paragraphBlock.Inline.ElementAt(i);
|
||||||
{
|
|
||||||
markdownTextBlock.Inlines.Add(new Run(literalInline.ToString()));
|
|
||||||
}
|
|
||||||
else if (inline is LinkInline linkInline)
|
|
||||||
{
|
|
||||||
string? url = linkInline.Url;
|
|
||||||
string? text = linkInline.FirstChild?.ToString();
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(text))
|
markdownTextBlock.AddMarkdownInline(inline);
|
||||||
continue;
|
|
||||||
|
|
||||||
markdownTextBlock.Inlines.Add(new Hyperlink(new Run(text))
|
|
||||||
{
|
|
||||||
Command = GlobalViewModel.OpenWebpageCommand,
|
|
||||||
CommandParameter = url
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static MarkdownTextBlock()
|
||||||
|
{
|
||||||
|
_markdownPipeline = new MarkdownPipelineBuilder()
|
||||||
|
.UseEmphasisExtras(Markdig.Extensions.EmphasisExtras.EmphasisExtraOptions.Marked) // enable '==' support
|
||||||
|
.Build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
<ui:Button Content="{Binding ConfirmButtonText, Mode=OneTime}" Appearance="Primary" Command="{Binding ConfirmSettingsCommand, Mode=OneWay}" IsEnabled="{Binding ConfirmButtonEnabled, Mode=OneWay}" />
|
<ui:Button Content="{Binding ConfirmButtonText, Mode=OneTime}" Appearance="Primary" Command="{Binding ConfirmSettingsCommand, Mode=OneWay}" IsEnabled="{Binding ConfirmButtonEnabled, 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="Cancel" Command="{Binding CloseWindowCommand, Mode=OneWay}" />
|
<ui:Button Content="{x:Static resources:Strings.Common_Cancel}" Command="{Binding CloseWindowCommand, Mode=OneWay}" />
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
</StatusBar>
|
</StatusBar>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -18,11 +18,7 @@
|
|||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<Border Grid.Column="0" Width="60" Height="60" VerticalAlignment="Center">
|
<Image Grid.Column="0" Width="60" Height="60" VerticalAlignment="Center" Source="pack://application:,,,/Bloxstrap.ico" RenderOptions.BitmapScalingMode="HighQuality" />
|
||||||
<Border.Background>
|
|
||||||
<ImageBrush ImageSource="pack://application:,,,/Bloxstrap.ico" />
|
|
||||||
</Border.Background>
|
|
||||||
</Border>
|
|
||||||
<StackPanel Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center">
|
<StackPanel Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@ -126,6 +122,7 @@
|
|||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
@ -151,7 +148,7 @@
|
|||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ui:CardAction>
|
</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/development/LICENSE">
|
<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>
|
<StackPanel>
|
||||||
<TextBlock FontSize="14" Text="DiscordRPC by Lachee" />
|
<TextBlock FontSize="14" Text="DiscordRPC by Lachee" />
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
@ -169,6 +166,12 @@
|
|||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ui:CardAction>
|
</ui:CardAction>
|
||||||
|
<ui:CardAction Grid.Row="2" Grid.ColumnSpan="3" 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 by xoofx" />
|
||||||
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="BSD 2-Clause License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:CardAction>
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ui:UiPage>
|
</ui:UiPage>
|
||||||
|
@ -134,6 +134,8 @@ namespace Bloxstrap.UI.Elements.Menu.Pages
|
|||||||
if (!newName.Contains(_searchFilter))
|
if (!newName.Contains(_searchFilter))
|
||||||
ClearSearch();
|
ClearSearch();
|
||||||
|
|
||||||
|
entry.Name = newName;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "Value":
|
case "Value":
|
||||||
|
@ -12,7 +12,7 @@ namespace Bloxstrap.UI
|
|||||||
|
|
||||||
public static MessageBoxResult ShowMessageBox(string message, MessageBoxImage icon = MessageBoxImage.None, MessageBoxButton buttons = MessageBoxButton.OK, MessageBoxResult defaultResult = MessageBoxResult.None)
|
public static MessageBoxResult ShowMessageBox(string message, MessageBoxImage icon = MessageBoxImage.None, MessageBoxButton buttons = MessageBoxButton.OK, MessageBoxResult defaultResult = MessageBoxResult.None)
|
||||||
{
|
{
|
||||||
if (App.IsQuiet)
|
if (App.LaunchSettings.IsQuiet)
|
||||||
return defaultResult;
|
return defaultResult;
|
||||||
|
|
||||||
switch (App.Settings.Prop.BootstrapperStyle)
|
switch (App.Settings.Prop.BootstrapperStyle)
|
||||||
@ -57,6 +57,8 @@ namespace Bloxstrap.UI
|
|||||||
BootstrapperStyle.ProgressDialog => new ProgressDialog(),
|
BootstrapperStyle.ProgressDialog => new ProgressDialog(),
|
||||||
BootstrapperStyle.FluentDialog => new FluentDialog(),
|
BootstrapperStyle.FluentDialog => new FluentDialog(),
|
||||||
BootstrapperStyle.ByfronDialog => new ByfronDialog(),
|
BootstrapperStyle.ByfronDialog => new ByfronDialog(),
|
||||||
|
BootstrapperStyle.ProgressFluentDialog => new ProgressFluentDialog(false),
|
||||||
|
BootstrapperStyle.ProgressFluentAeroDialog => new ProgressFluentDialog(true),
|
||||||
_ => new FluentDialog()
|
_ => new FluentDialog()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,12 @@ namespace Bloxstrap.UI.ViewModels.Bootstrapper
|
|||||||
public bool CancelEnabled { get; set; } = false;
|
public bool CancelEnabled { get; set; } = false;
|
||||||
public Visibility CancelButtonVisibility => CancelEnabled ? Visibility.Visible : Visibility.Collapsed;
|
public Visibility CancelButtonVisibility => CancelEnabled ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
|
||||||
|
[Obsolete("Do not use this! This is for the designer only.", true)]
|
||||||
|
public BootstrapperDialogViewModel()
|
||||||
|
{
|
||||||
|
_dialog = null!;
|
||||||
|
}
|
||||||
|
|
||||||
public BootstrapperDialogViewModel(IBootstrapperDialog dialog)
|
public BootstrapperDialogViewModel(IBootstrapperDialog dialog)
|
||||||
{
|
{
|
||||||
_dialog = dialog;
|
_dialog = dialog;
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using Wpf.Ui.Appearance;
|
||||||
|
|
||||||
|
namespace Bloxstrap.UI.ViewModels.Bootstrapper
|
||||||
|
{
|
||||||
|
public class ProgressFluentDialogViewModel : BootstrapperDialogViewModel
|
||||||
|
{
|
||||||
|
public BackgroundType WindowBackdropType { get; set; } = BackgroundType.Mica;
|
||||||
|
public SolidColorBrush BackgroundColourBrush { get; set; } = new SolidColorBrush(Color.FromArgb(0, 0, 0, 0));
|
||||||
|
|
||||||
|
[Obsolete("Do not use this! This is for the designer only.", true)]
|
||||||
|
public ProgressFluentDialogViewModel() : base()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public ProgressFluentDialogViewModel(IBootstrapperDialog dialog, bool aero) : base(dialog)
|
||||||
|
{
|
||||||
|
const int alpha = 128;
|
||||||
|
|
||||||
|
WindowBackdropType = aero ? BackgroundType.Aero : BackgroundType.Mica;
|
||||||
|
|
||||||
|
if (aero)
|
||||||
|
BackgroundColourBrush = App.Settings.Prop.Theme.GetFinal() == Enums.Theme.Light ?
|
||||||
|
new SolidColorBrush(Color.FromArgb(alpha, 225, 225, 225)) :
|
||||||
|
new SolidColorBrush(Color.FromArgb(alpha, 30, 30, 30));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,9 +23,9 @@ namespace Bloxstrap.UI.ViewModels.Menu
|
|||||||
IBootstrapperDialog dialog = App.Settings.Prop.BootstrapperStyle.GetNew();
|
IBootstrapperDialog dialog = App.Settings.Prop.BootstrapperStyle.GetNew();
|
||||||
|
|
||||||
if (App.Settings.Prop.BootstrapperStyle == BootstrapperStyle.ByfronDialog)
|
if (App.Settings.Prop.BootstrapperStyle == BootstrapperStyle.ByfronDialog)
|
||||||
dialog.Message = "Style preview - Click the X button at the top right to close";
|
dialog.Message = Resources.Strings.Bootstrapper_StylePreview_ImageCancel;
|
||||||
else
|
else
|
||||||
dialog.Message = "Style preview - Click Cancel to close";
|
dialog.Message = Resources.Strings.Bootstrapper_StylePreview_TextCancel;
|
||||||
|
|
||||||
dialog.CancelEnabled = true;
|
dialog.CancelEnabled = true;
|
||||||
dialog.ShowBootstrapper();
|
dialog.ShowBootstrapper();
|
||||||
@ -65,7 +65,7 @@ namespace Bloxstrap.UI.ViewModels.Menu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<BootstrapperStyle> Dialogs { get; } = Enum.GetValues(typeof(BootstrapperStyle)).Cast<BootstrapperStyle>();
|
public IEnumerable<BootstrapperStyle> Dialogs { get; } = BootstrapperStyleEx.Selections;
|
||||||
|
|
||||||
public BootstrapperStyle Dialog
|
public BootstrapperStyle Dialog
|
||||||
{
|
{
|
||||||
|
@ -28,7 +28,7 @@ namespace Bloxstrap.UI.ViewModels.Menu
|
|||||||
|
|
||||||
public ICommand OpenFastFlagEditorCommand => new RelayCommand(OpenFastFlagEditor);
|
public ICommand OpenFastFlagEditorCommand => new RelayCommand(OpenFastFlagEditor);
|
||||||
|
|
||||||
public Visibility ShowDebugFlags => App.Settings.Prop.OhHeyYouFoundMe ? Visibility.Visible : Visibility.Collapsed;
|
public Visibility ShowDebugFlags => App.Settings.Prop.PowerTools ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
|
||||||
public bool HttpRequestLogging
|
public bool HttpRequestLogging
|
||||||
{
|
{
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
[](https://discord.gg/nKjV3mGq6R)
|
[](https://discord.gg/nKjV3mGq6R)
|
||||||
[](https://media.tenor.com/FIkSGbGycmAAAAAd/manly-roblox.gif)
|
[](https://media.tenor.com/FIkSGbGycmAAAAAd/manly-roblox.gif)
|
||||||
|
|
||||||
An open-source, feature-packed alternative bootstrapper for Roblox.
|
An open-source, alternative bootstrapper for Roblox.
|
||||||
|
|
||||||
This a drop-in replacement for the stock Roblox bootstrapper, working more or less how you'd expect it to, while providing additional useful features. This does not touch or modify the game client itself, it's just a launcher! So don't worry, there's practically no risk of being banned for using this.
|
This is a drop-in replacement for the standard Roblox bootstrapper, providing additional useful features and improvements. This does not touch or modify the game client itself, it's just a launcher! So don't worry, there's no risk of being banned 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) or report it in our [Discord server](https://discord.gg/nKjV3mGq6R).
|
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).
|
||||||
|
|
||||||
@ -32,7 +32,6 @@ Once installed, Bloxstrap is added to your Start Menu, where you can access the
|
|||||||
Here's some of the features that Bloxstrap provides over the stock Roblox bootstrapper:
|
Here's some of the features that Bloxstrap provides over the stock Roblox bootstrapper:
|
||||||
|
|
||||||
* Persistent file modifications, includes re-adding the old death sound!
|
* Persistent file modifications, includes re-adding the old death sound!
|
||||||
* Support for easy and simple FastFlag editing, no need to mess around with a JSON file.
|
|
||||||
* Painless and seamless support for Discord Rich Presence - no auth cookie needed!
|
* Painless and seamless support for Discord Rich Presence - no auth cookie needed!
|
||||||
* A customizable launcher look
|
* A customizable launcher look
|
||||||
* Lets you see what region your current server is located in
|
* Lets you see what region your current server is located in
|
||||||
@ -45,10 +44,8 @@ Bloxstrap also only runs whenever necessary, so it doesn't stay running in the b
|
|||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||
<p float="left">
|
<p float="left">
|
||||||
<img src="https://github.com/pizzaboxer/bloxstrap/assets/41478239/cd723d23-9bff-401e-aadf-deea265a3b1c" width="829" />
|
|
||||||
<img src="https://github.com/pizzaboxer/bloxstrap/assets/41478239/dcfd0cdf-1aae-45bb-849a-f7710ec63b28" width="435" />
|
<img src="https://github.com/pizzaboxer/bloxstrap/assets/41478239/dcfd0cdf-1aae-45bb-849a-f7710ec63b28" width="435" />
|
||||||
<img src="https://github.com/pizzaboxer/bloxstrap/assets/41478239/e08cdf28-4f99-46b5-99f2-5c338aac86db" width="390" />
|
<img src="https://github.com/pizzaboxer/bloxstrap/assets/41478239/e08cdf28-4f99-46b5-99f2-5c338aac86db" width="390" />
|
||||||
<img src="https://github.com/pizzaboxer/bloxstrap/assets/41478239/a45755cb-39da-49df-b0ad-456a139e2efc" Width="593" />
|
|
||||||
<img src="https://github.com/pizzaboxer/bloxstrap/assets/41478239/7ba35223-9115-401f-bbc1-d15e9c5fd79e" width="232" />
|
<img src="https://github.com/pizzaboxer/bloxstrap/assets/41478239/7ba35223-9115-401f-bbc1-d15e9c5fd79e" width="232" />
|
||||||
<p>
|
<p>
|
||||||
|
|
||||||
|
2
wpfui
2
wpfui
@ -1 +1 @@
|
|||||||
Subproject commit 55d5ca08f9a1d7623f9a7e386e1f4ac9f2d024a7
|
Subproject commit 8f61545b386cc393f4502fb485cae9f052afbd46
|
Loading…
Reference in New Issue
Block a user