فهرست منبع

Show 'modified by' device in conflict resolver

Fixes: #492
Antony Male 6 سال پیش
والد
کامیت
60be7abee1

+ 1 - 0
src/SyncTrayzor/Pages/ConflictResolution/ConflictOptionViewModel.cs

@@ -15,6 +15,7 @@ namespace SyncTrayzor.Pages.ConflictResolution
         public DateTime DateCreated => this.ConflictOption.Created;
         public DateTime LastModified => this.ConflictOption.LastModified;
         public string Size => FormatUtils.BytesToHuman(this.ConflictOption.SizeBytes, 1);
+        public string ModifiedBy => this.ConflictOption.Device?.Name;
 
         public ConflictOptionViewModel(ConflictOption conflictOption)
         {

+ 10 - 1
src/SyncTrayzor/Pages/ConflictResolution/SingleConflictResolutionView.xaml

@@ -18,6 +18,7 @@
                 <ColumnDefinition Width="{Binding View.Columns[1].ActualWidth, ElementName=SelectConflictOptions}"/>
                 <ColumnDefinition Width="{Binding View.Columns[2].ActualWidth, ElementName=SelectConflictOptions}"/>
                 <ColumnDefinition Width="{Binding View.Columns[3].ActualWidth, ElementName=SelectConflictOptions}"/>
+                <ColumnDefinition Width="{Binding View.Columns[4].ActualWidth, ElementName=SelectConflictOptions}"/>
             </Grid.ColumnDefinitions>
             <Grid.RowDefinitions>
                 <RowDefinition/>
@@ -40,7 +41,8 @@
             <TextBlock Grid.Row="1" Grid.Column="0" Style="{StaticResource Value}" Text="{Binding Conflict.FileName}"/>
             <TextBlock Grid.Row="1" Grid.Column="1" Style="{StaticResource Value}" Text="{Binding Conflict.LastModified}"/>
             <TextBlock Grid.Row="1" Grid.Column="2" Style="{StaticResource Value}" Text="{Binding Conflict.Size}"/>
-            <Button Grid.Row="1" Grid.Column="3"
+            
+            <Button Grid.Row="1" Grid.Column="4"
                                 HorizontalAlignment="Left"
                                 Style="{StaticResource Value}"
                                 Padding="5,0"
@@ -76,6 +78,13 @@
                             </DataTemplate>
                         </GridViewColumn.CellTemplate>
                     </GridViewColumn>
+                    <GridViewColumn Header="{l:Loc ConflictResolutionView_Header_ModifiedBy}">
+                        <GridViewColumn.CellTemplate>
+                            <DataTemplate>
+                                <TextBlock Margin="0,0,10,0" Text="{Binding ModifiedBy}"/>
+                            </DataTemplate>
+                        </GridViewColumn.CellTemplate>
+                    </GridViewColumn>
                     <GridViewColumn>
                         <GridViewColumn.CellTemplate>
                             <DataTemplate>

+ 10 - 1
src/SyncTrayzor/Properties/Resources.Designer.cs

@@ -19,7 +19,7 @@ namespace SyncTrayzor.Properties {
     // class via a tool like ResGen or Visual Studio.
     // To add or remove a member, edit your .ResX file then rerun ResGen
     // with the /str option, or rebuild your VS project.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
     public class Resources {
@@ -367,6 +367,15 @@ namespace SyncTrayzor.Properties {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized string similar to Modified By.
+        /// </summary>
+        public static string ConflictResolutionView_Header_ModifiedBy {
+            get {
+                return ResourceManager.GetString("ConflictResolutionView_Header_ModifiedBy", resourceCulture);
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized string similar to Original File.
         /// </summary>

+ 4 - 0
src/SyncTrayzor/Properties/Resources.resx

@@ -770,6 +770,10 @@ Do you want to restart SyncTrayzor now?</value>
     <value>Original File</value>
     <comment>Header shown above the 'Original File' entry, which contains the name of the original file in the conflict, and is shown when the user selects a conflict</comment>
   </data>
+  <data name="ConflictResolutionView_Header_ModifiedBy" xml:space="preserve">
+    <value>Modified By</value>
+    <comment>Header shown above the 'Modified by' entry, which contains the name of the device which last modified the file, and is shown when the user selects a conflict</comment>
+  </data>
   <data name="ConflictResolutionView_Scanning_CancelButton" xml:space="preserve">
     <value>Cancel</value>
     <comment>Text on the 'Cancel' button, shown next to the 'Scanning' progress bar at the top of the page when scanning is in progress</comment>

+ 23 - 7
src/SyncTrayzor/Services/Conflicts/ConflictFileManager.cs

@@ -7,6 +7,8 @@ using System.Threading.Tasks;
 using Pri.LongPath;
 using NLog;
 using System.Reactive.Linq;
+using SyncTrayzor.Syncthing.Devices;
+using SyncTrayzor.Syncthing;
 
 namespace SyncTrayzor.Services.Conflicts
 {
@@ -36,13 +38,15 @@ namespace SyncTrayzor.Services.Conflicts
 
         public DateTime Created { get; }
         public long SizeBytes { get; }
+        public Device Device { get; }
 
-        public ConflictOption(string filePath, DateTime lastModified, DateTime created, long sizeBytes)
+        public ConflictOption(string filePath, DateTime lastModified, DateTime created, long sizeBytes, Device device)
         {
             this.FilePath = filePath;
             this.LastModified = lastModified;
             this.Created = created;
             this.SizeBytes = sizeBytes;
+            this.Device = device;
         }
 
         public override string ToString()
@@ -68,12 +72,14 @@ namespace SyncTrayzor.Services.Conflicts
         public string FilePath { get; }
         public string OriginalPath { get; }
         public DateTime Created { get; }
+        public string ShortDeviceId { get; }
 
-        public ParsedConflictFileInfo(string filePath, string originalPath, DateTime created)
+        public ParsedConflictFileInfo(string filePath, string originalPath, DateTime created, string shortDeviceId)
         {
             this.FilePath = filePath;
             this.OriginalPath = originalPath;
             this.Created = created;
+            this.ShortDeviceId = shortDeviceId;
         }
     }
 
@@ -96,17 +102,19 @@ namespace SyncTrayzor.Services.Conflicts
         private const string syncthingSpecialFileMarker = "~syncthing~";
 
         private static readonly Regex conflictRegex =
-            new Regex(@"^(?<prefix>.*).sync-conflict-(?<year>\d{4})(?<month>\d{2})(?<day>\d{2})-(?<hours>\d{2})(?<mins>\d{2})(?<secs>\d{2})(?<suffix>.*)(?<extension>\..*)$");
+            new Regex(@"^(?<prefix>.*).sync-conflict-(?<year>\d{4})(?<month>\d{2})(?<day>\d{2})-(?<hours>\d{2})(?<mins>\d{2})(?<secs>\d{2})(-(?<device>[a-zA-Z0-9]+))?(?<suffix>.*)(?<extension>\..*)$");
         private static readonly Logger logger = LogManager.GetCurrentClassLogger();
         private const int maxSearchDepth = 255; // Loosely based on the max path length (a bit over)
 
         private readonly IFilesystemProvider filesystemProvider;
+        private readonly ISyncthingManager syncthingManager;
 
         public string ConflictPattern => conflictPattern;
 
-        public ConflictFileManager(IFilesystemProvider filesystemProvider)
+        public ConflictFileManager(IFilesystemProvider filesystemProvider, ISyncthingManager syncthingManager)
         {
             this.filesystemProvider = filesystemProvider;
+            this.syncthingManager = syncthingManager;
         }
 
         public IObservable<ConflictSet> FindConflicts(string basePath)
@@ -187,7 +195,12 @@ namespace SyncTrayzor.Services.Conflicts
                     try
                     {
                         var file = new ConflictFile(kvp.Key, this.filesystemProvider.GetLastWriteTime(kvp.Key), this.filesystemProvider.GetFileSize(kvp.Key));
-                        var conflicts = kvp.Value.Select(x => new ConflictOption(x.FilePath, this.filesystemProvider.GetLastWriteTime(x.FilePath), x.Created, this.filesystemProvider.GetFileSize(x.FilePath))).ToList();
+                        var devices = this.syncthingManager.Devices.FetchDevices();
+                        var conflicts = kvp.Value.Select(x =>
+                        {
+                            var device = x.ShortDeviceId == null ? null : devices.FirstOrDefault(d => d.ShortDeviceId == x.ShortDeviceId);
+                            return new ConflictOption(x.FilePath, this.filesystemProvider.GetLastWriteTime(x.FilePath), x.Created, this.filesystemProvider.GetFileSize(x.FilePath), device);
+                        }).ToList();
                         observer.OnNext(new ConflictSet(file, conflicts));
                         cancellationToken.ThrowIfCancellationRequested();
                     }
@@ -255,6 +268,9 @@ namespace SyncTrayzor.Services.Conflicts
             var hours = Int32.Parse(parsed.Groups["hours"].Value);
             var mins = Int32.Parse(parsed.Groups["mins"].Value);
             var secs = Int32.Parse(parsed.Groups["secs"].Value);
+            var device = parsed.Groups["device"].Value;
+            if (string.IsNullOrWhiteSpace(device))
+                device = null;
             var suffix = parsed.Groups["suffix"].Value;
             var extension = parsed.Groups["extension"].Value;
 
@@ -279,14 +295,14 @@ namespace SyncTrayzor.Services.Conflicts
                 var withSuffix = Path.Combine(directory, prefix + suffix + extension);
                 if (this.filesystemProvider.FileExists(withSuffix))
                 {
-                    parsedConflictFileInfo = new ParsedConflictFileInfo(filePath, withSuffix, dateCreated);
+                    parsedConflictFileInfo = new ParsedConflictFileInfo(filePath, withSuffix, dateCreated, device);
                     return true;
                 }
 
                 var withoutSuffix = Path.Combine(directory, prefix + extension);
                 if (this.filesystemProvider.FileExists(withoutSuffix))
                 {
-                    parsedConflictFileInfo = new ParsedConflictFileInfo(filePath, withoutSuffix, dateCreated);
+                    parsedConflictFileInfo = new ParsedConflictFileInfo(filePath, withoutSuffix, dateCreated, device);
                     return true;
                 }
             }

+ 4 - 0
src/SyncTrayzor/Syncthing/Devices/Device.cs

@@ -8,6 +8,10 @@ namespace SyncTrayzor.Syncthing.Devices
         private readonly object syncRoot = new object();
 
         public string DeviceId { get; }
+
+        private string _shortDeviceId;
+        public string ShortDeviceId => _shortDeviceId ?? (_shortDeviceId = this.DeviceId.Substring(0, this.DeviceId.IndexOf('-')));
+
         public string Name { get; }
 
         public bool IsConnected