Port and revamp the Crash Reporting System from old Gui project to Fluent
ADD
WalletWasabi.Fluent/CrashReport/CrashReportApp.axaml
+<Application xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:local="using:WalletWasabi.Fluent"
+ x:Class="WalletWasabi.Fluent.CrashReport.CrashReportApp">
+
+ <Application.DataTemplates>
+ <local:ViewLocator />
+ </Application.DataTemplates>
+
+ <Application.Resources>
+ <x:Double x:Key="ToggleSwitchThemeMinWidth">0</x:Double>
+ </Application.Resources>
+
+ <Application.Styles>
+ <StyleInclude Source="avares://WalletWasabi.Fluent/Styles/Themes/BaseDark.axaml" />
+ <StyleInclude Source="avares://WalletWasabi.Fluent/Icons/Icons.axaml" />
+ <StyleInclude Source="avares://WalletWasabi.Fluent/Styles/Styles.axaml" />
+ <StyleInclude Source="avares://WalletWasabi.Fluent/Controls/ContentArea.axaml" />
+ <StyleInclude Source="avares://WalletWasabi.Fluent/Controls/InfoMessage.axaml" />
+ </Application.Styles>
+</Application>
\ No newline at end of file

ADD
WalletWasabi.Fluent/CrashReport/CrashReportApp.axaml.cs
+using System;
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+using WalletWasabi.Fluent.CrashReport.ViewModels;
+using WalletWasabi.Models;
+using WalletWasabi.Fluent.CrashReport.Views;
+
+namespace WalletWasabi.Fluent.CrashReport
+{
+ public class CrashReportApp : Application
+ {
+ private readonly SerializableException _serializableException;
+
+ public CrashReportApp()
+ {
+ Name = "Wasabi Wallet Crash Report";
+ }
+
+ public CrashReportApp(SerializableException exception) : this()
+ {
+ _serializableException = exception;
+ }
+
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ desktop.MainWindow = new CrashReportWindow
+ {
+ DataContext = new CrashReportWindowViewModel(_serializableException)
+ };
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+ }
+}

ADD
WalletWasabi.Fluent/CrashReport/ViewModels/CrashReportWindowViewModel.cs
+using System;
+using System.IO;
+using ReactiveUI;
+using System.Windows.Input;
+using Avalonia;
+using WalletWasabi.Fluent.Helpers;
+using WalletWasabi.Fluent.ViewModels;
+using WalletWasabi.Fluent.ViewModels.HelpAndSupport;
+using WalletWasabi.Models;
+
+namespace WalletWasabi.Fluent.CrashReport.ViewModels
+{
+ public class CrashReportWindowViewModel : ViewModelBase
+ {
+ public CrashReportWindowViewModel(SerializableException serializedException)
+ {
+ SerializedException = serializedException;
+ CancelCommand = ReactiveCommand.Create(AppLifetimeHelper.Restart);
+ NextCommand = ReactiveCommand.Create(AppLifetimeHelper.Shutdown);
+
+ OpenGitHubRepoCommand = ReactiveCommand.CreateFromTask(async () =>
+ {
+ await IoHelpers.OpenBrowserAsync(AboutViewModel.UserSupportLink);
+ });
+
+ CopyTraceCommand = ReactiveCommand.CreateFromTask(async () =>
+ {
+ await Application.Current.Clipboard.SetTextAsync(Trace);
+ });
+ }
+
+ public SerializableException SerializedException { get; }
+
+ public ICommand OpenGitHubRepoCommand { get; }
+
+ public ICommand NextCommand { get; }
+
+ public ICommand CancelCommand { get; }
+
+ public ICommand CopyTraceCommand { get; }
+
+ public string Caption { get; } = $"A problem has occurred and Wasabi is unable to continue.";
+
+ public string Trace => $"{SerializedException.Message}{Environment.NewLine}" +
+ $"{Environment.NewLine}{SerializedException.StackTrace}";
+
+ public string Title { get; } = "Wasabi has crashed";
+ }
+}
\ No newline at end of file

ADD
WalletWasabi.Fluent/CrashReport/Views/CrashReportWindow.axaml
+<Window xmlns="https://github.com/avaloniaui"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:vm="using:WalletWasabi.Fluent.CrashReport.ViewModels"
+ xmlns:controls="clr-namespace:WalletWasabi.Fluent.Controls"
+ x:Class="WalletWasabi.Fluent.CrashReport.Views.CrashReportWindow"
+ Width="640" Height="480"
+ MinWidth="640" MinHeight="480"
+ MaxWidth="640" MaxHeight="480"
+ Title="{Binding Title}"
+ WindowStartupLocation="CenterScreen"
+ ExtendClientAreaToDecorationsHint="True"
+ ExtendClientAreaChromeHints="PreferSystemChrome"
+ x:Name="CrashReporterWindow"
+ x:CompileBindings="True"
+ x:DataType="vm:CrashReportWindowViewModel">
+ <Panel Margin="{Binding #CrashReporterWindow.OffScreenMargin}">
+ <controls:ContentArea EnableNext="True"
+ NextContent="Exit"
+ CancelContent="Restart Wasabi"
+ FocusNext="True"
+ Title="{Binding Title}"
+ Caption="{Binding Caption}"
+ ScrollViewer.HorizontalScrollBarVisibility="Disabled"
+ ScrollViewer.VerticalScrollBarVisibility="Disabled">
+ <controls:ContentArea.Styles>
+ <Style Selector="controls|ContentArea /template/ DockPanel#MainDockPanel">
+ <Setter Property="Margin" Value="0 36 0 0" />
+ </Style>
+ </controls:ContentArea.Styles>
+ <DockPanel LastChildFill="True">
+ <controls:InfoMessage DockPanel.Dock="Bottom" VerticalAlignment="Center" HorizontalAlignment="Center"
+ Margin="0 20 0 0">
+ <Panel>
+ <WrapPanel>
+ <TextBlock Text="You can click this icon" />
+ <controls:AnimatedButton Margin="5 0"
+ ToolTip.Tip="Copy Log"
+ Command="{Binding CopyTraceCommand}"
+ NormalIcon="{StaticResource copy_regular}"
+ ClickIcon="{StaticResource copy_confirmed}"
+ InitialOpacity="1.0"/>
+ <TextBlock Text="to copy the above text and post an issue tracker on our" />
+ <Button Margin="5 0" Classes="activeHyperLink" Content="GitHub repo here"
+ Command="{Binding OpenGitHubRepoCommand}" />
+ <TextBlock Text="so we can take a closer look." />
+ </WrapPanel>
+ </Panel>
+ </controls:InfoMessage>
+ <TextBox Classes="selectableTextBlock monoSpaced wrap"
+ Text="{Binding Trace}" />
+ </DockPanel>
+ </controls:ContentArea>
+ <Viewbox Width="300" Height="300" Opacity="0.1" VerticalAlignment="Center"
+ HorizontalAlignment="Right" IsHitTestVisible="False">
+ <ContentControl Template="{DynamicResource wasabi_logo_dynamic}" />
+ </Viewbox>
+ </Panel>
+</Window>
\ No newline at end of file

ADD
WalletWasabi.Fluent/CrashReport/Views/CrashReportWindow.axaml.cs
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace WalletWasabi.Fluent.CrashReport.Views
+{
+ public class CrashReportWindow : Window
+ {
+ public CrashReportWindow()
+ {
+ InitializeComponent();
+#if DEBUG
+ this.AttachDevTools();
+#endif
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}

ADD
WalletWasabi.Fluent/Helpers/AppLifetimeHelper.cs
+using System;
+using System.Diagnostics;
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using WalletWasabi.Microservices;
+
+namespace WalletWasabi.Fluent.Helpers
+{
+ /// <summary>
+ /// Helper methods for Application lifetime related functions.
+ /// </summary>
+ public static class AppLifetimeHelper
+ {
+ /// <summary>
+ /// Attempts to restart the app without passing any program arguments.
+ /// </summary>
+ /// <remarks>
+ /// This method is only functional on the published builds
+ /// and not on debugging runs.
+ /// </remarks>
+ public static void Restart()
+ {
+ StartAppWithArgs();
+ Shutdown();
+ }
+
+ /// <summary>
+ /// Attempts to start a new instance of the app with optional program arguments
+ /// </summary>
+ /// <remarks>
+ /// This method is only functional on the published builds
+ /// and not on debugging runs.
+ /// </remarks>
+ /// <param name="args">The program arguments to pass to the new instance.</param>
+ public static void StartAppWithArgs(string args = "")
+ {
+ var path = Process.GetCurrentProcess().MainModule?.FileName;
+
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new InvalidOperationException($"Invalid path: '{path}'");
+ }
+
+ var startInfo = ProcessStartInfoFactory.Make(path, args);
+ using var p = Process.Start(startInfo);
+ }
+
+ /// <summary>
+ /// Attempts to shutdown the current instance of the app safely.
+ /// </summary>
+ public static void Shutdown()
+ {
+ (Application.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.Shutdown();
+ }
+ }
+}
\ No newline at end of file

Port and revamp the Crash Reporting System from old Gui project to Fluent