Переглянути джерело

Include autosaved file in crash report and added rounded corners to the crash report dialog

CPKreuz 1 рік тому
батько
коміт
12d8b2efb8

+ 12 - 1
src/PixiEditor/Models/DataHolders/AutosaveFilePathInfo.cs

@@ -1,10 +1,21 @@
-namespace PixiEditor.Models.DataHolders;
+using System.IO;
+
+namespace PixiEditor.Models.DataHolders;
 
 public class AutosaveFilePathInfo
 {
     public string? OriginalPath { get; set; }
     
     public string? AutosavePath { get; set; }
+
+    public Guid? GetAutosaveGuid()
+    {
+        if (AutosavePath == null)
+            return null;
+        
+        string guidString = Path.GetFileNameWithoutExtension(AutosavePath)["autosave-".Length..];
+        return Guid.Parse(guidString);
+    }
     
     public AutosaveFilePathInfo(string? originalPath, string? autosavePath)
     {

+ 64 - 21
src/PixiEditor/Models/DataHolders/CrashReport.cs

@@ -207,40 +207,35 @@ internal class CrashReport : IDisposable
 
     private ZipArchive ZipFile { get; set; }
 
-    public int GetDocumentCount() => ZipFile.Entries.Where(x => x.FullName.EndsWith(".pixi")).Count();
+    public int GetDocumentCount() => ZipFile.Entries.Count(x => x.FullName.StartsWith("Documents") && x.FullName.EndsWith(".pixi"));
 
-    public List<(AutosaveFilePathInfo originalPath, byte[] dotPixiBytes)> RecoverDocuments()
+    public List<RecoveredPixi> RecoverDocuments()
     {
-        // Load .pixi files
-        Dictionary<string, byte[]> recoveredDocuments = new();
-        foreach (ZipArchiveEntry entry in ZipFile.Entries.Where(x => x.FullName.EndsWith(".pixi")))
-        {
-            using Stream stream = entry.Open();
-            using MemoryStream memStream = new();
-            stream.CopyTo(memStream);
-            recoveredDocuments.Add(entry.FullName["Documents/".Length..], memStream.ToArray());
-        }
-
         var originalPathsEntry = ZipFile.Entries.First(entry => entry.FullName == "DocumentInfo.json");
-        
+
         // Load original paths
-        Dictionary<string, AutosaveFilePathInfo> originalPaths;
+        Dictionary<string, AutosaveFilePathInfo> paths;
         {
             using Stream stream = originalPathsEntry.Open();
             using StreamReader reader = new(stream);
             string json = reader.ReadToEnd();
-            originalPaths = JsonConvert.DeserializeObject<Dictionary<string, AutosaveFilePathInfo>>(json);
+            paths = JsonConvert.DeserializeObject<Dictionary<string, AutosaveFilePathInfo>>(json);
         }
 
-        var list = new List<(AutosaveFilePathInfo originalPath, byte[] dotPixiBytes)>();
-
-        foreach (var document in recoveredDocuments)
+        // Load .pixi files
+        List<RecoveredPixi> recoveredDocuments = new();
+        foreach (var path in paths)
         {
-            var originalPath = originalPaths[document.Key];
-            list.Add((originalPath, document.Value));
+            ZipArchiveEntry autosaved = null;
+            if (path.Value.AutosavePath != null)
+            {
+                autosaved = ZipFile.GetEntry($"Autosave/{Path.GetFileName(path.Value.AutosavePath)}");
+            }
+
+            recoveredDocuments.Add(new RecoveredPixi(path.Value, ZipFile.GetEntry($"Documents/{path.Key}"), autosaved));
         }
 
-        return list;
+        return recoveredDocuments;
     }
 
     public void Dispose()
@@ -308,6 +303,18 @@ internal class CrashReport : IDisposable
                 originalPaths.Add(nameInZip, new AutosaveFilePathInfo(document.FullFilePath, document.AutosaveViewModel.LastSavedPath));
             }
             catch { }
+
+            try
+            {
+                if (document.AutosaveViewModel.LastSavedPath != null)
+                {
+                    using var file = File.OpenRead(document.AutosaveViewModel.LastSavedPath);
+                    using var entry = archive.CreateEntry($"Autosave/{Path.GetFileName(document.AutosaveViewModel.LastSavedPath)}").Open();
+                    
+                    file.CopyTo(entry);
+                }
+            }
+            catch { }
             counter++;
         }
 
@@ -332,6 +339,42 @@ internal class CrashReport : IDisposable
         ReportText = Encoding.UTF8.GetString(encodedReport);
     }
 
+    public class RecoveredPixi
+    {
+        public AutosaveFilePathInfo Path { get; }
+        
+        public ZipArchiveEntry RecoveredEntry { get; }
+        
+        public ZipArchiveEntry? AutosaveEntry { get; }
+
+        public byte[] GetRecoveredBytes()
+        {
+            var buffer = new byte[RecoveredEntry.Length];
+            using var stream = RecoveredEntry.Open();
+
+            stream.ReadExactly(buffer);
+            
+            return buffer;
+        }
+
+        public byte[] GetAutosaveBytes()
+        {
+            var buffer = new byte[AutosaveEntry.Length];
+            using var stream = AutosaveEntry.Open();
+
+            stream.ReadExactly(buffer);
+            
+            return buffer;
+        }
+
+        public RecoveredPixi(AutosaveFilePathInfo path, ZipArchiveEntry recoveredEntry, ZipArchiveEntry? autosaveEntry)
+        {
+            Path = path;
+            RecoveredEntry = recoveredEntry;
+            AutosaveEntry = autosaveEntry;
+        }
+    }
+    
     internal class CrashReportUserMessage
     {
         public string Message { get; set; }

+ 12 - 4
src/PixiEditor/ViewModels/SubViewModels/Main/FileViewModel.cs

@@ -132,11 +132,13 @@ internal class FileViewModel : SubViewModel<ViewModelMain>
             {
                 if (file.AutosavePath != null)
                 {
-                    string guidString = Path.GetFileNameWithoutExtension(file.AutosavePath)["autosave-".Length..];
                     var document = OpenFromPath(file.AutosavePath, false);
                     document.FullFilePath = file.OriginalPath;
-                    
-                    document.AutosaveViewModel.SetTempFileGuidAndLastSavedPath(Guid.Parse(guidString), file.AutosavePath);
+
+                    if (file.AutosavePath != null)
+                    {
+                        document.AutosaveViewModel.SetTempFileGuidAndLastSavedPath(file.GetAutosaveGuid()!.Value, file.AutosavePath);
+                    }
                 }
                 else
                 {
@@ -255,10 +257,16 @@ internal class FileViewModel : SubViewModel<ViewModelMain>
     /// <summary>
     /// Opens a .pixi file from path, creates a document from it, and adds it to the system
     /// </summary>
-    public void OpenRecoveredDotPixi(string? originalPath, byte[] dotPixiBytes)
+    public void OpenRecoveredDotPixi(string? originalPath, string? autosavePath, Guid? autosaveGuid, byte[] dotPixiBytes)
     {
         DocumentViewModel document = Importer.ImportDocument(dotPixiBytes, originalPath);
         document.MarkAsUnsaved();
+
+        if (autosavePath != null)
+        {
+            document.AutosaveViewModel.SetTempFileGuidAndLastSavedPath(autosaveGuid!.Value, autosavePath);
+        }
+        
         AddDocumentViewModelToTheSystem(document);
     }
 

+ 2 - 2
src/PixiEditor/Views/Dialogs/CrashReportDialog.xaml

@@ -32,13 +32,13 @@
         <dial:DialogTitleBar TitleKey="PixiEditor has crashed!" CloseCommand="{x:Static SystemCommands.CloseWindowCommand}" />
         <Grid Grid.Row="1" Margin="30,30,30,0" >
             <StackPanel>
-                <Grid Background="{StaticResource MainColor}">
+                <Border Background="{StaticResource MainColor}" CornerRadius="5">
                     <StackPanel Margin="7" VerticalAlignment="Center">
                         <TextBlock Text="{Binding DocumentCount, StringFormat={}{0} file(s) might be recoverable}"
                        d:Text="2 file(s) can be recovered"/>
                         <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>
+                </Border>
 
                 <WrapPanel Margin="0,20,0,5" Orientation="Horizontal" HorizontalAlignment="Center">
                     <Button Command="{Binding OpenSendCrashReportCommand}"

+ 13 - 3
src/PixiEditor/Views/MainWindow.xaml.cs

@@ -120,21 +120,31 @@ internal partial class MainWindow : Window
 
         var i = 0;
 
-        foreach (var (path, bytes) in documents)
+        foreach (var document in documents)
         {
             try
             {
-                fileVM.OpenRecoveredDotPixi(path.OriginalPath, bytes);
+                fileVM.OpenRecoveredDotPixi(document.Path.OriginalPath, document.Path.AutosavePath, document.Path.GetAutosaveGuid(), document.GetRecoveredBytes());
                 i++;
             }
             catch (Exception e)
             {
                 try
                 {
-                    fileVM.OpenFromPath(path.AutosavePath, false);
+                    fileVM.OpenFromPath(document.Path.AutosavePath, false);
+                    
                 }
                 catch (Exception deepE)
                 {
+                    try
+                    {
+                        fileVM.OpenRecoveredDotPixi(document.Path.OriginalPath, document.Path.AutosavePath, document.Path.GetAutosaveGuid(), document.GetAutosaveBytes());
+                    }
+                    catch (Exception veryDeepE)
+                    {
+                        CrashHelper.SendExceptionInfoToWebhook(veryDeepE);
+                    }
+                    
                     CrashHelper.SendExceptionInfoToWebhook(deepE);
                 }