Draft design and functionality for Fluent Dialog

This commit is contained in:
pizzaboxer 2023-02-12 23:19:00 +00:00
parent d07f99afcc
commit 48d09f6730
13 changed files with 258 additions and 32 deletions

View File

@ -2,7 +2,8 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Bloxstrap"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml">
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>

View File

@ -55,9 +55,9 @@ namespace Bloxstrap
public static void Terminate(int code = Bootstrapper.ERROR_SUCCESS)
{
Debug.WriteLine($"[App] Terminating with exit code {code}");
Settings.Save();
State.Save();
Debug.WriteLine($"[App] Terminating with exit code {code}");
Environment.Exit(code);
}
@ -109,14 +109,12 @@ namespace Bloxstrap
registryKey.Close();
}
// preferences dialog was closed, and so base directory was never set
// exit if we don't click the install button on installation
if (!IsSetupComplete)
Environment.Exit(Bootstrapper.ERROR_INSTALL_USEREXIT);
Directories.Initialize(BaseDirectory);
//Settings.FileLocation = Path.Combine(Directories.Base, "Settings.json");
// we shouldn't save settings on the first run until the first installation is finished,
// just in case the user decides to cancel the install
if (!IsFirstRun)
@ -185,6 +183,7 @@ namespace Bloxstrap
Task bootstrapperTask = Task.Run(() => bootstrapper.Run()).ContinueWith(t =>
{
// TODO: add error logging
Debug.WriteLine("[App] Bootstrapper task has finished");
if (t.Exception is null)
return;

View File

@ -13,7 +13,14 @@
</PropertyGroup>
<ItemGroup>
<None Remove="Resources\Icon2009-png.png" />
<None Remove="Resources\Icon2011-png.png" />
<None Remove="Resources\Icon2017-png.png" />
<None Remove="Resources\Icon2019-png.png" />
<None Remove="Resources\Icon2022-png.png" />
<None Remove="Resources\IconBloxstrap-png.png" />
<None Remove="Resources\IconEarly2015-png.png" />
<None Remove="Resources\IconLate2015-png.png" />
</ItemGroup>
<ItemGroup>
@ -35,7 +42,14 @@
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\Icon2009-png.png" />
<Resource Include="Resources\Icon2011-png.png" />
<Resource Include="Resources\Icon2017-png.png" />
<Resource Include="Resources\Icon2019-png.png" />
<Resource Include="Resources\Icon2022-png.png" />
<Resource Include="Resources\IconBloxstrap-png.png" />
<Resource Include="Resources\IconEarly2015-png.png" />
<Resource Include="Resources\IconLate2015-png.png" />
</ItemGroup>
</Project>

View File

@ -10,8 +10,9 @@ namespace Bloxstrap.Dialogs
{
public class BootstrapperDialogForm : Form, IBootstrapperDialog
{
public Bootstrapper Bootstrapper { get; set; } = null!;
public Bootstrapper? Bootstrapper { get; set; }
#region UI Elements
protected virtual string _message { get; set; } = "Please wait...";
protected virtual ProgressBarStyle _progressStyle { get; set; }
protected virtual int _progressValue { get; set; }
@ -64,6 +65,7 @@ namespace Bloxstrap.Dialogs
_cancelEnabled = value;
}
}
#endregion
public void ScaleWindow()
{
@ -83,6 +85,13 @@ namespace Bloxstrap.Dialogs
this.Icon = App.Settings.Prop.BootstrapperIcon.GetIcon();
}
public void ButtonCancel_Click(object? sender, EventArgs e)
{
Bootstrapper?.CancelInstall();
this.Close();
}
#region IBootstrapperDialog Methods
public void ShowBootstrapper() => this.ShowDialog();
public virtual void CloseBootstrapper()
@ -116,11 +125,6 @@ namespace Bloxstrap.Dialogs
if (result != MessageBoxResult.OK)
Environment.Exit(Bootstrapper.ERROR_INSTALL_USEREXIT);
}
public void ButtonCancel_Click(object? sender, EventArgs e)
{
Bootstrapper.CancelInstall();
this.Close();
}
#endregion
}
}

View File

@ -0,0 +1,40 @@
<ui:UiWindow x:Class="Bloxstrap.Dialogs.FluentDialog"
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"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
mc:Ignorable="d"
Width="420"
Height="178"
MinHeight="178"
MaxHeight="178"
ResizeMode="NoResize"
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
ExtendsContentIntoTitleBar="True"
WindowBackdropType="Mica"
WindowCornerPreference="Round"
WindowStartupLocation="CenterScreen">
<StackPanel>
<TextBlock Margin="16,16,8,0" Text="Bloxstrap" Foreground="{DynamicResource TextFillColorPrimaryBrush}" />
<Grid Margin="16,0,16,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Margin="0,12,0,0" Width="48" Height="48" VerticalAlignment="Top">
<Border.Background>
<ImageBrush ImageSource="{Binding Icon, Mode=OneWay}" />
</Border.Background>
</Border>
<StackPanel Grid.Column="1">
<TextBlock Margin="16,8,0,0" FontSize="20" Text="{Binding Message, Mode=OneWay}" Foreground="{DynamicResource TextFillColorPrimaryBrush}" />
<ProgressBar Margin="16,16,0,16" IsIndeterminate="{Binding ProgressIndeterminate, Mode=OneWay}" Value="{Binding ProgressValue, Mode=OneWay}" />
</StackPanel>
</Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Margin="8,16,16,16" Content="{Binding CancelButtonText, Mode=OneWay}" Width="120" HorizontalAlignment="Right" Visibility="{Binding CancelButtonVisibility, Mode=OneWay}" Command="{Binding CancelInstallCommand}" />
</StackPanel>
</StackPanel>
</ui:UiWindow>

View File

@ -0,0 +1,122 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Bloxstrap.Enums;
using Bloxstrap.ViewModels;
using Wpf.Ui.Appearance;
using Wpf.Ui.Mvvm.Contracts;
using Wpf.Ui.Mvvm.Services;
namespace Bloxstrap.Dialogs
{
/// <summary>
/// Interaction logic for FluentDialog.xaml
/// </summary>
public partial class FluentDialog : IBootstrapperDialog
{
private readonly IThemeService _themeService = new ThemeService();
private readonly FluentDialogViewModel _viewModel;
public Bootstrapper? Bootstrapper { get; set; }
#region UI Elements
public string Message
{
get => _viewModel.Message;
set
{
_viewModel.Message = value;
_viewModel.OnPropertyChanged(nameof(_viewModel.Message));
}
}
public ProgressBarStyle ProgressStyle
{
get => _viewModel.ProgressIndeterminate ? ProgressBarStyle.Marquee : ProgressBarStyle.Continuous;
set
{
_viewModel.ProgressIndeterminate = (value == ProgressBarStyle.Marquee);
_viewModel.OnPropertyChanged(nameof(_viewModel.ProgressIndeterminate));
}
}
public int ProgressValue
{
get => _viewModel.ProgressValue;
set
{
_viewModel.ProgressValue = value;
_viewModel.OnPropertyChanged(nameof(_viewModel.ProgressValue));
}
}
public bool CancelEnabled
{
get => _viewModel.CancelButtonVisibility == Visibility.Visible;
set
{
_viewModel.CancelButtonVisibility = (value ? Visibility.Visible : Visibility.Collapsed);
_viewModel.OnPropertyChanged(nameof(_viewModel.CancelButtonVisibility));
}
}
#endregion
public FluentDialog()
{
_viewModel = new FluentDialogViewModel(this);
DataContext = _viewModel;
Title = App.ProjectName;
_themeService.SetTheme(App.Settings.Prop.Theme.GetFinal() == Enums.Theme.Dark ? ThemeType.Dark : ThemeType.Light);
_themeService.SetSystemAccent();
InitializeComponent();
}
#region IBootstrapperDialog Methods
public void ShowBootstrapper() => this.ShowDialog();
public void CloseBootstrapper() => Dispatcher.BeginInvoke(this.Close);
// TODO: make prompts use dialog view natively rather than using message dialog boxes
public void ShowSuccess(string message)
{
App.ShowMessageBox(message, MessageBoxImage.Information);
App.Terminate();
}
public void ShowError(string message)
{
App.ShowMessageBox($"An error occurred while starting Roblox\n\nDetails: {message}", MessageBoxImage.Error);
App.Terminate(Bootstrapper.ERROR_INSTALL_FAILURE);
}
public void PromptShutdown()
{
MessageBoxResult result = App.ShowMessageBox(
"Roblox is currently running, but needs to close. Would you like close Roblox now?",
MessageBoxImage.Information,
MessageBoxButton.OKCancel
);
if (result != MessageBoxResult.OK)
Environment.Exit(Bootstrapper.ERROR_INSTALL_USEREXIT);
}
#endregion
}
}

View File

@ -4,7 +4,7 @@ namespace Bloxstrap.Dialogs
{
public interface IBootstrapperDialog
{
public Bootstrapper Bootstrapper { get; set; }
public Bootstrapper? Bootstrapper { get; set; }
string Message { get; set; }
ProgressBarStyle ProgressStyle { get; set; }

View File

@ -1,4 +1,5 @@
using System.Drawing;
using System;
using System.Drawing;
namespace Bloxstrap.Enums
{
@ -16,6 +17,11 @@ namespace Bloxstrap.Enums
public static class BootstrapperIconEx
{
public static string GetPackUri(this BootstrapperIcon icon)
{
return $"pack://application:,,,/Resources/{Enum.GetName(icon)}-png.png";
}
public static Icon GetIcon(this BootstrapperIcon icon)
{
switch (icon)

View File

@ -10,6 +10,7 @@ namespace Bloxstrap.Enums
LegacyDialog2009,
LegacyDialog2011,
ProgressDialog,
FluentDialog
}
public static class BootstrapperStyleEx
@ -22,7 +23,8 @@ namespace Bloxstrap.Enums
BootstrapperStyle.LegacyDialog2009 => new LegacyDialog2009(),
BootstrapperStyle.LegacyDialog2011 => new LegacyDialog2011(),
BootstrapperStyle.ProgressDialog => new ProgressDialog(),
_ => new ProgressDialog()
BootstrapperStyle.FluentDialog => new FluentDialog(),
_ => new FluentDialog()
};
}
}

View File

@ -6,7 +6,7 @@ namespace Bloxstrap.Models
public class Settings
{
// bloxstrap configuration
public BootstrapperStyle BootstrapperStyle { get; set; } = BootstrapperStyle.ProgressDialog;
public BootstrapperStyle BootstrapperStyle { get; set; } = BootstrapperStyle.FluentDialog;
public BootstrapperIcon BootstrapperIcon { get; set; } = BootstrapperIcon.IconBloxstrap;
public Theme Theme { get; set; } = Theme.Default;
public bool CheckForUpdates { get; set; } = true;

View File

@ -72,10 +72,11 @@ namespace Bloxstrap.ViewModels
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 },
{ "Fluent", BootstrapperStyle.FluentDialog },
{ "Progress (~2014)", BootstrapperStyle.ProgressDialog },
{ "Legacy (2011 - 2014)", BootstrapperStyle.LegacyDialog2011 },
{ "Legacy (2009 - 2011)", BootstrapperStyle.LegacyDialog2009 },
{ "Vista (2009 - 2011)", BootstrapperStyle.VistaDialog },
};
public string Dialog
@ -87,13 +88,13 @@ namespace Bloxstrap.ViewModels
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 },
{ "2022", BootstrapperIcon.Icon2022 },
{ "2019", BootstrapperIcon.Icon2019 },
{ "2022", BootstrapperIcon.Icon2022 }
{ "2017", BootstrapperIcon.Icon2017 },
{ "2016", BootstrapperIcon.IconLate2015 },
{ "2015", BootstrapperIcon.IconEarly2015 },
{ "2011", BootstrapperIcon.Icon2011 },
{ "2009", BootstrapperIcon.Icon2009 },
};
public string Icon

View File

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows;
using CommunityToolkit.Mvvm.Input;
using Bloxstrap.Dialogs;
using Bloxstrap.Enums;
namespace Bloxstrap.ViewModels
{
class FluentDialogViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
private readonly IBootstrapperDialog _dialog;
public ICommand CancelInstallCommand => new RelayCommand(CancelInstall);
public string Icon { get; set; } = App.Settings.Prop.BootstrapperIcon.GetPackUri();
public string Message { get; set; } = "Please wait...";
public bool ProgressIndeterminate { get; set; } = true;
public int ProgressValue { get; set; } = 0;
public Visibility CancelButtonVisibility { get; set; } = Visibility.Collapsed;
public string CancelButtonText { get; set; } = "Cancel";
public FluentDialogViewModel(IBootstrapperDialog dialog)
{
_dialog = dialog;
}
private void CancelInstall()
{
_dialog.Bootstrapper?.CancelInstall();
_dialog.CloseBootstrapper();
}
}
}

View File

@ -27,12 +27,7 @@ namespace Bloxstrap.Views
public void SetTheme()
{
var theme = ThemeType.Light;
if (App.Settings.Prop.Theme.GetFinal() == Enums.Theme.Dark)
theme = ThemeType.Dark;
_themeService.SetTheme(theme);
_themeService.SetTheme(App.Settings.Prop.Theme.GetFinal() == Enums.Theme.Dark ? ThemeType.Dark : ThemeType.Light);
_themeService.SetSystemAccent();
}