Browse Source

Fixed crash report

Krzysztof Krysiński 1 year ago
parent
commit
100ab98c22

+ 4 - 11
src/PixiEditor.AvaloniaUI/Data/Localization/Languages/en.json

@@ -592,16 +592,9 @@
   "NAVIGATOR_DOCKABLE_TITLE": "Navigator",
   "SWATCHES_DOCKABLE_TITLE": "Swatches",
     "PALETTE_DOCKABLE_TITLE": "Palette",
-  
+
   "BROWSE_DIRECTORY": "Browse Directory",
-  "SEND_CRASH_REPORT_TITLE": "Send crash report",
-  "OPEN_IN_EXPLORER": "Open in explorer",
-  "CRASH_SEND_METHODS": "You can send your crash report using:",
-  "EMAIL": "E-Mail",
-  "CRASH_REPORT_DESCRIPTION": "The report contains the documents that were opened when the crash happened, feel free to review it before sending.",
-  "PIXIEDITOR_CRASHED_TITLE": "PixiEditor has crashed!",
-  "CRASH_ACTION_DESCRIPTION": "You can help the developers fix this bug by sending a crash report that was generated (you will still be able to recover the files).",
-  "SEND_REPORT": "Send report",
-  "RECOVER_FILES": "Recover files",
-  "ATTACH_DEBUGGER": "(Re)Attach debugger"
+  "CRASH_NOT_ALL_DOCUMENTS_RECOVERED_TITLE": "Not all documents were recovered",
+  "CRASH_NOT_ALL_DOCUMENTS_RECOVERED": "Could not recover all documents. Git gud at saving your work.",
+  "SEND": "Send report"
 }

+ 5 - 3
src/PixiEditor.AvaloniaUI/Helpers/CrashHelper.cs

@@ -1,4 +1,5 @@
-using System.Globalization;
+using System.Collections.Generic;
+using System.Globalization;
 using System.IO;
 using System.Net.Http;
 using System.Runtime.CompilerServices;
@@ -7,6 +8,7 @@ using System.Threading.Tasks;
 using ByteSizeLib;
 using Hardware.Info;
 using PixiEditor.AvaloniaUI.Models.ExceptionHandling;
+using PixiEditor.AvaloniaUI.ViewModels.Document;
 
 namespace PixiEditor.AvaloniaUI.Helpers;
 
@@ -14,7 +16,7 @@ internal class CrashHelper
 {
     private readonly IHardwareInfo hwInfo;
 
-    public static void SaveCrashInfo(Exception exception)
+    public static void SaveCrashInfo(Exception exception, IEnumerable<DocumentViewModel> documents)
     {
         try
         {
@@ -26,7 +28,7 @@ internal class CrashHelper
         }
         
         var report = CrashReport.Generate(exception);
-        report.TrySave();
+        report.TrySave(documents);
         report.RestartToCrashReport();
     }
 

+ 7 - 10
src/PixiEditor.AvaloniaUI/Models/ExceptionHandling/CrashReport.cs

@@ -11,9 +11,11 @@ using PixiEditor.AvaloniaUI.Helpers;
 using PixiEditor.AvaloniaUI.Models.Commands;
 using PixiEditor.AvaloniaUI.Models.Preferences;
 using PixiEditor.AvaloniaUI.ViewModels;
+using PixiEditor.AvaloniaUI.ViewModels.Document;
 using PixiEditor.AvaloniaUI.Views;
 using PixiEditor.Extensions.Common.Localization;
 using PixiEditor.Extensions.Common.UserPreferences;
+using PixiEditor.Parser;
 
 namespace PixiEditor.AvaloniaUI.Models.ExceptionHandling;
 
@@ -345,11 +347,11 @@ internal class CrashReport : IDisposable
         process.Start();
     }
 
-    public bool TrySave()
+    public bool TrySave(IEnumerable<DocumentViewModel> documents)
     {
         try
         {
-            Save();
+            Save(documents);
             return true;
         }
         catch
@@ -358,7 +360,7 @@ internal class CrashReport : IDisposable
         }
     }
 
-    public void Save()
+    public void Save(IEnumerable<DocumentViewModel> documents)
     {
         using FileStream zipStream = new(FilePath, FileMode.Create, FileAccess.Write);
         using ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Create);
@@ -367,17 +369,12 @@ internal class CrashReport : IDisposable
         {
             reportStream.Write(Encoding.UTF8.GetBytes(ReportText));
         }
-        //TODO: Implement
-
-        /*var vm = ViewModelMain.Current;
-        if (vm is null)
-            return;*/
 
         // Write the documents into zip
         int counter = 0;
         var originalPaths = new Dictionary<string, string>();
         //TODO: Implement
-        /*foreach (var document in vm.DocumentManagerSubViewModel.Documents)
+        foreach (var document in documents)
         {
             try
             {
@@ -395,7 +392,7 @@ internal class CrashReport : IDisposable
             }
             catch { }
             counter++;
-        }*/
+        }
 
         // Write their original paths into a separate file
         {

+ 30 - 21
src/PixiEditor.AvaloniaUI/ViewModels/CrashReportViewModel.cs

@@ -1,7 +1,9 @@
-using System.Diagnostics;
+using System.ComponentModel;
+using System.Diagnostics;
 using System.Threading.Tasks;
 using Avalonia;
 using Avalonia.Controls;
+using Avalonia.Threading;
 using CommunityToolkit.Mvvm.Input;
 using PixiEditor.AvaloniaUI.Helpers;
 using PixiEditor.AvaloniaUI.Models.Dialogs;
@@ -12,7 +14,7 @@ using PixiEditor.Extensions.Common.Localization;
 
 namespace PixiEditor.AvaloniaUI.ViewModels;
 
-internal partial class CrashReportViewModel : ViewModelBase
+internal partial class CrashReportViewModel : Window
 {
     private bool hasRecoveredDocuments = true;
 
@@ -42,31 +44,38 @@ internal partial class CrashReportViewModel : ViewModelBase
     [RelayCommand(CanExecute = nameof(CanRecoverDocuments))]
     public async Task RecoverDocuments()
     {
+        if (!hasRecoveredDocuments)
+        {
+            return;
+        }
+
         MainWindow window = MainWindow.CreateWithRecoveredDocuments(CrashReport, out var showMissingFilesDialog);
 
-        Application.Current.Run(window);
-        window.Show();
-        hasRecoveredDocuments = false;
-        
-        if (showMissingFilesDialog)
+        window.Loaded += (sender, args) =>
         {
-            var dialog = new OptionsDialog<LocalizedString>(
-                "CRASH_NOT_ALL_DOCUMENTS_RECOVERED_TITLE",
-                new LocalizedString("CRASH_NOT_ALL_DOCUMENTS_RECOVERED"), 
-                MainWindow.Current!)
+            if (showMissingFilesDialog)
             {
+                var dialog = new OptionsDialog<LocalizedString>(
+                    "CRASH_NOT_ALL_DOCUMENTS_RECOVERED_TITLE",
+                    new LocalizedString("CRASH_NOT_ALL_DOCUMENTS_RECOVERED"),
+                    MainWindow.Current!)
                 {
-                    "SEND", _ =>
                     {
-                        var sendReportDialog = new SendCrashReportDialog(CrashReport);
-                        sendReportDialog.ShowDialog(window);
-                    }
-                },
-                "CLOSE"
-            };
-
-            await dialog.ShowDialog(true);
-        }
+                        "SEND", _ =>
+                        {
+                            var sendReportDialog = new SendCrashReportDialog(CrashReport);
+                            sendReportDialog.ShowDialog(window);
+                        }
+                    },
+                    "CLOSE"
+                };
+
+                _ = dialog.ShowDialog(true);
+            }
+        };
+
+        hasRecoveredDocuments = false;
+        Application.Current.Run(window);
     }
 
     public bool CanRecoverDocuments()

+ 9 - 8
src/PixiEditor.AvaloniaUI/Views/Dialogs/CrashReportDialog.axaml

@@ -1,4 +1,4 @@
-<dialogs:PixiEditorPopup x:Class="PixiEditor.AvaloniaUI.Views.Dialogs.CrashReportDialog"
+<Window x:Class="PixiEditor.AvaloniaUI.Views.Dialogs.CrashReportDialog"
         x:ClassModifier="internal"
         xmlns="https://github.com/avaloniaui"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -8,7 +8,9 @@
         xmlns:ui="clr-namespace:PixiEditor.Extensions.UI;assembly=PixiEditor.Extensions"
         xmlns:viewModels="clr-namespace:PixiEditor.AvaloniaUI.ViewModels"
         mc:Ignorable="d"
-        ui:Translator.Key="PIXIEDITOR_CRASHED_TITLE"
+        ExtendClientAreaToDecorationsHint="False"
+        ExtendClientAreaChromeHints="Default"
+        Title="PixiEditor has crashed!"
         MinWidth="480" MinHeight="195"
         x:DataType="viewModels:CrashReportViewModel"
         Width="480" Height="195">
@@ -19,21 +21,20 @@
         <StackPanel>
             <Grid Background="{DynamicResource ThemeBackgroundBrush}">
                 <StackPanel Margin="7" VerticalAlignment="Center">
-                    <!--TODO: Translate string format below-->
                     <TextBlock Text="{Binding DocumentCount, StringFormat={}{0} file(s) might be recoverable}"
                                d:Text="2 file(s) can be recovered"/>
-                    <TextBlock TextWrapping="Wrap" ui:Translator.Key="CRASH_ACTION_DESCRIPTION"/>
+                    <TextBlock TextWrapping="Wrap">You can help the developers fix this bug by sending a crash report that was generated (you will still be able to recover the files).</TextBlock>
                 </StackPanel>
             </Grid>
 
             <WrapPanel Margin="0,20,0,5" Orientation="Horizontal" HorizontalAlignment="Center">
                 <Button Command="{Binding OpenSendCrashReportCommand}"
-                        Width="120" ui:Translator.Key="SEND_REPORT"/>
+                        Width="120">Send report</Button>
                 <Button Margin="5,0,5,0" Width="120"
-                        Command="{Binding RecoverDocumentsCommand}" ui:Translator.Key="RECOVER_FILES"/>
+                        Command="{Binding RecoverDocumentsCommand}">Recover files</Button>
                 <Button IsVisible="{Binding IsDebugBuild}" Width="170"
-                        Command="{Binding AttachDebuggerCommand}" ui:Translator.Key="ATTACH_DEBUGGER"/>
+                        Command="{Binding AttachDebuggerCommand}">(Re)Attach debugger</Button>
             </WrapPanel>
         </StackPanel>
     </Grid>
-</dialogs:PixiEditorPopup>
+</Window>

+ 3 - 3
src/PixiEditor.AvaloniaUI/Views/Dialogs/DialogTitleBar.axaml

@@ -15,10 +15,10 @@
         <Grid Background="{DynamicResource ThemeBackgroundBrush1}" IsHitTestVisible="False"/>
         <TextBlock
             IsHitTestVisible="False"
-            TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" 
+            TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center"
             ui:Translator.Key="{Binding ElementName=uc, Path=TitleKey}"
-            Foreground="White" 
-            FontSize="15"
+            Foreground="{DynamicResource ThemeForegroundBrush}"
+            FontSize="13"
             Margin="5,0,0,0"/>
         <DockPanel IsHitTestVisible="True">
             <Button 

+ 2 - 1
src/PixiEditor.AvaloniaUI/Views/Dialogs/OptionPopup.axaml

@@ -9,8 +9,9 @@
     mc:Ignorable="d"
     d:DesignWidth="800"
     d:DesignHeight="450"
+    MinWidth="250"
+    MinHeight="150"
     x:Class="PixiEditor.AvaloniaUI.Views.Dialogs.OptionPopup"
-    Title="OptionPopup"
     SizeToContent="WidthAndHeight"
     Name="popup"
     ui:Translator.Key="{Binding #popup.Title, Mode=OneTime}">

+ 13 - 11
src/PixiEditor.AvaloniaUI/Views/Dialogs/SendCrashReportDialog.axaml

@@ -1,4 +1,4 @@
-<dialogs:PixiEditorPopup xmlns="https://github.com/avaloniaui"
+<Window xmlns="https://github.com/avaloniaui"
         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"
@@ -7,19 +7,21 @@
         mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
         x:Class="PixiEditor.AvaloniaUI.Views.Dialogs.SendCrashReportDialog"
         MinHeight="195" MinWidth="340"
+        ExtendClientAreaToDecorationsHint="False"
+        ExtendClientAreaChromeHints="Default"
         Height="195" Width="340"
-        ui:Translator.Key="SEND_CRASH_REPORT_TITLE">
+        Title="Send crash report">
     <StackPanel Margin="10">
         <TextBlock>You can find the report here:</TextBlock>
-        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
-            <Button Width="140" Click="OpenInExplorer" ui:Translator.Key="OPEN_IN_EXPLORER"/>
+        <StackPanel Margin="0 10" Orientation="Horizontal" HorizontalAlignment="Center">
+            <Button Width="140" Click="OpenInExplorer" Content="Open in explorer"/>
         </StackPanel>
-        <TextBlock TextAlignment="Center" ui:Translator.Key="CRASH_SEND_METHODS"/>
-        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
-            <Button Click="OpenHyperlink" Tag="github" ui:Translator.Key="GITHUB"/>
-            <Button Click="OpenHyperlink" Tag="discord" ui:Translator.Key="DISCORD"/>
-            <Button Click="OpenHyperlink" Tag="email" ui:Translator.Key="EMAIL"/>
+        <TextBlock TextAlignment="Center" Text="You can send your crash report using:"/>
+        <StackPanel Margin="0 10" Orientation="Horizontal" HorizontalAlignment="Center">
+            <Button Click="OpenHyperlink" Tag="github" Content="GitHub"/>
+            <Button Click="OpenHyperlink" Tag="discord" Content="Discord"/>
+            <Button Click="OpenHyperlink" Tag="email" Content="E-Mail"/>
         </StackPanel>
-        <TextBlock TextWrapping="Wrap" TextAlignment="Center" ui:Translator.Key="CRASH_REPORT_DESCRIPTION"/>
+        <TextBlock TextWrapping="Wrap" TextAlignment="Center" Text="The report contains the documents that were opened when the crash happened, feel free to review it before sending."/>
     </StackPanel>
-</dialogs:PixiEditorPopup>
+</Window>

+ 18 - 8
src/PixiEditor.AvaloniaUI/Views/Dialogs/SendCrashReportDialog.axaml.cs

@@ -1,17 +1,14 @@
-using System.IO;
+using System.Diagnostics;
+using System.IO;
 using System.Text;
 using System.Web;
-using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Interactivity;
-using Avalonia.Markup.Xaml;
 using PixiEditor.AvaloniaUI.Models.ExceptionHandling;
-using PixiEditor.AvaloniaUI.ViewModels;
-using PixiEditor.OperatingSystem;
 
 namespace PixiEditor.AvaloniaUI.Views.Dialogs;
 
-internal partial class SendCrashReportDialog : PixiEditorPopup
+internal partial class SendCrashReportDialog : Window
 {
     const string DiscordInviteLink = "https://discord.gg/eh8gx6vNEp";
 
@@ -40,7 +37,7 @@ internal partial class SendCrashReportDialog : PixiEditorPopup
 
         File.Copy(report.FilePath, Path.Combine(tempPath, Path.GetFileName(report.FilePath)), true);
 
-        IOperatingSystem.Current.ProcessUtility.ShellExecute(tempPath);
+        ShellExecute(tempPath);
     }
 
     private void OpenHyperlink(object sender, RoutedEventArgs e)
@@ -60,7 +57,7 @@ internal partial class SendCrashReportDialog : PixiEditorPopup
         };
 
         OpenInExplorer(null, null);
-        IOperatingSystem.Current.ProcessUtility.ShellExecute(result);
+        ShellExecute(result);
 
         string GetGitHubLink()
         {
@@ -86,4 +83,17 @@ internal partial class SendCrashReportDialog : PixiEditorPopup
             return builder.ToString();
         }
     }
+
+    private void ShellExecute(string path)
+    {
+        // Cannot use IOperatingSystem.Current.ProcessUtility.ShellExecute because app crashed and IOperatingSystem.Current is null
+        // TODO: Other OS support?
+        ProcessStartInfo startInfo = new()
+        {
+            FileName = path,
+            UseShellExecute = true
+        };
+
+        Process.Start(startInfo);
+    }
 }

+ 4 - 1
src/PixiEditor.AvaloniaUI/Views/MainWindow.axaml.cs

@@ -140,6 +140,9 @@ internal partial class MainWindow : Window
 
     private void MainWindow_Initialized(object? sender, EventArgs e)
     {
-        AppDomain.CurrentDomain.UnhandledException += (sender, e) => Helpers.CrashHelper.SaveCrashInfo((Exception)e.ExceptionObject);
+        AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
+        {
+            CrashHelper.SaveCrashInfo((Exception)e.ExceptionObject, DataContext.DocumentManagerSubViewModel.Documents);
+        };
     }
 }

+ 1 - 1
src/PixiEditor.Extensions/UI/Translator.cs

@@ -77,7 +77,7 @@ public class Translator : Control
 
     private static void OnLanguageChangedFlowDirection(AvaloniaObject objSender)
     {
-        objSender.SetValue(Control.FlowDirectionProperty, ILocalizationProvider.Current.CurrentLanguage.FlowDirection);
+        objSender.SetValue(Control.FlowDirectionProperty, ILocalizationProvider.Current?.CurrentLanguage.FlowDirection ?? FlowDirection.LeftToRight);
     }
 
     private static void TooltipLocalizedStringPropertyChanged(AvaloniaPropertyChangedEventArgs<LocalizedString> e)