Add new exception dialog

This commit is contained in:
pizzaboxer 2023-07-01 20:34:00 +01:00
parent e708ef30fa
commit dc0531eb38
No known key found for this signature in database
GPG Key ID: 59D4A1DBAD0F2BA8
11 changed files with 159 additions and 66 deletions

View File

@ -16,10 +16,10 @@ using Microsoft.Win32;
using Bloxstrap.Extensions;
using Bloxstrap.Models;
using Bloxstrap.Models.Attributes;
using Bloxstrap.UI;
using Bloxstrap.UI.BootstrapperDialogs;
using Bloxstrap.UI.MessageBox;
using Bloxstrap.Utility;
using Bloxstrap.UI;
namespace Bloxstrap
{
@ -100,8 +100,17 @@ namespace Bloxstrap
Logger.WriteLine("[App::OnStartup] An exception occurred when running the main thread");
Logger.WriteLine($"[App::OnStartup] {e.Exception}");
FinalizeExceptionHandling(e.Exception);
}
void FinalizeExceptionHandling(Exception exception)
{
#if DEBUG
throw exception;
#endif
if (!IsQuiet)
Settings.Prop.BootstrapperStyle.GetNew().ShowError($"{e.Exception.GetType()}: {e.Exception.Message}");
Controls.ShowExceptionDialog(exception);
Terminate(Bootstrapper.ERROR_INSTALL_FAILURE);
}
@ -313,13 +322,9 @@ namespace Bloxstrap
}
}
// there's a bug here that i have yet to fix!
// sometimes the task just terminates when the bootstrapper hasn't
// actually finished, causing the bootstrapper to hang indefinitely
// i have no idea how the fuck this happens, but it happens like VERY
// rarely so i'm not too concerned by it
// maybe one day ill find out why it happens
Task bootstrapperTask = Task.Run(() => bootstrapper.Run()).ContinueWith(t =>
Task bootstrapperTask = Task.Run(() => bootstrapper.Run());
bootstrapperTask.ContinueWith(t =>
{
Logger.WriteLine("[App::OnStartup] Bootstrapper task has finished");
@ -331,16 +336,18 @@ namespace Bloxstrap
Logger.WriteLine($"[App::OnStartup] {t.Exception}");
#if DEBUG
throw t.Exception;
#else
var exception = t.Exception.InnerExceptions.Count >= 1 ? t.Exception.InnerExceptions[0] : t.Exception;
dialog?.ShowError($"{exception.GetType()}: {exception.Message}");
Terminate(Bootstrapper.ERROR_INSTALL_FAILURE);
Exception exception = t.Exception;
#if !DEBUG
if (t.Exception.GetType().ToString() == "System.AggregateException")
exception = t.Exception.InnerException!;
#endif
FinalizeExceptionHandling(exception);
});
dialog?.ShowBootstrapper();
bootstrapperTask.Wait();
if (singletonMutex is not null)

View File

@ -16,9 +16,12 @@ namespace Bloxstrap
public class Logger
{
private readonly SemaphoreSlim _semaphore = new(1, 1);
private readonly List<string> _backlog = new();
private FileStream? _filestream;
public readonly List<string> Backlog = new();
public bool Initialized = false;
public string? Filename;
public void Initialize(string filename)
{
if (_filestream is not null)
@ -31,10 +34,13 @@ namespace Bloxstrap
_filestream = File.Open(filename, FileMode.Create, FileAccess.Write, FileShare.Read);
if (_backlog.Count > 0)
WriteToLog(string.Join("\r\n", _backlog));
if (Backlog.Count > 0)
WriteToLog(string.Join("\r\n", Backlog));
WriteLine($"[Logger::Logger] Initialized at {filename}");
Initialized = true;
Filename = filename;
}
public void WriteLine(string message)
@ -49,16 +55,16 @@ namespace Bloxstrap
private async void WriteToLog(string message)
{
if (_filestream is null)
if (!Initialized)
{
_backlog.Add(message);
Backlog.Add(message);
return;
}
try
{
await _semaphore.WaitAsync();
await _filestream.WriteAsync(Encoding.Unicode.GetBytes($"{message}\r\n"));
await _filestream!.WriteAsync(Encoding.Unicode.GetBytes($"{message}\r\n"));
await _filestream.FlushAsync();
}
finally

View File

@ -14,11 +14,5 @@ namespace Bloxstrap.UI.BootstrapperDialogs
App.Terminate();
}
public static void ShowError(string message)
{
Controls.ShowMessageBox($"An error occurred while starting Roblox\n\nDetails: {message}", MessageBoxImage.Error);
App.Terminate(Bootstrapper.ERROR_INSTALL_FAILURE);
}
}
}

View File

@ -15,6 +15,5 @@ namespace Bloxstrap.UI.BootstrapperDialogs
void ShowBootstrapper();
void CloseBootstrapper();
void ShowSuccess(string message, Action? callback = null);
void ShowError(string message);
}
}

View File

@ -92,8 +92,6 @@ namespace Bloxstrap.UI.BootstrapperDialogs.WPF.Views
public void CloseBootstrapper() => Dispatcher.BeginInvoke(this.Close);
public void ShowSuccess(string message, Action? callback) => BaseFunctions.ShowSuccess(message, callback);
public void ShowError(string message) => BaseFunctions.ShowError(message);
#endregion
}
}

View File

@ -86,10 +86,7 @@ namespace Bloxstrap.UI.BootstrapperDialogs.WPF.Views
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, Action? callback) => BaseFunctions.ShowSuccess(message, callback);
public void ShowError(string message) => BaseFunctions.ShowError(message);
#endregion
}
}

View File

@ -101,8 +101,6 @@ namespace Bloxstrap.UI.BootstrapperDialogs.WinForms
}
public virtual void ShowSuccess(string message, Action? callback) => BaseFunctions.ShowSuccess(message, callback);
public virtual void ShowError(string message) => BaseFunctions.ShowError(message);
#endregion
}
}

View File

@ -109,36 +109,6 @@ namespace Bloxstrap.UI.BootstrapperDialogs.WinForms
}
}
public override void ShowError(string message)
{
if (this.InvokeRequired)
{
this.Invoke(ShowError, message);
}
else
{
TaskDialogPage errorDialog = new()
{
Icon = TaskDialogIcon.Error,
Caption = App.Settings.Prop.BootstrapperTitle,
Heading = "An error occurred while starting Roblox",
Buttons = { TaskDialogButton.Close },
Expander = new TaskDialogExpander()
{
Text = message,
CollapsedButtonText = "See details",
ExpandedButtonText = "Hide details",
Position = TaskDialogExpanderPosition.AfterText
}
};
errorDialog.Buttons[0].Click += (sender, e) => App.Terminate(Bootstrapper.ERROR_INSTALL_FAILURE);
_dialogPage.Navigate(errorDialog);
_dialogPage = errorDialog;
}
}
public override void CloseBootstrapper()
{
if (this.InvokeRequired)

View File

@ -1,4 +1,6 @@
using System.Windows;
using System;
using System.Drawing;
using System.Windows;
using Bloxstrap.Enums;
using Bloxstrap.UI.Menu.Views;
@ -22,5 +24,13 @@ namespace Bloxstrap.UI
return NativeMessageBox.Show(message, icon, buttons, defaultResult);
}
}
public static void ShowExceptionDialog(Exception exception)
{
Application.Current.Dispatcher.Invoke(() =>
{
new ExceptionDialog(exception).ShowDialog();
});
}
}
}

View File

@ -0,0 +1,49 @@
<ui:UiWindow x:Class="Bloxstrap.UI.ExceptionDialog"
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:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:local="clr-namespace:Bloxstrap.UI.MessageBox"
mc:Ignorable="d"
Width="480"
MinHeight="0"
SizeToContent="Height"
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
ExtendsContentIntoTitleBar="True"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TitleBar Grid.Row="0" Grid.ColumnSpan="2" Padding="8" x:Name="RootTitleBar" ShowMinimize="False" ShowMaximize="False" CanMaximize="False" KeyboardNavigation.TabNavigation="None" />
<Grid Grid.Row="1" Margin="16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Width="32" Height="32" Margin="0,0,15,0" VerticalAlignment="Top" RenderOptions.BitmapScalingMode="HighQuality" Source="pack://application:,,,/Resources/MessageBox/Error.png" />
<StackPanel Grid.Column="1">
<TextBlock Text="An exception occurred while running Bloxstrap" FontSize="18" Foreground="{DynamicResource TextFillColorPrimaryBrush}" />
<RichTextBox x:Name="ErrorRichTextBox" Padding="8" Margin="0,16,0,0" Block.LineHeight="2" FontFamily="Courier New" IsReadOnly="True" />
<TextBlock Text="Please report this exception through a GitHub issue or in our Discord chat, along with a copy of the log file that was created." Margin="0,16,0,0" TextWrapping="Wrap" Foreground="{DynamicResource TextFillColorPrimaryBrush}" />
</StackPanel>
</Grid>
<Border Grid.Row="2" Padding="15" Background="{ui:ThemeResource SolidBackgroundFillColorSecondaryBrush}">
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight" HorizontalAlignment="Right">
<Button x:Name="LocateLogFileButton" Content="Locate log file" />
<ComboBox x:Name="ReportOptions" SelectedIndex="0" Padding="12,6,12,6" Margin="12,0,0,0">
<ComboBoxItem Content="Report exception" Visibility="Collapsed" />
<ComboBoxItem Content="Report via GitHub" />
<ComboBoxItem Content="Report via Discord" />
</ComboBox>
<Button x:Name="CloseButton" MinWidth="100" Content="Close" Margin="12,0,0,0" />
</StackPanel>
</Border>
</Grid>
</ui:UiWindow>

View File

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using System.Media;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using Bloxstrap.Utility;
namespace Bloxstrap.UI
{
// hmm... do i use MVVM for this?
// this is entirely static, so i think im fine without it, and this way is just so much more efficient
/// <summary>
/// Interaction logic for ExceptionDialog.xaml
/// </summary>
public partial class ExceptionDialog
{
public ExceptionDialog(Exception exception)
{
InitializeComponent();
Title = RootTitleBar.Title = $"{App.ProjectName} Exception";
ErrorRichTextBox.Selection.Text = $"{exception.GetType()}: {exception.Message}";
if (!App.Logger.Initialized)
LocateLogFileButton.Content = "Copy log contents";
LocateLogFileButton.Click += delegate
{
if (App.Logger.Initialized)
Process.Start("explorer.exe", $"/select,\"{App.Logger.Filename}\"");
else
Clipboard.SetText(String.Join("\r\n", App.Logger.Backlog));
};
ReportOptions.DropDownClosed += (sender, e) =>
{
string? selectionName = ReportOptions.SelectedItem.ToString();
ReportOptions.SelectedIndex = 0;
if (selectionName is null)
return;
if (selectionName.EndsWith("GitHub"))
Utilities.ShellExecute($"https://github.com/{App.ProjectRepository}/issues");
else if (selectionName.EndsWith("Discord"))
Utilities.ShellExecute("https://discord.gg/nKjV3mGq6R");
};
CloseButton.Click += delegate
{
Close();
};
SystemSounds.Hand.Play();
}
}
}