Merge pull request #78 from pizzaboxer/menu-redesign-v3

Menu redesign
This commit is contained in:
pizzaboxer 2023-02-03 19:04:10 +00:00 committed by GitHub
commit 6fa7a73ac7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 1448 additions and 19079 deletions

View File

@ -1,12 +1,13 @@
<Application x:Class="Bloxstrap.App" <Application x:Class="Bloxstrap.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Bloxstrap"> xmlns:local="clr-namespace:Bloxstrap"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml">
<Application.Resources> <Application.Resources>
<ResourceDictionary> <ResourceDictionary>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<!--<ResourceDictionary Source="Themes\ColourfulDarkTheme.xaml" />--> <ui:ThemesDictionary Theme="Dark" />
<ResourceDictionary Source="Dialogs\Menu\Themes\LightTheme.xaml" /> <ui:ControlsDictionary />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
</Application.Resources> </Application.Resources>

View File

@ -6,13 +6,12 @@ using System.Net.Http;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using System.Windows; using System.Windows;
using Microsoft.Win32; using Microsoft.Win32;
using Bloxstrap.Models; using Bloxstrap.Models;
using Bloxstrap.Dialogs.Menu;
using Bloxstrap.Enums; using Bloxstrap.Enums;
using Bloxstrap.Helpers; using Bloxstrap.Helpers;
using Bloxstrap.Views;
namespace Bloxstrap namespace Bloxstrap
{ {
@ -21,13 +20,13 @@ namespace Bloxstrap
/// </summary> /// </summary>
public partial class App : Application public partial class App : Application
{ {
public const StringComparison StringFormat = StringComparison.InvariantCulture;
public static readonly CultureInfo CultureFormat = CultureInfo.InvariantCulture; public static readonly CultureInfo CultureFormat = CultureInfo.InvariantCulture;
public const string ProjectName = "Bloxstrap"; public const string ProjectName = "Bloxstrap";
public const string ProjectRepository = "pizzaboxer/bloxstrap"; public const string ProjectRepository = "pizzaboxer/bloxstrap";
public static string BaseDirectory = null!; public static string BaseDirectory = null!;
public static bool IsSetupComplete { get; set; } = true;
public static bool IsFirstRun { get; private set; } = false; public static bool IsFirstRun { get; private set; } = false;
public static bool IsQuiet { get; private set; } = false; public static bool IsQuiet { get; private set; } = false;
public static bool IsUninstall { get; private set; } = false; public static bool IsUninstall { get; private set; } = false;
@ -92,11 +91,13 @@ namespace Bloxstrap
{ {
IsFirstRun = true; IsFirstRun = true;
Settings = SettingsManager.Settings; Settings = SettingsManager.Settings;
BaseDirectory = Path.Combine(Directories.LocalAppData, ProjectName);
if (IsQuiet) if (!IsQuiet)
BaseDirectory = Path.Combine(Directories.LocalAppData, ProjectName); {
else IsSetupComplete = false;
new Preferences().ShowDialog(); new MainWindow().ShowDialog();
}
} }
else else
{ {
@ -105,8 +106,7 @@ namespace Bloxstrap
} }
// preferences dialog was closed, and so base directory was never set // preferences dialog was closed, and so base directory was never set
// (this doesnt account for the registry value not existing but thats basically never gonna happen) if (!IsSetupComplete)
if (String.IsNullOrEmpty(BaseDirectory))
Environment.Exit(Bootstrapper.ERROR_INSTALL_USEREXIT); Environment.Exit(Bootstrapper.ERROR_INSTALL_USEREXIT);
Directories.Initialize(BaseDirectory); Directories.Initialize(BaseDirectory);
@ -140,7 +140,8 @@ namespace Bloxstrap
} }
#endif #endif
new Preferences().ShowDialog(); //new Preferences().ShowDialog();
new MainWindow().ShowDialog();
} }
else if (LaunchArgs[0].StartsWith("roblox-player:")) else if (LaunchArgs[0].StartsWith("roblox-player:"))
{ {

View File

@ -9,8 +9,13 @@
<ApplicationIcon>Bloxstrap.ico</ApplicationIcon> <ApplicationIcon>Bloxstrap.ico</ApplicationIcon>
<Version>2.0.0</Version> <Version>2.0.0</Version>
<FileVersion>2.0.0.0</FileVersion> <FileVersion>2.0.0.0</FileVersion>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<None Remove="Resources\IconBloxstrap-png.png" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Bloxstrap.ico" /> <Content Include="Bloxstrap.ico" />
</ItemGroup> </ItemGroup>
@ -22,9 +27,15 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0" />
<PackageReference Include="DiscordRichPresence" Version="1.1.3.18" /> <PackageReference Include="DiscordRichPresence" Version="1.1.3.18" />
<PackageReference Include="ini-parser-netstandard" Version="2.5.2" /> <PackageReference Include="ini-parser-netstandard" Version="2.5.2" />
<PackageReference Include="securifybv.ShellLink" Version="0.1.0" /> <PackageReference Include="securifybv.ShellLink" Version="0.1.0" />
<PackageReference Include="WPF-UI" Version="2.0.3" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\IconBloxstrap-png.png" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -11,7 +11,7 @@ using System.Windows;
using Microsoft.Win32; using Microsoft.Win32;
using Bloxstrap.Dialogs.BootstrapperDialogs; using Bloxstrap.Dialogs;
using Bloxstrap.Helpers; using Bloxstrap.Helpers;
using Bloxstrap.Helpers.Integrations; using Bloxstrap.Helpers.Integrations;
using Bloxstrap.Helpers.RSMM; using Bloxstrap.Helpers.RSMM;
@ -381,7 +381,20 @@ namespace Bloxstrap
.WriteToFile(Path.Combine(Directories.StartMenu, "Play Roblox.lnk")); .WriteToFile(Path.Combine(Directories.StartMenu, "Play Roblox.lnk"));
ShellLink.Shortcut.CreateShortcut(Directories.Application, "-preferences", Directories.Application, 0) ShellLink.Shortcut.CreateShortcut(Directories.Application, "-preferences", Directories.Application, 0)
.WriteToFile(Path.Combine(Directories.StartMenu, $"Configure {App.ProjectName}.lnk")); .WriteToFile(Path.Combine(Directories.StartMenu, $"{App.ProjectName} Menu.lnk"));
}
else
{
// v2.0.0 - rebadge configuration menu as just "Bloxstrap Menu"
string oldMenuShortcut = Path.Combine(Directories.StartMenu, $"Configure {App.ProjectName}.lnk");
string newMenuShortcut = Path.Combine(Directories.StartMenu, $"{App.ProjectName} Menu.lnk");
if (File.Exists(oldMenuShortcut))
File.Delete(oldMenuShortcut);
if (!File.Exists(newMenuShortcut))
ShellLink.Shortcut.CreateShortcut(Directories.Application, "-preferences", Directories.Application, 0)
.WriteToFile(newMenuShortcut);
} }
if (App.Settings.CreateDesktopIcon && !File.Exists(Path.Combine(Directories.Desktop, "Play Roblox.lnk"))) if (App.Settings.CreateDesktopIcon && !File.Exists(Path.Combine(Directories.Desktop, "Play Roblox.lnk")))
@ -449,6 +462,12 @@ namespace Bloxstrap
private void UpdateProgressbar() private void UpdateProgressbar()
{ {
int newProgress = (int)Math.Floor(ProgressIncrement * TotalDownloadedBytes); int newProgress = (int)Math.Floor(ProgressIncrement * TotalDownloadedBytes);
// bugcheck: if we're restoring a file from a package, it'll incorrectly increment the progress beyond 100
// too lazy to fix properly so lol
if (newProgress > 100)
return;
Dialog.ProgressValue = newProgress; Dialog.ProgressValue = newProgress;
} }

View File

@ -6,7 +6,7 @@ using System.Windows.Forms;
using Bloxstrap.Enums; using Bloxstrap.Enums;
using Bloxstrap.Helpers; using Bloxstrap.Helpers;
namespace Bloxstrap.Dialogs.BootstrapperDialogs namespace Bloxstrap.Dialogs
{ {
public class BootstrapperDialogForm : Form, IBootstrapperDialog public class BootstrapperDialogForm : Form, IBootstrapperDialog
{ {
@ -84,13 +84,13 @@ namespace Bloxstrap.Dialogs.BootstrapperDialogs
if (Bootstrapper is null) if (Bootstrapper is null)
{ {
Message = "Style Preview - Click Cancel to return"; Message = "Style preview - Click Cancel to close";
CancelEnabled = true; CancelEnabled = true;
} }
else else
{ {
Bootstrapper.Dialog = this; Bootstrapper.Dialog = this;
Task.Run(() => RunBootstrapper()); Task.Run(RunBootstrapper);
} }
} }

View File

@ -1,6 +1,6 @@
using System.Windows.Forms; using System.Windows.Forms;
namespace Bloxstrap.Dialogs.BootstrapperDialogs namespace Bloxstrap.Dialogs
{ {
public interface IBootstrapperDialog public interface IBootstrapperDialog
{ {

View File

@ -1,6 +1,6 @@
using System.Windows.Forms; using System.Windows.Forms;
namespace Bloxstrap.Dialogs.BootstrapperDialogs namespace Bloxstrap.Dialogs
{ {
partial class LegacyDialog2009 partial class LegacyDialog2009
{ {

View File

@ -1,7 +1,7 @@
using System; using System;
using System.Windows.Forms; using System.Windows.Forms;
namespace Bloxstrap.Dialogs.BootstrapperDialogs namespace Bloxstrap.Dialogs
{ {
// windows: https://youtu.be/VpduiruysuM?t=18 // windows: https://youtu.be/VpduiruysuM?t=18
// mac: https://youtu.be/ncHhbcVDRgQ?t=63 // mac: https://youtu.be/ncHhbcVDRgQ?t=63

View File

@ -1,6 +1,6 @@
using System.Windows.Forms; using System.Windows.Forms;
namespace Bloxstrap.Dialogs.BootstrapperDialogs namespace Bloxstrap.Dialogs
{ {
partial class LegacyDialog2011 partial class LegacyDialog2011
{ {

View File

@ -3,7 +3,7 @@ using System.Windows.Forms;
using Bloxstrap.Enums; using Bloxstrap.Enums;
namespace Bloxstrap.Dialogs.BootstrapperDialogs namespace Bloxstrap.Dialogs
{ {
// https://youtu.be/3K9oCEMHj2s?t=35 // https://youtu.be/3K9oCEMHj2s?t=35

View File

@ -1,31 +0,0 @@
<Window x:Class="Bloxstrap.Dialogs.Menu.ModHelp"
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:local="clr-namespace:Bloxstrap.Dialogs.Menu"
mc:Ignorable="d"
Style="{DynamicResource MainWindowStyle}"
Title="Modification Help"
SizeToContent="WidthAndHeight"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen">
<Grid Width="420" Height="260">
<StackPanel Margin="10">
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Modification Help" VerticalAlignment="Top" FontSize="18" />
<StackPanel Margin="10">
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="The Modifications folder is where you can modify your Roblox files while ensuring that they're preserved whenever Roblox updates." />
<TextBlock HorizontalAlignment="Left" Margin="0,10,0,0" TextWrapping="Wrap" Text="For example, Modifications\content\sounds\ouch.ogg will automatically override Versions\Version-{id}\content\sounds\ouch.ogg" />
<TextBlock HorizontalAlignment="Left" Margin="0,10,0,0" TextWrapping="Wrap" Text="When you remove a file from the folder, Bloxstrap restores the original version of the file the next time Roblox launches." />
<TextBlock HorizontalAlignment="Left" Margin="0,10,0,0" TextWrapping="Wrap" Text="The folder is also used for handling presets and files for ReShade, so if you find any files or folders that already exist, you can just ignore them." />
</StackPanel>
</StackPanel>
<Border Background="{DynamicResource ControlSelectedBackground}" BorderBrush="{DynamicResource ControlSelectedBorderBrush}" BorderThickness="1" Margin="-1,0,-1,0" Height="42" VerticalAlignment="Bottom">
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="ButtonClose" Content="Close" Width="66" Height="23" HorizontalAlignment="Right" Margin="0,0,10,0" Click="ButtonClose_Click" />
</StackPanel>
</Grid>
</Border>
</Grid>
</Window>

View File

@ -1,21 +0,0 @@
using System;
using System.Windows;
namespace Bloxstrap.Dialogs.Menu
{
/// <summary>
/// Interaction logic for ModHelp.xaml
/// </summary>
public partial class ModHelp : Window
{
public ModHelp()
{
InitializeComponent();
}
private void ButtonClose_Click(object sender, EventArgs e)
{
this.Close();
}
}
}

View File

@ -1,169 +0,0 @@
<Window x:Class="Bloxstrap.Dialogs.Menu.Preferences"
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:local="clr-namespace:Bloxstrap.Dialogs.Menu"
mc:Ignorable="d"
Style="{DynamicResource MainWindowStyle}"
Title="PreferencesWPF"
SizeToContent="WidthAndHeight"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen">
<Grid Width="480" Height="360">
<TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Configure Bloxstrap" VerticalAlignment="Top" FontSize="18"/>
<TextBlock HorizontalAlignment="Right" Margin="0,14,10,0" TextWrapping="Wrap" Text="{Binding BloxstrapVersion, Mode=OneTime}" VerticalAlignment="Top" FontSize="12"/>
<TabControl TabStripPlacement="Left" Margin="10,40,10,51" Padding="0">
<TabItem Padding="5">
<TabItem.Header>
<TextBlock Text="Integrations" FontSize="13" />
</TabItem.Header>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<GroupBox Grid.Column="0" Header="Discord Rich Presence" Margin="10,10,5,5">
<StackPanel VerticalAlignment="Center">
<CheckBox x:Name="CheckBoxDRPEnabled" Content=" Show game activity" ToolTip="Choose whether the game you're currently playing should be shown on your Discord game activity." Margin="5" IsChecked="{Binding DRPEnabled, Mode=TwoWay}" />
<CheckBox x:Name="CheckBoxDRPButtons" Content=" Allow activity joining" ToolTip="Choose whether people can join the game you're in through your Discord game activity." Margin="5" IsEnabled="{Binding IsChecked, ElementName=CheckBoxDRPEnabled, Mode=OneWay}" IsChecked="{Binding DRPButtons, Mode=TwoWay}" />
</StackPanel>
</GroupBox>
<GroupBox Grid.Column="1" Header="FPS Unlocking" Margin="5,10,10,5">
<StackPanel VerticalAlignment="Center">
<CheckBox x:Name="CheckBoxRFUEnabled" Content=" Use rbxfpsunlocker" ToolTip="Choose whether rbxfpsunlocker should be downloaded and launched whenever Roblox starts." Margin="5" IsChecked="{Binding RFUEnabled, Mode=TwoWay}" />
<CheckBox x:Name="CheckBoxRFUAutoclose" Content=" Exit when Roblox closes" ToolTip="Choose whether rbxfpsunlocker should stop running when Roblox closes." Margin="5" IsEnabled="{Binding IsChecked, ElementName=CheckBoxRFUEnabled, Mode=OneWay}" IsChecked="{Binding RFUAutoclose, Mode=TwoWay}" />
</StackPanel>
</GroupBox>
</Grid>
<GroupBox Header="ReShade" Margin="10,5,10,0">
<StackPanel VerticalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="155" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" x:Name="CheckBoxUseReShade" Content=" Use ReShade" ToolTip="Choose whether to use ReShade to enhance your graphics with shaders." Margin="5" IsChecked="{Binding UseReShade, Mode=TwoWay}" />
<CheckBox Grid.Column="1" x:Name="CheckBoxUseReShadeExtraviPresets" Content=" Use Extravi's shader presets" ToolTip="Choose whether to use Extravi's shader presets with ReShade." Margin="5" IsEnabled="{Binding IsChecked, ElementName=CheckBoxUseReShade, Mode=OneWay}" IsChecked="{Binding UseReShadeExtraviPresets, Mode=TwoWay}" />
</Grid>
<Grid Margin="5,5,5,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" x:Name="ButtonOpenReShadeFolder" ToolTip="{Binding ReShadeFolderButtonTooltip, Mode=OneTime}" IsEnabled="{Binding ReShadeFolderButtonEnabled, Mode=OneTime}" Content="Open ReShade folder" Height="23" Margin="0,0,5,0" Click="ButtonOpenReShadeFolder_Click" />
<Button Grid.Column="1" x:Name="ButtonOpenReShadeHelp" Content="Help" Height="23" Margin="5,0,0,0" Click="ButtonOpenReShadeHelp_Click" />
</Grid>
</StackPanel>
</GroupBox>
</StackPanel>
</TabItem>
<TabItem Padding="5">
<TabItem.Header>
<TextBlock Text="Modifications" FontSize="13" />
</TabItem.Header>
<StackPanel>
<GroupBox Header="Presets" Margin="10,10,10,5">
<StackPanel VerticalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<CheckBox x:Name="CheckBoxModDeathSound" Content=" Use old death sound" Margin="5" IsChecked="{Binding ModOldDeathSound, Mode=TwoWay}" />
<CheckBox x:Name="CheckBoxModMouseCursor" Content=" Use old mouse cursor" Margin="5" IsChecked="{Binding ModOldMouseCursor, Mode=TwoWay}" />
</StackPanel>
<StackPanel Grid.Column="1">
<CheckBox x:Name="CheckBoxDisableAppPatch" Content=" Disable desktop app" Margin="5" IsChecked="{Binding ModDisableAppPatch, Mode=TwoWay}" />
</StackPanel>
</Grid>
</StackPanel>
</GroupBox>
<Grid Margin="10,5,10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" x:Name="ButtonOpenModFolder" Content="Open Modifications folder" ToolTip="{Binding ModFolderButtonTooltip, Mode=OneTime}" IsEnabled="{Binding ModFolderButtonEnabled, Mode=OneTime}" Height="23" Margin="0,0,5,0" Click="ButtonOpenModFolder_Click" />
<Button Grid.Column="1" x:Name="ButtonOpenModHelp" Content="Help" Height="23" Margin="5,0,0,0" Click="ButtonOpenModHelp_Click" />
</Grid>
</StackPanel>
</TabItem>
<TabItem Padding="5">
<TabItem.Header>
<TextBlock Text="Installation" FontSize="13" />
</TabItem.Header>
<StackPanel>
<GroupBox Header="Location" Margin="10,10,10,5">
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" x:Name="TextBoxInstallLocation" Padding="0,1,0,2" Margin="0,0,5,0" Text="{Binding InstallLocation, Mode=OneWay}" />
<Button Grid.Column="1" x:Name="ButtonInstallLocationBrowse" Content="Browse..." Margin="5,0,0,0" Click="ButtonLocationBrowse_Click" />
</Grid>
</GroupBox>
<GroupBox Header="Channel" Margin="10,5,10,5">
<StackPanel VerticalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="130" />
</Grid.ColumnDefinitions>
<ComboBox x:Name="ComboBoxChannel" ToolTip="Choose which release channel to download Roblox from. If you're not sure what this does, just leave it as LIVE." Margin="5" ItemsSource="{Binding Channels, Mode=OneWay}" Text="{Binding Channel, Mode=TwoWay}" />
<CheckBox Grid.Column="1" x:Name="CheckBoxShowAllChannels" Content=" Show all channels" VerticalAlignment="Center" Margin="5" IsChecked="{Binding ShowAllChannels, Mode=TwoWay}" />
</Grid>
<TextBlock x:Name="TextBlockChannelInfo" Text="{Binding ChannelInfo, Mode=OneWay}" TextWrapping="Wrap" Margin="5" />
<CheckBox x:Name="TextBoxPromptChannelChange" Content=" Prompt on Roblox-forced channel change" ToolTip="Choose whether to be prompted when Roblox mandates a channel change through the website. Otherwise, the channel changes automatically." Margin="5" IsChecked="{Binding PromptChannelChange, Mode=TwoWay}" />
</StackPanel>
</GroupBox>
</StackPanel>
</TabItem>
<TabItem Padding="5">
<TabItem.Header>
<TextBlock Text="Bloxstrap" FontSize="13" />
</TabItem.Header>
<StackPanel>
<GroupBox Header="Style" Margin="10,10,10,0">
<StackPanel Margin="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Theme*" VerticalAlignment="Center" Margin="0,0,0,5" />
<ComboBox Grid.Row="0" Grid.Column="1" x:Name="ComboBoxTheme" VerticalAlignment="Center" Margin="0,0,0,0" ItemsSource="{Binding Themes.Keys, Mode=OneTime}" Text="{Binding Theme, Mode=TwoWay}" />
<TextBlock Grid.Row="1" Grid.Column="1" Text="*Dark theme only applies to the Progress dialog" FontSize="10" VerticalAlignment="Center" Margin="0,0,0,5" />
<TextBlock Grid.Row="2" Grid.Column="0" Text="Dialog" VerticalAlignment="Center" Margin="0,5,0,5" />
<ComboBox Grid.Row="2" Grid.Column="1" x:Name="ComboBoxDialog" VerticalAlignment="Center" Margin="0,5,0,5" ItemsSource="{Binding Dialogs.Keys, Mode=OneTime}" Text="{Binding Dialog, Mode=TwoWay}" />
<TextBlock Grid.Row="3" Grid.Column="0" Text="Icon" VerticalAlignment="Center" Margin="0,5,0,5" />
<ComboBox Grid.Row="3" Grid.Column="1" x:Name="ComboBoxIcon" VerticalAlignment="Center" Margin="0,5,0,5" ItemsSource="{Binding Icons.Keys, Mode=OneTime}" Text="{Binding Icon, Mode=TwoWay}" />
</Grid>
<Button x:Name="ButtonPreview" Content="Preview" Margin="0,5,0,0" VerticalAlignment="Bottom" Height="23" Click="ButtonPreview_Click" />
</StackPanel>
</GroupBox>
<CheckBox Content=" Create desktop icon" IsChecked="{Binding CreateDesktopIcon, Mode=TwoWay}" Margin="10,10,10,0" />
<CheckBox Content=" Check for Bloxstrap updates on startup" IsChecked="{Binding CheckForUpdates, Mode=TwoWay}" Margin="10,10,10,0" />
</StackPanel>
</TabItem>
</TabControl>
<Border Background="{DynamicResource ControlSelectedBackground}" BorderBrush="{DynamicResource ControlSelectedBorderBrush}" BorderThickness="1" Margin="-1,0,-1,0" Height="42" VerticalAlignment="Bottom">
<Grid>
<TextBlock Text="Like Bloxstrap? " VerticalAlignment="Center" Margin="10,0,0,0" ><Hyperlink NavigateUri="https://github.com/pizzaboxer/bloxstrap" RequestNavigate="Hyperlink_RequestNavigate">Leave a star on GitHub!</Hyperlink></TextBlock>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="ButtonConfirm" Content="{Binding ConfirmButtonText, Mode=OneTime}" Width="66" Height="23" HorizontalAlignment="Right" Margin="0,0,10,0" Click="ButtonConfirm_Click" />
<Button x:Name="ButtonCancel" Content="Cancel" Width="66" Height="23" HorizontalAlignment="Right" Margin="0,0,10,0" Click="ButtonCancel_Click" />
</StackPanel>
</Grid>
</Border>
</Grid>
</Window>

View File

@ -1,424 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using Microsoft.Win32;
using Bloxstrap.Enums;
using Bloxstrap.Helpers;
using Bloxstrap.Models;
namespace Bloxstrap.Dialogs.Menu
{
/// <summary>
/// Interaction logic for PreferencesWPF.xaml
/// </summary>
public partial class Preferences : Window
{
public readonly PreferencesViewModel ViewModel;
public Preferences()
{
InitializeComponent();
SetTheme();
ViewModel = new(this);
this.DataContext = ViewModel;
App.SettingsManager.ShouldSave = false;
this.Icon = Imaging.CreateBitmapSourceFromHIcon(
Properties.Resources.IconBloxstrap_ico.Handle,
Int32Rect.Empty,
BitmapSizeOptions.FromEmptyOptions()
);
this.Title = App.ProjectName;
// just in case i guess?
if (!Environment.Is64BitOperatingSystem)
this.CheckBoxRFUEnabled.IsEnabled = false;
}
public void SetTheme()
{
string theme = "Light";
if (App.Settings.Theme.GetFinal() == Theme.Dark)
theme = "ColourfulDark";
Application.Current.Resources.MergedDictionaries[0] = new ResourceDictionary() { Source = new Uri($"Dialogs/Menu/Themes/{theme}Theme.xaml", UriKind.Relative) };
}
private void ButtonOpenReShadeFolder_Click(object sender, EventArgs e)
{
Process.Start("explorer.exe", Directories.ReShade);
}
private void ButtonOpenReShadeHelp_Click(object sender, EventArgs e)
{
new ReShadeHelp().Show();
}
private void ButtonOpenModFolder_Click(object sender, EventArgs e)
{
Process.Start("explorer.exe", Directories.Modifications);
}
private void ButtonOpenModHelp_Click(object sender, EventArgs e)
{
new ModHelp().Show();
}
private void ButtonLocationBrowse_Click(object sender, EventArgs e)
{
using (var dialog = new System.Windows.Forms.FolderBrowserDialog())
{
if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
ViewModel.InstallLocation = dialog.SelectedPath;
}
}
private void ButtonPreview_Click(object sender, EventArgs e)
{
//this.Visible = false;
App.Settings.BootstrapperStyle.Show();
//this.Visible = true;
}
private void ButtonCancel_Click(object sender, EventArgs e)
{
this.Close();
}
private void ButtonConfirm_Click(object sender, EventArgs e)
{
string installLocation = this.TextBoxInstallLocation.Text;
if (String.IsNullOrEmpty(installLocation))
{
App.ShowMessageBox("You must set an install location", MessageBoxImage.Error);
return;
}
try
{
// check if we can write to the directory (a bit hacky but eh)
string testPath = installLocation;
string testFile = Path.Combine(installLocation, "BloxstrapWriteTest.txt");
bool testPathExists = Directory.Exists(testPath);
if (!testPathExists)
Directory.CreateDirectory(testPath);
File.WriteAllText(testFile, "hi");
File.Delete(testFile);
if (!testPathExists)
Directory.Delete(testPath);
}
catch (UnauthorizedAccessException)
{
App.ShowMessageBox($"{App.ProjectName} does not have write access to the install location you selected. Please choose another install location.", MessageBoxImage.Error);
return;
}
catch (Exception ex)
{
App.ShowMessageBox(ex.Message, MessageBoxImage.Error);
return;
}
if (App.IsFirstRun)
{
// this will be set in the registry after first install
App.BaseDirectory = installLocation;
}
else
{
App.SettingsManager.ShouldSave = true;
if (App.BaseDirectory is not null && App.BaseDirectory != installLocation)
{
App.ShowMessageBox($"{App.ProjectName} will install to the new location you've set the next time it runs.", MessageBoxImage.Information);
App.Settings.VersionGuid = "";
using (RegistryKey registryKey = Registry.CurrentUser.CreateSubKey($@"Software\{App.ProjectName}"))
{
registryKey.SetValue("InstallLocation", installLocation);
registryKey.SetValue("OldInstallLocation", App.BaseDirectory);
}
// preserve settings
// we don't need to copy the bootstrapper over since the install process will do that automatically
App.SettingsManager.Save();
File.Copy(Path.Combine(App.BaseDirectory, "Settings.json"), Path.Combine(installLocation, "Settings.json"));
}
}
this.Close();
}
private void Hyperlink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
{
Utilities.OpenWebsite(e.Uri.AbsoluteUri);
e.Handled = true;
}
}
public class PreferencesViewModel : INotifyPropertyChanged
{
private readonly Preferences _window;
public event PropertyChangedEventHandler? PropertyChanged;
public string BloxstrapVersion { get; } = $"Version {App.Version}";
#region Integrations
public bool DRPEnabled
{
get => App.Settings.UseDiscordRichPresence;
set
{
// if user wants discord rpc, auto-enable buttons by default
_window.CheckBoxDRPButtons.IsChecked = value;
App.Settings.UseDiscordRichPresence = value;
}
}
public bool DRPButtons
{
get => !App.Settings.HideRPCButtons;
set => App.Settings.HideRPCButtons = !value;
}
public bool RFUEnabled
{
get => App.Settings.RFUEnabled;
set
{
// if user wants to use rbxfpsunlocker, auto-enable autoclosing by default
_window.CheckBoxRFUAutoclose.IsChecked = value;
App.Settings.RFUEnabled = value;
}
}
public bool RFUAutoclose
{
get => App.Settings.RFUAutoclose;
set => App.Settings.RFUAutoclose = value;
}
public bool UseReShade
{
get => App.Settings.UseReShade;
set
{
// if user wants to use reshade, auto-enable use of extravi's presets by default
_window.CheckBoxUseReShadeExtraviPresets.IsChecked = value;
App.Settings.UseReShade = value;
}
}
public bool UseReShadeExtraviPresets
{
get => App.Settings.UseReShadeExtraviPresets;
set => App.Settings.UseReShadeExtraviPresets = value;
}
public bool ReShadeFolderButtonEnabled { get; } = !App.IsFirstRun;
public string ReShadeFolderButtonTooltip { get; } = App.IsFirstRun ? "Bloxstrap must first be installed before managing ReShade" : "This is the folder that contains all your ReShade resources for presets, shaders and textures.";
#endregion
#region Modifications
public bool ModOldDeathSound
{
get => App.Settings.UseOldDeathSound;
set => App.Settings.UseOldDeathSound = value;
}
public bool ModOldMouseCursor
{
get => App.Settings.UseOldMouseCursor;
set => App.Settings.UseOldMouseCursor = value;
}
public bool ModDisableAppPatch
{
get => App.Settings.UseDisableAppPatch;
set => App.Settings.UseDisableAppPatch = value;
}
public bool ModFolderButtonEnabled { get; } = !App.IsFirstRun;
public string ModFolderButtonTooltip { get; } = App.IsFirstRun ? "Bloxstrap must first be installed before managing mods" : "This is the folder that contains all your file modifications, including presets and any ReShade files needed.";
#endregion
#region Installation
private string installLocation = App.IsFirstRun ? Path.Combine(Directories.LocalAppData, App.ProjectName) : App.BaseDirectory;
public string InstallLocation
{
get => installLocation;
set
{
installLocation = value;
OnPropertyChanged();
}
}
private bool showAllChannels = !DeployManager.ChannelsAbstracted.Contains(App.Settings.Channel);
public bool ShowAllChannels
{
get => showAllChannels;
set
{
if (value)
{
Channels = DeployManager.ChannelsAll;
}
else
{
Channels = DeployManager.ChannelsAbstracted;
Channel = DeployManager.DefaultChannel;
OnPropertyChanged("Channel");
}
showAllChannels = value;
}
}
private IEnumerable<string> channels = DeployManager.ChannelsAbstracted.Contains(App.Settings.Channel) ? DeployManager.ChannelsAbstracted : DeployManager.ChannelsAll;
public IEnumerable<string> Channels
{
get => channels;
set
{
channels = value;
OnPropertyChanged();
}
}
public string Channel
{
get => App.Settings.Channel;
set
{
Task.Run(() => GetChannelInfo(value));
App.Settings.Channel = value;
}
}
private string channelInfo = "Getting latest version info, please wait...\n";
public string ChannelInfo
{
get => channelInfo;
set
{
channelInfo = value;
OnPropertyChanged();
}
}
public bool PromptChannelChange
{
get => App.Settings.PromptChannelChange;
set => App.Settings.PromptChannelChange = value;
}
#endregion
#region Bloxstrap
public IReadOnlyDictionary<string, Theme> Themes { get; set; } = new Dictionary<string, Theme>()
{
{ "System Default", Enums.Theme.Default },
{ "Light", Enums.Theme.Light },
{ "Dark", Enums.Theme.Dark },
};
public string Theme
{
get => Themes.FirstOrDefault(x => x.Value == App.Settings.Theme).Key;
set
{
App.Settings.Theme = Themes[value];
_window.SetTheme();
}
}
public IReadOnlyDictionary<string, BootstrapperStyle> Dialogs { get; set; } = new Dictionary<string, BootstrapperStyle>()
{
{ "Vista (2009 - 2011)", BootstrapperStyle.VistaDialog },
{ "Legacy (2009 - 2011)", BootstrapperStyle.LegacyDialog2009 },
{ "Legacy (2011 - 2014)", BootstrapperStyle.LegacyDialog2011 },
{ "Progress (~2014)", BootstrapperStyle.ProgressDialog },
};
public string Dialog
{
get => Dialogs.FirstOrDefault(x => x.Value == App.Settings.BootstrapperStyle).Key;
set => App.Settings.BootstrapperStyle = Dialogs[value];
}
public IReadOnlyDictionary<string, BootstrapperIcon> Icons { get; set; } = new Dictionary<string, BootstrapperIcon>()
{
{ "Bloxstrap", BootstrapperIcon.IconBloxstrap },
{ "2009", BootstrapperIcon.Icon2009 },
{ "2011", BootstrapperIcon.Icon2011 },
{ "2015", BootstrapperIcon.IconEarly2015 },
{ "2016", BootstrapperIcon.IconLate2015 },
{ "2017", BootstrapperIcon.Icon2017 },
{ "2019", BootstrapperIcon.Icon2019 },
{ "2022", BootstrapperIcon.Icon2022 }
};
public string Icon
{
get => Icons.FirstOrDefault(x => x.Value == App.Settings.BootstrapperIcon).Key;
set => App.Settings.BootstrapperIcon = Icons[value];
}
public bool CreateDesktopIcon
{
get => App.Settings.CreateDesktopIcon;
set => App.Settings.CreateDesktopIcon = value;
}
public bool CheckForUpdates
{
get => App.Settings.CheckForUpdates;
set => App.Settings.CheckForUpdates = value;
}
#endregion
public string ConfirmButtonText { get; } = App.IsFirstRun ? "Install" : "Save";
public PreferencesViewModel(Preferences window)
{
_window = window;
Task.Run(() => GetChannelInfo(App.Settings.Channel));
}
protected void OnPropertyChanged([CallerMemberName] string? name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
private async Task GetChannelInfo(string channel)
{
ChannelInfo = "Getting latest version info, please wait...\n";
ClientVersion info = await DeployManager.GetLastDeploy(channel, true);
string? strTimestamp = info.Timestamp?.ToString("MM/dd/yyyy h:mm:ss tt", App.CultureFormat);
ChannelInfo = $"Version: v{info.Version} ({info.VersionGuid})\nDeployed: {strTimestamp}";
}
}
}

View File

@ -1,46 +0,0 @@
<Window x:Class="Bloxstrap.Dialogs.Menu.ReShadeHelp"
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:local="clr-namespace:Bloxstrap.Dialogs.Menu"
mc:Ignorable="d"
Style="{DynamicResource MainWindowStyle}"
Title="ReShade Help"
SizeToContent="WidthAndHeight"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen">
<Grid Width="420" Height="220">
<StackPanel Margin="10">
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="ReShade Help" VerticalAlignment="Top" FontSize="18" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Toggle Menu" FontSize="16" />
<TextBlock HorizontalAlignment="Left" Margin="10,0,0,0" TextWrapping="Wrap" Text="Shift + Tab" />
</StackPanel>
<StackPanel Grid.Column="1">
<TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Toggle Shaders" FontSize="16" />
<TextBlock HorizontalAlignment="Left" Margin="10,0,0,0" TextWrapping="Wrap" Text="Shift + F6" />
</StackPanel>
<StackPanel Grid.Column="2">
<TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Take Screenshot" FontSize="16" />
<TextBlock HorizontalAlignment="Left" Margin="10,0,0,0" TextWrapping="Wrap" Text="Print Screen" />
</StackPanel>
</Grid>
<TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="If you're using a compact keyboard, you may have to hold down the Fn key when pressing F6." />
<TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Any screenshots you take are saved to the Screenshots folder in the ReShade folder." />
</StackPanel>
<Border Background="{DynamicResource ControlSelectedBackground}" BorderBrush="{DynamicResource ControlSelectedBorderBrush}" BorderThickness="1" Margin="-1,0,-1,0" Height="42" VerticalAlignment="Bottom">
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="ButtonClose" Content="Close" Width="66" Height="23" HorizontalAlignment="Right" Margin="0,0,10,0" Click="ButtonClose_Click" />
</StackPanel>
</Grid>
</Border>
</Grid>
</Window>

View File

@ -1,21 +0,0 @@
using System;
using System.Windows;
namespace Bloxstrap.Dialogs.Menu
{
/// <summary>
/// Interaction logic for ReShadeHelp.xaml
/// </summary>
public partial class ReShadeHelp : Window
{
public ReShadeHelp()
{
InitializeComponent();
}
private void ButtonClose_Click(object sender, EventArgs e)
{
this.Close();
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +0,0 @@
using System.Windows;
namespace REghZyFramework.Themes {
public partial class ColourfulDarkTheme {
private void CloseWindow_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
CloseWind(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
private void AutoMinimize_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
MaximizeRestore(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
private void Minimize_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
MinimizeWind(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
public void CloseWind(Window window) => window.Close();
public void MaximizeRestore(Window window) {
if (window.WindowState == WindowState.Maximized)
window.WindowState = WindowState.Normal;
else if (window.WindowState == WindowState.Normal)
window.WindowState = WindowState.Maximized;
}
public void MinimizeWind(Window window) => window.WindowState = WindowState.Minimized;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +0,0 @@
using System.Windows;
namespace REghZyFramework.Themes {
public partial class ColourfulLightTheme {
private void CloseWindow_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
CloseWind(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
private void AutoMinimize_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
MaximizeRestore(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
private void Minimize_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
MinimizeWind(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
public void CloseWind(Window window) => window.Close();
public void MaximizeRestore(Window window) {
if (window.WindowState == WindowState.Maximized)
window.WindowState = WindowState.Normal;
else if (window.WindowState == WindowState.Normal)
window.WindowState = WindowState.Maximized;
}
public void MinimizeWind(Window window) => window.WindowState = WindowState.Minimized;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +0,0 @@
using System.Windows;
namespace REghZyFramework.Themes {
public partial class DarkTheme {
private void CloseWindow_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
CloseWind(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
private void AutoMinimize_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
MaximizeRestore(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
private void Minimize_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
MinimizeWind(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
public void CloseWind(Window window) => window.Close();
public void MaximizeRestore(Window window) {
if (window.WindowState == WindowState.Maximized)
window.WindowState = WindowState.Normal;
else if (window.WindowState == WindowState.Normal)
window.WindowState = WindowState.Maximized;
}
public void MinimizeWind(Window window) => window.WindowState = WindowState.Minimized;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,43 +0,0 @@
using System.Windows;
namespace REghZyFramework.Themes {
public partial class LightTheme {
private void CloseWindow_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
CloseWind(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
private void AutoMinimize_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
MaximizeRestore(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
private void Minimize_Event(object sender, RoutedEventArgs e) {
if (e.Source != null)
try {
MinimizeWind(Window.GetWindow((FrameworkElement) e.Source));
}
catch {
}
}
public void CloseWind(Window window) => window.Close();
public void MaximizeRestore(Window window) {
if (window.WindowState == WindowState.Maximized)
window.WindowState = WindowState.Normal;
else if (window.WindowState == WindowState.Normal)
window.WindowState = WindowState.Maximized;
}
public void MinimizeWind(Window window) => window.WindowState = WindowState.Minimized;
}
}

View File

@ -1,6 +1,6 @@
using System.Windows.Forms; using System.Windows.Forms;
namespace Bloxstrap.Dialogs.BootstrapperDialogs namespace Bloxstrap.Dialogs
{ {
partial class ProgressDialog partial class ProgressDialog
{ {

View File

@ -4,7 +4,7 @@ using System.Windows.Forms;
using Bloxstrap.Enums; using Bloxstrap.Enums;
namespace Bloxstrap.Dialogs.BootstrapperDialogs namespace Bloxstrap.Dialogs
{ {
// basically just the modern dialog // basically just the modern dialog

View File

@ -1,4 +1,4 @@
namespace Bloxstrap.Dialogs.BootstrapperDialogs namespace Bloxstrap.Dialogs
{ {
partial class VistaDialog partial class VistaDialog
{ {

View File

@ -3,7 +3,7 @@ using System.Windows.Forms;
using Bloxstrap.Enums; using Bloxstrap.Enums;
namespace Bloxstrap.Dialogs.BootstrapperDialogs namespace Bloxstrap.Dialogs
{ {
// https://youtu.be/h0_AL95Sc3o?t=48 // https://youtu.be/h0_AL95Sc3o?t=48

View File

@ -1,6 +1,6 @@
using System.Windows.Forms; using System.Windows.Forms;
using Bloxstrap.Dialogs.BootstrapperDialogs; using Bloxstrap.Dialogs;
namespace Bloxstrap.Enums namespace Bloxstrap.Enums
{ {

View File

@ -3,7 +3,7 @@ using System.Diagnostics;
using System.IO; using System.IO;
using System.Windows; using System.Windows;
using Bloxstrap.Dialogs.Menu; using Bloxstrap.Views;
namespace Bloxstrap.Helpers namespace Bloxstrap.Helpers
{ {
@ -58,7 +58,8 @@ namespace Bloxstrap.Helpers
MessageBoxButton.OK MessageBoxButton.OK
); );
new Preferences().ShowDialog(); //new Preferences().ShowDialog();
new MainWindow().ShowDialog();
App.Terminate(); App.Terminate();
} }
} }

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Bloxstrap.Models
{
public class DeployInfo
{
public string Timestamp { get; set; } = null!;
public string Version { get; set; } = null!;
public string VersionGuid { get; set; } = null!;
}
}

View File

@ -0,0 +1,21 @@
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using Bloxstrap.Helpers;
namespace Bloxstrap.ViewModels
{
public class AboutViewModel
{
public ICommand OpenWebpageCommand => new RelayCommand<string>(OpenWebpage);
private void OpenWebpage(string? location)
{
if (location is null)
return;
Utilities.OpenWebsite(location);
}
public string Version => $"Version {App.Version}";
}
}

View File

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Bloxstrap.Enums;
using Bloxstrap.Views;
using CommunityToolkit.Mvvm.Input;
using Wpf.Ui.Mvvm.Services;
using Wpf.Ui.Mvvm.Contracts;
namespace Bloxstrap.ViewModels
{
public class BootstrapperViewModel
{
private readonly Page _page;
public ICommand PreviewBootstrapperCommand => new RelayCommand(PreviewBootstrapper);
private void PreviewBootstrapper() => App.Settings.BootstrapperStyle.Show();
public BootstrapperViewModel(Page page)
{
_page = page;
}
public bool UpdateCheckingEnabled
{
get => App.Settings.CheckForUpdates;
set => App.Settings.CheckForUpdates = value;
}
public bool ChannelChangePromptingEnabled
{
get => App.Settings.PromptChannelChange;
set => App.Settings.PromptChannelChange = value;
}
public IReadOnlyDictionary<string, Theme> Themes { get; set; } = new Dictionary<string, Theme>()
{
{ "System Default", Enums.Theme.Default },
{ "Light", Enums.Theme.Light },
{ "Dark", Enums.Theme.Dark },
};
public string Theme
{
get => Themes.FirstOrDefault(x => x.Value == App.Settings.Theme).Key;
set
{
App.Settings.Theme = Themes[value];
((MainWindow)Window.GetWindow(_page)!).SetTheme();
}
}
public IReadOnlyDictionary<string, BootstrapperStyle> Dialogs { get; set; } = new Dictionary<string, BootstrapperStyle>()
{
{ "Vista (2009 - 2011)", BootstrapperStyle.VistaDialog },
{ "Legacy (2009 - 2011)", BootstrapperStyle.LegacyDialog2009 },
{ "Legacy (2011 - 2014)", BootstrapperStyle.LegacyDialog2011 },
{ "Progress (~2014)", BootstrapperStyle.ProgressDialog },
};
public string Dialog
{
get => Dialogs.FirstOrDefault(x => x.Value == App.Settings.BootstrapperStyle).Key;
set => App.Settings.BootstrapperStyle = Dialogs[value];
}
public IReadOnlyDictionary<string, BootstrapperIcon> Icons { get; set; } = new Dictionary<string, BootstrapperIcon>()
{
{ "Bloxstrap", BootstrapperIcon.IconBloxstrap },
{ "2009", BootstrapperIcon.Icon2009 },
{ "2011", BootstrapperIcon.Icon2011 },
{ "2015", BootstrapperIcon.IconEarly2015 },
{ "2016", BootstrapperIcon.IconLate2015 },
{ "2017", BootstrapperIcon.Icon2017 },
{ "2019", BootstrapperIcon.Icon2019 },
{ "2022", BootstrapperIcon.Icon2022 }
};
public string Icon
{
get => Icons.FirstOrDefault(x => x.Value == App.Settings.BootstrapperIcon).Key;
set => App.Settings.BootstrapperIcon = Icons[value];
}
}
}

View File

@ -0,0 +1,108 @@
using Bloxstrap.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using CommunityToolkit.Mvvm.Input;
using System.Windows.Forms;
using Wpf.Ui.Mvvm.Interfaces;
using System.ComponentModel;
using Bloxstrap.Helpers;
using Bloxstrap.Models;
namespace Bloxstrap.ViewModels
{
public class InstallationViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private IEnumerable<string> _channels = DeployManager.ChannelsAbstracted.Contains(App.Settings.Channel) ? DeployManager.ChannelsAbstracted : DeployManager.ChannelsAll;
private bool _showAllChannels = !DeployManager.ChannelsAbstracted.Contains(App.Settings.Channel);
public ICommand BrowseInstallLocationCommand => new RelayCommand(BrowseInstallLocation);
public DeployInfo? ChannelDeployInfo { get; private set; } = null; //new DeployInfo(){ Version = "hi", VersionGuid = "hi", Timestamp = "January 25 2023 at 6:03:48 PM" };
public InstallationViewModel()
{
Task.Run(() => LoadChannelDeployInfo(App.Settings.Channel));
}
private async Task LoadChannelDeployInfo(string channel)
{
ChannelDeployInfo = null;
OnPropertyChanged(nameof(ChannelDeployInfo));
ClientVersion info = await DeployManager.GetLastDeploy(channel, true);
string? strTimestamp = info.Timestamp?.ToString("MM/dd/yyyy h:mm:ss tt", App.CultureFormat);
ChannelDeployInfo = new DeployInfo() { Version = info.Version, VersionGuid = info.VersionGuid, Timestamp = strTimestamp! };
OnPropertyChanged(nameof(ChannelDeployInfo));
}
private void BrowseInstallLocation()
{
using var dialog = new FolderBrowserDialog();
if (dialog.ShowDialog() == DialogResult.OK)
{
InstallLocation = dialog.SelectedPath;
OnPropertyChanged(nameof(InstallLocation));
}
}
public string InstallLocation
{
get => App.BaseDirectory;
set => App.BaseDirectory = value;
}
public bool CreateDesktopIcon
{
get => App.Settings.CreateDesktopIcon;
set => App.Settings.CreateDesktopIcon = value;
}
public IEnumerable<string> Channels
{
get => _channels;
set => _channels = value;
}
public string Channel
{
get => App.Settings.Channel;
set
{
//Task.Run(() => GetChannelInfo(value));
Task.Run(() => LoadChannelDeployInfo(value));
App.Settings.Channel = value;
}
}
public bool ShowAllChannels
{
get => _showAllChannels;
set
{
if (value)
{
Channels = DeployManager.ChannelsAll;
}
else
{
Channels = DeployManager.ChannelsAbstracted;
Channel = DeployManager.DefaultChannel;
OnPropertyChanged(nameof(Channel));
}
OnPropertyChanged(nameof(Channels));
_showAllChannels = value;
}
}
}
}

View File

@ -0,0 +1,95 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Wpf.Ui.Mvvm.Contracts;
using Bloxstrap.Views.Pages;
using Bloxstrap.Helpers;
using System.Diagnostics;
namespace Bloxstrap.ViewModels
{
public class IntegrationsViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private readonly Page _page;
public ICommand OpenReShadeFolderCommand => new RelayCommand(OpenReShadeFolder);
public ICommand ShowReShadeHelpCommand => new RelayCommand(ShowReShadeHelp);
public bool CanOpenReShadeFolder => !App.IsFirstRun;
public IntegrationsViewModel(Page page)
{
_page = page;
}
private void OpenReShadeFolder()
{
Process.Start("explorer.exe", Directories.ReShade);
}
private void ShowReShadeHelp()
{
((INavigationWindow)Window.GetWindow(_page)!).Navigate(typeof(ReShadeHelpPage));
}
public bool DiscordActivityEnabled
{
get => App.Settings.UseDiscordRichPresence;
set
{
App.Settings.UseDiscordRichPresence = value;
if (!value)
{
DiscordActivityJoinEnabled = value;
OnPropertyChanged(nameof(DiscordActivityJoinEnabled));
}
}
}
public bool DiscordActivityJoinEnabled
{
get => !App.Settings.HideRPCButtons;
set => App.Settings.HideRPCButtons = !value;
}
public bool ReShadeEnabled
{
get => App.Settings.UseReShade;
set
{
App.Settings.UseReShade = value;
ReShadePresetsEnabled = value;
OnPropertyChanged(nameof(ReShadePresetsEnabled));
}
}
public bool ReShadePresetsEnabled
{
get => App.Settings.UseReShadeExtraviPresets;
set => App.Settings.UseReShadeExtraviPresets = value;
}
public bool RbxFpsUnlockerEnabled
{
get => App.Settings.RFUEnabled;
set
{
App.Settings.RFUEnabled = value;
RbxFpsUnlockerAutocloseEnabled = value;
OnPropertyChanged(nameof(RbxFpsUnlockerAutocloseEnabled));
}
}
public bool RbxFpsUnlockerAutocloseEnabled
{
get => App.Settings.RFUAutoclose;
set => App.Settings.RFUAutoclose = value;
}
}
}

View File

@ -0,0 +1,96 @@
using System.IO;
using System;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Input;
using Bloxstrap.Views;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Win32;
namespace Bloxstrap.ViewModels
{
public class MainWindowViewModel
{
private readonly Window _window;
private readonly string _originalBaseDirectory = App.BaseDirectory; // we need this to check if the basedirectory changes
public ICommand CloseWindowCommand => new RelayCommand(CloseWindow);
public ICommand ConfirmSettingsCommand => new RelayCommand(ConfirmSettings);
public string ConfirmButtonText => App.IsFirstRun ? "Install" : "Save";
public MainWindowViewModel(Window window)
{
_window = window;
}
private void CloseWindow() => _window.Close();
private void ConfirmSettings()
{
if (String.IsNullOrEmpty(App.BaseDirectory))
{
App.ShowMessageBox("You must set an install location", MessageBoxImage.Error);
return;
}
try
{
// check if we can write to the directory (a bit hacky but eh)
string testPath = App.BaseDirectory;
string testFile = Path.Combine(testPath, $"{App.ProjectName}WriteTest.txt");
bool testPathExists = Directory.Exists(testPath);
if (!testPathExists)
Directory.CreateDirectory(testPath);
File.WriteAllText(testFile, "hi");
File.Delete(testFile);
if (!testPathExists)
Directory.Delete(testPath);
}
catch (UnauthorizedAccessException)
{
App.ShowMessageBox($"{App.ProjectName} does not have write access to the install location you selected. Please choose another install location.", MessageBoxImage.Error);
return;
}
catch (Exception ex)
{
App.ShowMessageBox(ex.Message, MessageBoxImage.Error);
return;
}
if (!App.IsFirstRun)
{
App.SettingsManager.ShouldSave = true;
if (App.BaseDirectory != _originalBaseDirectory)
{
App.ShowMessageBox($"{App.ProjectName} will install to the new location you've set the next time it runs.", MessageBoxImage.Information);
App.Settings.VersionGuid = "";
using (RegistryKey registryKey = Registry.CurrentUser.CreateSubKey($@"Software\{App.ProjectName}"))
{
registryKey.SetValue("InstallLocation", App.BaseDirectory);
registryKey.SetValue("OldInstallLocation", _originalBaseDirectory);
registryKey.Close();
}
// preserve settings
// we don't need to copy the bootstrapper over since the install process will do that automatically
App.SettingsManager.Save();
File.Copy(Path.Combine(App.BaseDirectory, "Settings.json"), Path.Combine(App.BaseDirectory, "Settings.json"));
}
}
App.IsSetupComplete = true;
CloseWindow();
}
}
}

View File

@ -0,0 +1,37 @@
using System.Diagnostics;
using System.Windows.Input;
using Bloxstrap.Helpers;
using CommunityToolkit.Mvvm.Input;
namespace Bloxstrap.ViewModels
{
public class ModsViewModel
{
public ICommand OpenModsFolderCommand => new RelayCommand(OpenModsFolder);
public bool CanOpenModsFolder => !App.IsFirstRun;
private void OpenModsFolder()
{
Process.Start("explorer.exe", Directories.Modifications);
}
public bool OldDeathSoundEnabled
{
get => App.Settings.UseOldDeathSound;
set => App.Settings.UseOldDeathSound = value;
}
public bool OldMouseCursorEnabled
{
get => App.Settings.UseOldMouseCursor;
set => App.Settings.UseOldMouseCursor = value;
}
public bool DisableAppPatchEnabled
{
get => App.Settings.UseDisableAppPatch;
set => App.Settings.UseDisableAppPatch = value;
}
}
}

View File

@ -0,0 +1,101 @@
<ui:UiWindow x:Class="Bloxstrap.Views.MainWindow"
x:Name="ConfigurationWindow"
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.Views.Pages"
xmlns:models="clr-namespace:Bloxstrap.ViewModels"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d"
Title="Bloxstrap Menu"
MinWidth="880"
Width="920"
Height="580"
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
ExtendsContentIntoTitleBar="True"
WindowBackdropType="Mica"
WindowCornerPreference="Round"
WindowStartupLocation="CenterScreen">
<!--AllowsTransparency="True"
WindowStyle="None"
WindowBackdropType="Acrylic"-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TitleBar x:Name="RootTitleBar" Grid.Row="0" ForceShutdown="False" MinimizeToTray="False" ShowHelp="False" UseSnapLayout="True" Title="Bloxstrap Menu" Icon="pack://application:,,,/Resources/IconBloxstrap-png.png" />
<Grid x:Name="RootGrid" Grid.Row="1" Margin="13,0,0,0" Visibility="Visible">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!--<Grid Grid.Row="0" Margin="6,0,0,24">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Width="40" Height="40">
<Border.Background>
<ImageBrush ImageSource="pack://application:,,,/Resources/IconBloxstrap-png.png" />
</Border.Background>
</Border>
<StackPanel Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center">
<TextBlock FontSize="18" FontWeight="Medium" Text="Bloxstrap" />
<TextBlock Text="Configuration Menu" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</Grid>-->
<ui:NavigationFluent x:Name="RootNavigation" Grid.Row="1" Grid.Column="0" Margin="0,0,12,0" Frame="{Binding ElementName=RootFrame}" SelectedPageIndex="0">
<ui:NavigationFluent.Items>
<ui:NavigationItem Content="Integrations" PageType="{x:Type pages:IntegrationsPage}" Icon="AddSquareMultiple20" Tag="integrations" />
<ui:NavigationItem Content="Mods" PageType="{x:Type pages:ModsPage}" Icon="DocumentToolbox24" Tag="mods" />
<ui:NavigationItem Content="Bootstrapper" PageType="{x:Type pages:BootstrapperPage}" Icon="Window48" Tag="bootstrapper" />
<ui:NavigationItem Content="Installation" PageType="{x:Type pages:InstallationPage}" Icon="HardDrive20" Tag="installation" />
<ui:NavigationSeparator />
<ui:NavigationItem Content="ReShade Help" PageType="{x:Type pages:ReShadeHelpPage}" Icon="BookQuestionMark24" Tag="reshadehelp" />
<ui:NavigationItem Content="About" PageType="{x:Type pages:AboutPage}" Icon="QuestionCircle48" Tag="about" />
</ui:NavigationFluent.Items>
</ui:NavigationFluent>
<Grid Grid.Row="0" Grid.RowSpan="2" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ui:Breadcrumb Grid.Row="0" Margin="0,0,0,14" Navigation="{Binding ElementName=RootNavigation}" />
<Frame x:Name="RootFrame" Grid.Row="1" />
</Grid>
</Grid>
<StatusBar x:Name="RootStatusBar" Grid.Row="2" Padding="14,9,14,9" Background="{ui:ThemeResource ApplicationBackgroundBrush}" BorderThickness="0,1,0,0">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="1" Padding="0,0,4,0">
<ui:Button Content="{Binding ConfirmButtonText, Mode=OneTime}" Appearance="Primary" Command="{Binding ConfirmSettingsCommand, Mode=OneWay}" />
</StatusBarItem>
<StatusBarItem Grid.Column="2" Padding="4,0,0,0">
<ui:Button Content="Cancel" Command="{Binding CloseWindowCommand, Mode=OneWay}" />
</StatusBarItem>
</StatusBar>
</Grid>
</ui:UiWindow>

View File

@ -0,0 +1,53 @@
using System.Windows.Controls;
using System;
using Wpf.Ui.Controls.Interfaces;
using Wpf.Ui.Mvvm.Contracts;
using Bloxstrap.Enums;
using Bloxstrap.ViewModels;
using Wpf.Ui.Mvvm.Services;
using Wpf.Ui.Appearance;
namespace Bloxstrap.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : INavigationWindow
{
private readonly IThemeService _themeService = new ThemeService();
public MainWindow()
{
DataContext = new MainWindowViewModel(this);
SetTheme();
InitializeComponent();
}
public void SetTheme()
{
var theme = ThemeType.Light;
if (App.Settings.Theme.GetFinal() == Enums.Theme.Dark)
theme = ThemeType.Dark;
_themeService.SetTheme(theme);
_themeService.SetSystemAccent();
}
#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
}
}

View File

@ -0,0 +1,139 @@
<ui:UiPage x:Class="Bloxstrap.Views.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:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="AboutPage"
Scrollable="True">
<StackPanel Margin="0,0,14,14">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Width="60" Height="60" VerticalAlignment="Center">
<Border.Background>
<ImageBrush ImageSource="pack://application:,,,/Resources/IconBloxstrap-png.png" />
</Border.Background>
</Border>
<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="An open-source, feature-packed alternative bootstrapper for Roblox" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
<TextBlock Text="Developed by pizzaboxer - if you like this, please consider leaving a star on GitHub!" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</Grid>
<StackPanel Orientation="Horizontal">
<ui:Anchor Margin="0,16,4,0" Content="GitHub Repository" Icon="Code24" NavigateUri="https://github.com/pizzaboxer/bloxstrap" />
<ui:Anchor Margin="4,16,4,0" Content="Report an issue" Icon="Chat48" NavigateUri="https://github.com/pizzaboxer/bloxstrap/issues" />
<ui:Anchor Margin="4,16,0,0" Content="Latest Releases" Icon="ArrowDownload48" NavigateUri="https://github.com/pizzaboxer/bloxstrap/releases" />
</StackPanel>
<TextBlock Text="Contributions" FontWeight="Medium" FontSize="20" Margin="0,16,0,0" />
<TextBlock Text="These are the people who have made notable contributions to Bloxstrap, helping make it what it is." TextWrapping="Wrap" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
<Grid Column="0" Margin="0,16,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,0,16,8" FontSize="14" FontWeight="Medium"><Hyperlink Foreground="{DynamicResource TextFillColorPrimaryBrush}" Command="{Binding OpenWebpageCommand}" CommandParameter="https://www.roblox.com/users/2485612194/profile">Multako</Hyperlink></TextBlock>
<TextBlock Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" VerticalAlignment="Bottom" Text="Designing the Bloxstrap logo" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,16,8" FontSize="14" FontWeight="Medium"><Hyperlink Foreground="{DynamicResource TextFillColorPrimaryBrush}" Command="{Binding OpenWebpageCommand}" CommandParameter="https://github.com/bluepilledgreat">bluepilledgreat</Hyperlink></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="0,0,0,8" VerticalAlignment="Bottom" Text="Helping with bootstrapper functionality and UX" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,16,8" FontSize="14" FontWeight="Medium"><Hyperlink Foreground="{DynamicResource TextFillColorPrimaryBrush}" Command="{Binding OpenWebpageCommand}" CommandParameter="https://github.com/1011025m">1011025m</Hyperlink></TextBlock>
<TextBlock Grid.Row="2" Grid.Column="1" Margin="0,0,0,8" VerticalAlignment="Bottom" Text="Providing a method for disabling the Roblox desktop app" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
<TextBlock Grid.Row="3" Grid.Column="0" Margin="0,0,16,0" FontSize="14" FontWeight="Medium"><Hyperlink Foreground="{DynamicResource TextFillColorPrimaryBrush}" Command="{Binding OpenWebpageCommand}" CommandParameter="https://github.com/sitiom">sitiom</Hyperlink></TextBlock>
<TextBlock Grid.Row="3" Grid.Column="1" Margin="0,0,0,0" VerticalAlignment="Bottom" Text="Setting up GitHub CI workflows and Winget releases" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</Grid>
<ui:Anchor Margin="0,16,0,0" Content="See all code contributors" Icon="People48" NavigateUri="https://github.com/pizzaboxer/bloxstrap/graphs/contributors" />
<TextBlock Text="Licenses" FontWeight="Medium" FontSize="18" Margin="0,16,0,0" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Bloxstrap" FontSize="14" TextWrapping="Wrap" Margin="0,8,0,0" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
<ui:CardAction Grid.Row="1" Grid.Column="0" Margin="0,8,8,0" Command="{Binding OpenWebpageCommand}" CommandParameter="https://github.com/pizzaboxer/bloxstrap/blob/main/LICENSE">
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="Bloxstrap by pizzaboxer" />
<TextBlock FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardAction>
<ui:CardAction Grid.Row="1" Grid.Column="1" Margin="0,8,8,0" Command="{Binding OpenWebpageCommand}" CommandParameter="https://github.com/lepoco/wpfui/blob/main/LICENSE">
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="WPF-UI by lepoco" />
<TextBlock FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardAction>
<ui:CardAction Grid.Row="1" Grid.Column="2" Margin="0,8,0,0" Command="{Binding OpenWebpageCommand}" CommandParameter="https://github.com/securifybv/ShellLink/blob/master/LICENSE.txt">
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="ShellLink by securifybv" />
<TextBlock FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardAction>
<ui:CardAction Grid.Row="2" Grid.Column="0" Margin="0,8,8,0" Command="{Binding OpenWebpageCommand}" CommandParameter="https://github.com/rickyah/ini-parser/blob/development/LICENSE">
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="ini-parser by rickyah" />
<TextBlock FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardAction>
<ui:CardAction Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Margin="0,8,0,0" Command="{Binding OpenWebpageCommand}" CommandParameter="https://github.com/MaximumADHD/Roblox-Studio-Mod-Manager/blob/main/LICENSE">
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="Roblox Studio Mod Manager by MaximumADHD" />
<TextBlock FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardAction>
<TextBlock Grid.Row="3" Grid.Column="0" Text="Integrations" FontSize="14" TextWrapping="Wrap" Margin="0,8,0,0" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
<ui:CardAction Grid.Row="4" Grid.Column="0" Margin="0,8,8,0" Command="{Binding OpenWebpageCommand}" CommandParameter="https://github.com/Lachee/discord-rpc-csharp/blob/master/LICENSE">
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="DiscordRPC by Lachee" />
<TextBlock FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardAction>
<ui:CardAction Grid.Row="4" Grid.Column="1" Margin="0,8,8,0" Command="{Binding OpenWebpageCommand}" CommandParameter="https://github.com/crosire/reshade/blob/main/LICENSE.md">
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="ReShade by crosire" />
<TextBlock FontSize="12" Text="BSD 3-Clause License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardAction>
<ui:CardAction Grid.Row="4" Grid.Column="2" Margin="0,8,0,0" Command="{Binding OpenWebpageCommand}" CommandParameter="https://github.com/axstin/rbxfpsunlocker/blob/master/LICENSE">
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="rbxfpsunlocker by axstin" />
<TextBlock FontSize="12" Text="MIT License" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardAction>
</Grid>
</StackPanel>
</ui:UiPage>

View File

@ -0,0 +1,16 @@
using Bloxstrap.ViewModels;
namespace Bloxstrap.Views.Pages
{
/// <summary>
/// Interaction logic for AboutPage.xaml
/// </summary>
public partial class AboutPage
{
public AboutPage()
{
DataContext = new AboutViewModel();
InitializeComponent();
}
}
}

View File

@ -0,0 +1,67 @@
<ui:UiPage x:Class="Bloxstrap.Views.Pages.BootstrapperPage"
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.ViewModels"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="BootstrapperPage"
Scrollable="True">
<StackPanel Margin="0,0,14,14">
<TextBlock Text="Configure how Bloxstrap should function and look." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock Text="Behaviour" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Update Bloxstrap on startup" />
<TextBlock FontSize="12" Text="Bloxstrap will check and automatically update itself when launching Roblox." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding UpdateCheckingEnabled, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Prompt on Roblox-forced channel change" />
<TextBlock FontSize="12" Text="Confirm if Roblox mandates a channel change on launch. Otherwise, it'll change automatically." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding ChannelChangePromptingEnabled, Mode=TwoWay}" />
</ui:CardControl>
<!--should this all be in a collapsed panel like how channel settings are? that might be better, idk-->
<TextBlock Text="Appearance" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Theme" />
<TextBlock FontSize="12" Text="Dark theme does not apply to Legacy or Vista styles." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ComboBox Width="200" Padding="10,5,10,5" ItemsSource="{Binding Themes.Keys, Mode=OneTime}" Text="{Binding Theme, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Style" />
<TextBlock FontSize="12" Text="Choose how the bootstrapper should look." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ComboBox Width="200" Padding="10,5,10,5" ItemsSource="{Binding Dialogs.Keys, Mode=OneTime}" Text="{Binding Dialog, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Icon" />
<TextBlock FontSize="12" Text="Choose what icon the bootstrapper should use." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ComboBox Width="200" Padding="10,5,10,5" ItemsSource="{Binding Icons.Keys, Mode=OneTime}" Text="{Binding Icon, Mode=TwoWay}" />
</ui:CardControl>
<ui:Button Content="Preview" HorizontalAlignment="Stretch" Margin="0,8,0,0" Command="{Binding PreviewBootstrapperCommand}" />
</StackPanel>
</ui:UiPage>

View File

@ -0,0 +1,16 @@
using Bloxstrap.ViewModels;
namespace Bloxstrap.Views.Pages
{
/// <summary>
/// Interaction logic for BootstrapperPage.xaml
/// </summary>
public partial class BootstrapperPage
{
public BootstrapperPage()
{
DataContext = new BootstrapperViewModel(this);
InitializeComponent();
}
}
}

View File

@ -0,0 +1,116 @@
<ui:UiPage x:Class="Bloxstrap.Views.Pages.InstallationPage"
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:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="InstallationPage"
Scrollable="True">
<StackPanel Margin="0,0,14,14">
<TextBlock Text="Configure how Bloxstrap and Roblox are installed." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<ui:CardExpander Margin="0,16,0,0">
<ui:CardExpander.Header>
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="Install Location" />
<TextBlock FontSize="12" Text="Choose where Bloxstrap should be installed to." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardExpander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Margin="0,0,4,0" Text="{Binding InstallLocation, Mode=TwoWay}" />
<ui:Button Grid.Column="1" Margin="4,0,0,0" Height="35" Icon="Folder24" Content="Browse" Command="{Binding BrowseInstallLocationCommand}" />
</Grid>
</ui:CardExpander>
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Create desktop icon" />
<TextBlock FontSize="12" Text="Bloxstrap will place an icon on the desktop that launches Roblox." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding CreateDesktopIcon, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardExpander Margin="0,8,0,0">
<ui:CardExpander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Channel" />
<TextBlock FontSize="12" Text="Choose which release channel to download Roblox from." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
<ComboBox Grid.Column="1" Margin="8,0,8,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding Channels, Mode=OneWay}" Text="{Binding Channel, Mode=TwoWay}" />
</Grid>
</ui:CardExpander.Header>
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid Column="0" Margin="0,0,4,0">
<Grid.Style>
<Style>
<Setter Property="Grid.Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ChannelDeployInfo}" Value="{x:Null}">
<Setter Property="Grid.Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Grid.RowDefinitions>
<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,0,16,8" VerticalAlignment="Center" Text="Version" />
<TextBlock Grid.Row="0" Grid.Column="1" Foreground="{DynamicResource TextFillColorTertiaryBrush}" Text="{Binding ChannelDeployInfo.Version, Mode=OneWay}" />
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,16,8" VerticalAlignment="Center" Text="VersionGuid" />
<TextBlock Grid.Row="1" Grid.Column="1" Foreground="{DynamicResource TextFillColorTertiaryBrush}" Text="{Binding ChannelDeployInfo.VersionGuid, Mode=OneWay}" />
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,16,0" VerticalAlignment="Center" Text="Deployed" />
<TextBlock Grid.Row="2" Grid.Column="1" Foreground="{DynamicResource TextFillColorTertiaryBrush}" Text="{Binding ChannelDeployInfo.Timestamp, Mode=OneWay}" />
</Grid>
<Grid Column="0">
<Grid.Style>
<Style>
<Setter Property="Grid.Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ChannelDeployInfo}" Value="{x:Null}">
<Setter Property="Grid.Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Style>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:ProgressRing Grid.Column="0" Margin="6" IsIndeterminate="True" />
<TextBlock Grid.Column="1" Margin="16" VerticalAlignment="Center" Text="Fetching latest deploy info, please wait..." />
</Grid>
<CheckBox Grid.Column="1" Margin="4,0,0,0" Content="Show all available channels" VerticalAlignment="Top" IsChecked="{Binding ShowAllChannels, Mode=TwoWay}" />
</Grid>
</StackPanel>
</ui:CardExpander>
</StackPanel>
</ui:UiPage>

View File

@ -0,0 +1,16 @@
using Bloxstrap.ViewModels;
namespace Bloxstrap.Views.Pages
{
/// <summary>
/// Interaction logic for InstallationPage.xaml
/// </summary>
public partial class InstallationPage
{
public InstallationPage()
{
DataContext = new InstallationViewModel();
InitializeComponent();
}
}
}

View File

@ -0,0 +1,118 @@
<ui:UiPage x:Class="Bloxstrap.Views.Pages.IntegrationsPage"
x:Name="IntegrationsPageView"
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.ViewModels"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d"
d:DesignHeight="680" d:DesignWidth="800"
Title="IntegrationsPage"
Scrollable="True">
<StackPanel Margin="0,0,14,14">
<TextBlock Text="Configure quick and easy ways to improve the Roblox gameplay experience." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock Text="Discord Rich Presence" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Show game activity" />
<TextBlock FontSize="12" Text="The game you're playing on Roblox will show on your Discord activity." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch x:Name="DiscordActivityEnabledToggle" IsChecked="{Binding DiscordActivityEnabled, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0" IsEnabled="{Binding IsChecked, ElementName=DiscordActivityEnabledToggle, Mode=OneWay}">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Allow activity joining" />
<TextBlock FontSize="12" Text="When enabled, anyone can join your game through your Discord activity." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding DiscordActivityJoinEnabled, Mode=TwoWay}" />
</ui:CardControl>
<TextBlock Text="ReShade" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Use ReShade" />
<TextBlock FontSize="12" Text="Reshade is a post-processing injector that enables the use of shaders." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch x:Name="ReShadeEnabledToggle" IsChecked="{Binding ReShadeEnabled, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0" IsEnabled="{Binding IsChecked, ElementName=ReShadeEnabledToggle, Mode=OneWay}">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Use Extravi's shader presets" />
<TextBlock FontSize="12" Text="ReShade presets made specifically for Roblox that enhance your graphics." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding ReShadePresetsEnabled, Mode=TwoWay}" />
</ui:CardControl>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:CardAction Grid.Column="0" Margin="0,8,4,0" Icon="Folder24" Command="{Binding OpenReShadeFolderCommand}" IsEnabled="{Binding CanOpenReShadeFolder}">
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="Open ReShade Folder">
<!--this is so fucking stupid the disabled state of the cardaction doesnt change the header text colour-->
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding CanOpenReShadeFolder}" Value="False">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TextFillColorDisabledBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock FontSize="12" Foreground="{DynamicResource TextFillColorTertiaryBrush}">
<TextBlock.Style>
<Style>
<Setter Property="TextBlock.Text" Value="Shaders and screenshots are stored here."/>
<Style.Triggers>
<DataTrigger Binding="{Binding CanOpenReShadeFolder}" Value="False">
<Setter Property="TextBlock.Text" Value="Bloxstrap must first be installed." />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</ui:CardAction>
<ui:CardAction Grid.Column="1" Margin="4,8,0,0" Icon="BookQuestionMark24" Command="{Binding ShowReShadeHelpCommand}">
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="Help" />
<TextBlock FontSize="12" Text="See help information on using ReShade." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardAction>
</Grid>
<StackPanel x:Name="RbxFpsUnlockerOptions">
<TextBlock Text="FPS Unlocking" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<ui:CardControl Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Use axstin's rbxfpsunlocker" />
<TextBlock FontSize="12" Text="rbxfpsunlocker removes Roblox's 60FPS cap and will launch alongside Roblox." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch x:Name="RbxFpsUnlockerEnabledToggle" IsChecked="{Binding RbxFpsUnlockerEnabled, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Margin="0,8,0,0" IsEnabled="{Binding IsChecked, ElementName=RbxFpsUnlockerEnabledToggle, Mode=OneWay}">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Stop when Roblox closes" />
<TextBlock FontSize="12" Text="rbxfpsunlocker will automatically close when Roblox closes." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding RbxFpsUnlockerAutocloseEnabled, Mode=TwoWay}" />
</ui:CardControl>
</StackPanel>
</StackPanel>
</ui:UiPage>

View File

@ -0,0 +1,22 @@
using System;
using System.Windows;
using Bloxstrap.ViewModels;
namespace Bloxstrap.Views.Pages
{
/// <summary>
/// Interaction logic for IntegrationsPage.xaml
/// </summary>
public partial class IntegrationsPage
{
public IntegrationsPage()
{
DataContext = new IntegrationsViewModel(this);
InitializeComponent();
// rbxfpsunlocker does not have 64 bit support
if (!Environment.Is64BitOperatingSystem)
this.RbxFpsUnlockerOptions.Visibility = Visibility.Collapsed;
}
}
}

View File

@ -0,0 +1,91 @@
<ui:UiPage x:Class="Bloxstrap.Views.Pages.ModsPage"
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.ViewModels"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="ModsPage"
Scrollable="True">
<StackPanel Margin="0,0,14,14">
<TextBlock Text="Manage and apply file mods to the Roblox game client." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<ui:CardAction Grid.Column="0" Margin="0,16,0,0" Icon="Folder24" Command="{Binding OpenModsFolderCommand}" IsEnabled="{Binding CanOpenModsFolder, Mode=OneTime}">
<StackPanel>
<TextBlock FontSize="13" FontWeight="Medium" Text="Open Mods Folder">
<!--this is so fucking stupid the disabled state of the cardaction doesnt change the header text colour-->
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding CanOpenModsFolder, Mode=OneTime}" Value="False">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TextFillColorDisabledBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock FontSize="12" Foreground="{DynamicResource TextFillColorTertiaryBrush}">
<TextBlock.Style>
<Style>
<Setter Property="TextBlock.Text" Value="This folder contains all the file mods applied to Roblox. See below for more info."/>
<Style.Triggers>
<DataTrigger Binding="{Binding CanOpenModsFolder, Mode=OneTime}" Value="False">
<Setter Property="TextBlock.Text" Value="Bloxstrap must first be installed before accessing this folder. See below for what it does." />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</ui:CardAction>
<TextBlock Text="Presets" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ui:CardControl Grid.Row="0" Grid.Column="0" Margin="0,8,4,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Use old death sound" />
<TextBlock FontSize="12" Text="Bring back the classic 'oof' death sound." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding OldDeathSoundEnabled, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Grid.Row="0" Grid.Column="1" Margin="4,8,0,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Use old mouse cursor" />
<TextBlock FontSize="12" Text="Use the pre-2022 style mouse cursor." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding OldMouseCursorEnabled, Mode=TwoWay}" />
</ui:CardControl>
<ui:CardControl Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,8,0,0">
<ui:CardControl.Header>
<StackPanel Grid.Column="0">
<TextBlock FontSize="13" FontWeight="Medium" Text="Disable desktop app" />
<TextBlock FontSize="12" Text="Stops the desktop app from showing when launching Roblox or leaving a game." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</StackPanel>
</ui:CardControl.Header>
<ui:ToggleSwitch IsChecked="{Binding DisableAppPatchEnabled, Mode=TwoWay}" />
</ui:CardControl>
</Grid>
<TextBlock Text="Adding your own mods" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<TextBlock HorizontalAlignment="Left" Margin="0,8,0,0" TextWrapping="Wrap" Text="The Mods folder is where you can apply modifications to Roblox files while ensuring that they're preserved whenever Roblox updates." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock HorizontalAlignment="Left" Margin="0,8,0,0" TextWrapping="Wrap" Text="For example, placing a file at Modifications\content\sounds\ouch.ogg will automatically copy to and overwrite the file at Versions\Version-id\content\sounds\ouch.ogg. In this case, it replaces the death sound, which the old death sound preset does." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock HorizontalAlignment="Left" Margin="0,8,0,0" TextWrapping="Wrap" Text="When you remove a file, Bloxstrap restores the original version of the file the next time Roblox launches." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock HorizontalAlignment="Left" Margin="0,8,0,0" TextWrapping="Wrap" Text="The folder is also used for handling mod presets and files for integrations like ReShade, so if you find any files or folders that already exist, you can safely ignore them." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
</StackPanel>
</ui:UiPage>

View File

@ -0,0 +1,16 @@
using Bloxstrap.ViewModels;
namespace Bloxstrap.Views.Pages
{
/// <summary>
/// Interaction logic for ModsPage.xaml
/// </summary>
public partial class ModsPage
{
public ModsPage()
{
DataContext = new ModsViewModel();
InitializeComponent();
}
}
}

View File

@ -0,0 +1,44 @@
<ui:UiPage x:Class="Bloxstrap.Views.Pages.ReShadeHelpPage"
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:local="clr-namespace:Bloxstrap.Views.Pages"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="ReShadeHelpPage"
Scrollable="True">
<StackPanel Margin="0,0,14,14">
<TextBlock Text="Keyboard Controls" FontSize="16" FontWeight="Medium" />
<Grid Column="0" Margin="0,8,0,0">
<Grid.RowDefinitions>
<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,0,16,8" FontSize="14" FontWeight="Medium" Text="Toggle Menu" />
<TextBlock Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" VerticalAlignment="Bottom" Text="Shift + Tab" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,16,8" FontSize="14" FontWeight="Medium" Text="Toggle Shaders" />
<TextBlock Grid.Row="1" Grid.Column="1" Margin="0,0,0,8" VerticalAlignment="Bottom" Text="Shift + F6" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,16,8" FontSize="14" FontWeight="Medium" Text="Take Screenshot" />
<TextBlock Grid.Row="2" Grid.Column="1" Margin="0,0,0,8" VerticalAlignment="Bottom" Text="Print Screen" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
</Grid>
<TextBlock HorizontalAlignment="Left" Margin="0,8,0,0" TextWrapping="Wrap" Text="If you're using a laptop keyboard, you may have to hold down the Fn key when pressing F6." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock HorizontalAlignment="Left" Margin="0,8,0,0" TextWrapping="Wrap" Text="Any screenshots you take are saved to the Screenshots folder in the ReShade folder." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock Text="Adding your own shaders and presets" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
<TextBlock HorizontalAlignment="Left" Margin="0,8,0,0" TextWrapping="Wrap" Text="While Bloxstrap provides Extravi's ReShade presets as a great way to enhance Roblox's graphics, it also provides the ability to install custom shaders and presets." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock HorizontalAlignment="Left" Margin="0,8,0,0" TextWrapping="Wrap" Text="To install custom presets, just extract the necessary .ini files to the ReShade Presets folder. Though, you may also need to add additional shaders and textures." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
<TextBlock HorizontalAlignment="Left" Margin="0,8,0,0" TextWrapping="Wrap" Text="To install shaders (known as effects), extract the necessary files to the ReShade Shaders folder. The same goes for textures, where you extract them to the ReShade Textures folder. You could alternatively extract them to organized subfolders like how Bloxstrap does them, though you'll have to configure ReShade to look in those folders." Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
</StackPanel>
</ui:UiPage>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
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.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Bloxstrap.Views.Pages
{
/// <summary>
/// Interaction logic for ReShadeHelpPage.xaml
/// </summary>
public partial class ReShadeHelpPage
{
public ReShadeHelpPage()
{
InitializeComponent();
}
}
}

79
Bloxstrap/app.manifest Normal file
View File

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<!-- UAC Manifest Options
If you want to change the Windows User Account Control level replace the
requestedExecutionLevel node with one of the following.
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
Specifying requestedExecutionLevel element will disable file and registry virtualization.
Remove this element if your application requires this virtualization for backwards
compatibility.
-->
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows Vista -->
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
<!-- Windows 7 -->
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
<!-- Windows 8 -->
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
<!-- Windows 8.1 -->
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
<!-- Windows 10 -->
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
</application>
</compatibility>
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config.
Makes the application long-path aware. See https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
<!--
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
</windowsSettings>
</application>
-->
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>