Command refactor, fixes, improvements
This commit is contained in:
53
src/Core/FileTime.Core/Command/CommandBase.cs
Normal file
53
src/Core/FileTime.Core/Command/CommandBase.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using AsyncEvent;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command
|
||||
{
|
||||
public abstract class CommandBase : ICommand
|
||||
{
|
||||
private readonly List<string> _canRunMessages = new();
|
||||
public Dictionary<AbsolutePath, List<OperationProgress>> OperationStatuses { get; set; } = new();
|
||||
protected OperationProgress? CurrentOperationProgress { get; set; }
|
||||
public virtual string DisplayLabel { get; protected set; }
|
||||
public virtual IReadOnlyList<string> CanRunMessages { get; protected set; }
|
||||
public virtual int Progress { get; protected set; }
|
||||
public virtual int CurrentProgress { get; protected set; }
|
||||
public virtual AsyncEventHandler ProgressChanged { get; } = new AsyncEventHandler();
|
||||
|
||||
public abstract Task<CanCommandRun> CanRun(PointInTime startPoint);
|
||||
public abstract Task<PointInTime> SimulateCommand(PointInTime startPoint);
|
||||
|
||||
protected CommandBase()
|
||||
{
|
||||
CanRunMessages = _canRunMessages.AsReadOnly();
|
||||
DisplayLabel = "";
|
||||
}
|
||||
|
||||
public async Task UpdateProgress()
|
||||
{
|
||||
var total = 0L;
|
||||
var current = 0L;
|
||||
|
||||
foreach (var folder in OperationStatuses.Values)
|
||||
{
|
||||
foreach (var item in folder)
|
||||
{
|
||||
current += item.Progress;
|
||||
total += item.TotalCount;
|
||||
}
|
||||
}
|
||||
|
||||
Progress = total == 0 ? 0 : (int)(current * 100 / total);
|
||||
if (CurrentOperationProgress == null)
|
||||
{
|
||||
CurrentProgress = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentProgress = CurrentOperationProgress.TotalCount == 0 ? 0 : (int)(CurrentOperationProgress.Progress * 100 / CurrentOperationProgress.TotalCount);
|
||||
}
|
||||
await ProgressChanged.InvokeAsync(this, AsyncEventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
45
src/Core/FileTime.Core/Command/Copy/CalculateOperation.cs
Normal file
45
src/Core/FileTime.Core/Command/Copy/CalculateOperation.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Core.Command.Copy
|
||||
{
|
||||
public class CalculateOperation : ICopyOperation
|
||||
{
|
||||
private readonly Dictionary<AbsolutePath, List<OperationProgress>> _operationStatuses;
|
||||
public IReadOnlyDictionary<AbsolutePath, List<OperationProgress>> OperationStatuses { get; }
|
||||
|
||||
public CalculateOperation()
|
||||
{
|
||||
_operationStatuses = new Dictionary<AbsolutePath, List<OperationProgress>>();
|
||||
OperationStatuses = new ReadOnlyDictionary<AbsolutePath, List<OperationProgress>>(_operationStatuses);
|
||||
}
|
||||
|
||||
public Task ContainerCopyDoneAsync(AbsolutePath path)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task CopyAsync(AbsolutePath from, AbsolutePath to, OperationProgress? operation, CopyCommandContext context)
|
||||
{
|
||||
var parentPath = to.GetParent();
|
||||
List<OperationProgress> operationsByFolder;
|
||||
if (_operationStatuses.ContainsKey(parentPath))
|
||||
{
|
||||
operationsByFolder = _operationStatuses[parentPath];
|
||||
}
|
||||
else
|
||||
{
|
||||
operationsByFolder = new List<OperationProgress>();
|
||||
_operationStatuses.Add(parentPath, operationsByFolder);
|
||||
}
|
||||
|
||||
var resolvedFrom = await from.ResolveAsync();
|
||||
operationsByFolder.Add(new OperationProgress(from.Path, resolvedFrom is IElement element ? await element.GetElementSize() : 0L));
|
||||
}
|
||||
|
||||
public Task CreateContainerAsync(IContainer target, string name)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
119
src/Core/FileTime.Core/Command/Copy/CopyCommand.cs
Normal file
119
src/Core/FileTime.Core/Command/Copy/CopyCommand.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using FileTime.Core.Interactions;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command.Copy
|
||||
{
|
||||
public class CopyCommand : CommandBase, ITransportationCommand
|
||||
{
|
||||
public IList<AbsolutePath> Sources { get; } = new List<AbsolutePath>();
|
||||
|
||||
public AbsolutePath? Target { get; set; }
|
||||
|
||||
public TransportMode? TransportMode { get; set; } = Command.TransportMode.Merge;
|
||||
internal TimeRunner? TimeRunner { get; private set; }
|
||||
|
||||
public bool TargetIsContainer => true;
|
||||
public List<InputElement> Inputs { get; } = new();
|
||||
public List<object>? InputResults { get; set; }
|
||||
|
||||
public CopyCommand()
|
||||
{
|
||||
DisplayLabel = "Copy";
|
||||
}
|
||||
|
||||
public override async Task<PointInTime> SimulateCommand(PointInTime startPoint)
|
||||
{
|
||||
if (Sources == null) throw new ArgumentException(nameof(Sources) + " can not be null");
|
||||
if (Target == null) throw new ArgumentException(nameof(Target) + " can not be null");
|
||||
if (TransportMode == null) throw new ArgumentException(nameof(TransportMode) + " can not be null");
|
||||
|
||||
var simulateOperation = new SimulateOperation();
|
||||
|
||||
await TraverseTree(Sources, Target, TransportMode.Value, simulateOperation);
|
||||
|
||||
return startPoint.WithDifferences(simulateOperation.NewDiffs);
|
||||
}
|
||||
|
||||
public async Task Execute(Func<AbsolutePath, AbsolutePath, OperationProgress?, CopyCommandContext, Task> copy, TimeRunner timeRunner)
|
||||
{
|
||||
if (Sources == null) throw new ArgumentException(nameof(Sources) + " can not be null");
|
||||
if (Target == null) throw new ArgumentException(nameof(Target) + " can not be null");
|
||||
if (TransportMode == null) throw new ArgumentException(nameof(TransportMode) + " can not be null");
|
||||
|
||||
TimeRunner = timeRunner;
|
||||
|
||||
await CalculateProgress();
|
||||
|
||||
var copyOperation = new CopyOperation(copy, this);
|
||||
|
||||
await TraverseTree(Sources, Target, TransportMode.Value, copyOperation);
|
||||
await TimeRunner.RefreshContainer.InvokeAsync(this, Target);
|
||||
}
|
||||
|
||||
private async Task CalculateProgress()
|
||||
{
|
||||
if (Sources == null) throw new ArgumentException(nameof(Sources) + " can not be null");
|
||||
if (Target == null) throw new ArgumentException(nameof(Target) + " can not be null");
|
||||
if (TransportMode == null) throw new ArgumentException(nameof(TransportMode) + " can not be null");
|
||||
|
||||
var calculateOperation = new CalculateOperation();
|
||||
await TraverseTree(Sources, Target, TransportMode.Value, calculateOperation);
|
||||
OperationStatuses = new Dictionary<AbsolutePath, List<OperationProgress>>(calculateOperation.OperationStatuses);
|
||||
}
|
||||
|
||||
private async Task TraverseTree(
|
||||
IEnumerable<AbsolutePath> sources,
|
||||
AbsolutePath target,
|
||||
TransportMode transportMode,
|
||||
ICopyOperation copyOperation)
|
||||
{
|
||||
var resolvedTarget = (IContainer?)await target.ResolveAsync();
|
||||
|
||||
foreach (var source in sources)
|
||||
{
|
||||
var item = await source.ResolveAsync();
|
||||
|
||||
if (item is IContainer container)
|
||||
{
|
||||
var targetContainer = target.GetChild(item.Name, AbsolutePathType.Container);
|
||||
if (resolvedTarget != null)
|
||||
{
|
||||
await resolvedTarget.RefreshAsync();
|
||||
|
||||
if (!await resolvedTarget.IsExistsAsync(item.Name))
|
||||
{
|
||||
await copyOperation.CreateContainerAsync(resolvedTarget, container.Name);
|
||||
}
|
||||
}
|
||||
|
||||
await TraverseTree((await container.GetItems())!.Select(i => new AbsolutePath(i)), targetContainer, transportMode, copyOperation);
|
||||
await copyOperation.ContainerCopyDoneAsync(new AbsolutePath(container));
|
||||
}
|
||||
else if (item is IElement element)
|
||||
{
|
||||
var newElementName = await Helper.CommandHelper.GetNewNameAsync(resolvedTarget, element.Name, transportMode);
|
||||
if (newElementName == null) continue;
|
||||
|
||||
OperationProgress? operation = null;
|
||||
var newElementPath = target.GetChild(newElementName, AbsolutePathType.Element);
|
||||
|
||||
if (OperationStatuses.TryGetValue(target, out var targetPathOperations))
|
||||
{
|
||||
var path = new AbsolutePath(element).Path;
|
||||
operation = targetPathOperations.Find(o => o.Key == path);
|
||||
}
|
||||
CurrentOperationProgress = operation;
|
||||
|
||||
await copyOperation.CopyAsync(new AbsolutePath(element), newElementPath, operation, new CopyCommandContext(UpdateProgress));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override Task<CanCommandRun> CanRun(PointInTime startPoint)
|
||||
{
|
||||
//TODO: implement
|
||||
return Task.FromResult(CanCommandRun.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace FileTime.Core.Command
|
||||
namespace FileTime.Core.Command.Copy
|
||||
{
|
||||
public class CopyCommandContext
|
||||
{
|
||||
44
src/Core/FileTime.Core/Command/Copy/CopyOperation.cs
Normal file
44
src/Core/FileTime.Core/Command/Copy/CopyOperation.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Core.Command.Copy
|
||||
{
|
||||
public class CopyOperation : ICopyOperation
|
||||
{
|
||||
private readonly Func<AbsolutePath, AbsolutePath, OperationProgress?, CopyCommandContext, Task> _copy;
|
||||
private readonly CopyCommand _copyCommand;
|
||||
|
||||
public CopyOperation(Func<AbsolutePath, AbsolutePath, OperationProgress?, CopyCommandContext, Task> copy, CopyCommand copyCommand)
|
||||
{
|
||||
_copy = copy;
|
||||
_copyCommand = copyCommand;
|
||||
}
|
||||
|
||||
public async Task CopyAsync(AbsolutePath from, AbsolutePath to, OperationProgress? operation, CopyCommandContext context)
|
||||
{
|
||||
await _copy(from, to, operation, context);
|
||||
if (operation != null)
|
||||
{
|
||||
operation.Progress = operation.TotalCount;
|
||||
}
|
||||
await _copyCommand.UpdateProgress();
|
||||
}
|
||||
|
||||
public async Task CreateContainerAsync(IContainer target, string name) => await target.CreateContainerAsync(name);
|
||||
|
||||
public async Task ContainerCopyDoneAsync(AbsolutePath path)
|
||||
{
|
||||
if (_copyCommand.OperationStatuses.ContainsKey(path))
|
||||
{
|
||||
foreach (var item in _copyCommand.OperationStatuses[path])
|
||||
{
|
||||
item.Progress = item.TotalCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (_copyCommand.TimeRunner != null)
|
||||
{
|
||||
await _copyCommand.TimeRunner.RefreshContainer.InvokeAsync(this, path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/Core/FileTime.Core/Command/Copy/ICopyOperation.cs
Normal file
11
src/Core/FileTime.Core/Command/Copy/ICopyOperation.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Core.Command.Copy
|
||||
{
|
||||
public interface ICopyOperation
|
||||
{
|
||||
Task ContainerCopyDoneAsync(AbsolutePath path);
|
||||
Task CopyAsync(AbsolutePath from, AbsolutePath to, OperationProgress? operation, CopyCommandContext context);
|
||||
Task CreateContainerAsync(IContainer target, string name);
|
||||
}
|
||||
}
|
||||
39
src/Core/FileTime.Core/Command/Copy/SimulateOperation.cs
Normal file
39
src/Core/FileTime.Core/Command/Copy/SimulateOperation.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command.Copy
|
||||
{
|
||||
public class SimulateOperation : ICopyOperation
|
||||
{
|
||||
private readonly List<Difference> _newDiffs;
|
||||
public IReadOnlyList<Difference> NewDiffs { get; }
|
||||
|
||||
public SimulateOperation()
|
||||
{
|
||||
_newDiffs = new List<Difference>();
|
||||
NewDiffs = _newDiffs.AsReadOnly();
|
||||
}
|
||||
public Task ContainerCopyDoneAsync(AbsolutePath path)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task CopyAsync(AbsolutePath from, AbsolutePath to, OperationProgress? operation, CopyCommandContext context)
|
||||
{
|
||||
_newDiffs.Add(new Difference(DifferenceActionType.Create, to));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task CreateContainerAsync(IContainer target, string name)
|
||||
{
|
||||
var newContainerDiff = new Difference(
|
||||
DifferenceActionType.Create,
|
||||
AbsolutePath.FromParentAndChildName(target, name, AbsolutePathType.Container)
|
||||
);
|
||||
|
||||
_newDiffs.Add(newContainerDiff);
|
||||
|
||||
return Task.FromResult((IContainer)null!);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,211 +0,0 @@
|
||||
using AsyncEvent;
|
||||
using FileTime.Core.Interactions;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command
|
||||
{
|
||||
public class CopyCommand : ITransportationCommand
|
||||
{
|
||||
private Func<AbsolutePath, AbsolutePath, OperationProgress?, CopyCommandContext, Task>? _copyOperation;
|
||||
private Dictionary<AbsolutePath, List<OperationProgress>> _operationStatuses = new();
|
||||
private Func<IContainer, string, Task<IContainer>>? _createContainer;
|
||||
private Func<AbsolutePath, Task>? _containerCopyDone;
|
||||
private OperationProgress? _currentOperationProgress;
|
||||
|
||||
public IList<AbsolutePath> Sources { get; } = new List<AbsolutePath>();
|
||||
|
||||
public AbsolutePath? Target { get; set; }
|
||||
|
||||
public TransportMode? TransportMode { get; set; } = Command.TransportMode.Merge;
|
||||
|
||||
public int Progress { get; private set; }
|
||||
public int CurrentProgress { get; private set; }
|
||||
|
||||
public AsyncEventHandler ProgressChanged { get; } = new();
|
||||
|
||||
public string DisplayLabel { get; } = "Copy";
|
||||
public IReadOnlyList<string> CanRunMessages { get; } = new List<string>().AsReadOnly();
|
||||
public bool TargetIsContainer => true;
|
||||
public List<InputElement> Inputs { get; } = new();
|
||||
public List<object>? InputResults { get; set; }
|
||||
|
||||
private async Task UpdateProgress()
|
||||
{
|
||||
var total = 0L;
|
||||
var current = 0L;
|
||||
|
||||
foreach (var folder in _operationStatuses.Values)
|
||||
{
|
||||
foreach (var item in folder)
|
||||
{
|
||||
current += item.Progress;
|
||||
total += item.TotalCount;
|
||||
}
|
||||
}
|
||||
|
||||
Progress = (int)(current * 100 / total);
|
||||
if (_currentOperationProgress == null)
|
||||
{
|
||||
CurrentProgress = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentProgress = (int)(_currentOperationProgress.Progress * 100 / _currentOperationProgress.TotalCount);
|
||||
}
|
||||
await ProgressChanged.InvokeAsync(this, AsyncEventArgs.Empty);
|
||||
}
|
||||
|
||||
public async Task<PointInTime> SimulateCommand(PointInTime startPoint)
|
||||
{
|
||||
if (Sources == null) throw new ArgumentException(nameof(Sources) + " can not be null");
|
||||
if (Target == null) throw new ArgumentException(nameof(Target) + " can not be null");
|
||||
if (TransportMode == null) throw new ArgumentException(nameof(TransportMode) + " can not be null");
|
||||
|
||||
var newDiffs = new List<Difference>();
|
||||
|
||||
_copyOperation = (_, to, _, _) =>
|
||||
{
|
||||
newDiffs.Add(new Difference(DifferenceActionType.Create, to));
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
_createContainer = (IContainer target, string name) =>
|
||||
{
|
||||
var newContainerDiff = new Difference(
|
||||
DifferenceActionType.Create,
|
||||
AbsolutePath.FromParentAndChildName(target, name, AbsolutePathType.Container)
|
||||
);
|
||||
|
||||
newDiffs.Add(newContainerDiff);
|
||||
|
||||
return Task.FromResult((IContainer)null!);
|
||||
};
|
||||
|
||||
await TraverseTree(Sources, Target, TransportMode.Value);
|
||||
|
||||
return startPoint.WithDifferences(newDiffs);
|
||||
}
|
||||
|
||||
public async Task Execute(Func<AbsolutePath, AbsolutePath, OperationProgress?, CopyCommandContext, Task> copy, TimeRunner timeRunner)
|
||||
{
|
||||
if (Sources == null) throw new ArgumentException(nameof(Sources) + " can not be null");
|
||||
if (Target == null) throw new ArgumentException(nameof(Target) + " can not be null");
|
||||
if (TransportMode == null) throw new ArgumentException(nameof(TransportMode) + " can not be null");
|
||||
|
||||
await CalculateProgress();
|
||||
|
||||
_copyOperation = async (from, to, operation, context) =>
|
||||
{
|
||||
await copy(from, to, operation, context);
|
||||
if (operation != null)
|
||||
{
|
||||
operation.Progress = operation.TotalCount;
|
||||
}
|
||||
await UpdateProgress();
|
||||
};
|
||||
|
||||
_createContainer = async (IContainer target, string name) => await target.CreateContainerAsync(name);
|
||||
_containerCopyDone = async (path) =>
|
||||
{
|
||||
foreach (var item in _operationStatuses[path])
|
||||
{
|
||||
item.Progress = item.TotalCount;
|
||||
}
|
||||
|
||||
if (timeRunner != null)
|
||||
{
|
||||
await timeRunner.RefreshContainer.InvokeAsync(this, path);
|
||||
}
|
||||
};
|
||||
|
||||
await TraverseTree(Sources, Target, TransportMode.Value);
|
||||
}
|
||||
|
||||
private async Task CalculateProgress()
|
||||
{
|
||||
if (Sources == null) throw new ArgumentException(nameof(Sources) + " can not be null");
|
||||
if (Target == null) throw new ArgumentException(nameof(Target) + " can not be null");
|
||||
if (TransportMode == null) throw new ArgumentException(nameof(TransportMode) + " can not be null");
|
||||
|
||||
var operationStatuses = new Dictionary<AbsolutePath, List<OperationProgress>>();
|
||||
|
||||
_copyOperation = async (from, to, _, _) =>
|
||||
{
|
||||
var parentPath = to.GetParent();
|
||||
List<OperationProgress> operationsByFolder;
|
||||
if (operationStatuses.ContainsKey(parentPath))
|
||||
{
|
||||
operationsByFolder = operationStatuses[parentPath];
|
||||
}
|
||||
else
|
||||
{
|
||||
var resolvedFrom = await from.ResolveAsync();
|
||||
operationsByFolder = new List<OperationProgress>();
|
||||
operationStatuses.Add(parentPath, operationsByFolder);
|
||||
operationsByFolder.Add(new OperationProgress(from.Path, resolvedFrom is IElement element ? await element.GetElementSize() : 0L));
|
||||
}
|
||||
};
|
||||
|
||||
await TraverseTree(Sources, Target, TransportMode.Value);
|
||||
_operationStatuses = operationStatuses;
|
||||
}
|
||||
|
||||
private async Task TraverseTree(
|
||||
IEnumerable<AbsolutePath> sources,
|
||||
AbsolutePath target,
|
||||
TransportMode transportMode)
|
||||
{
|
||||
if (_copyOperation == null) throw new ArgumentException("No copy operation were given.");
|
||||
if (_createContainer == null) throw new ArgumentException("No container creation function were given.");
|
||||
|
||||
var resolvedTarget = (IContainer?)await target.ResolveAsync();
|
||||
|
||||
foreach (var source in sources)
|
||||
{
|
||||
var item = await source.ResolveAsync();
|
||||
|
||||
if (item is IContainer container)
|
||||
{
|
||||
var targetContainer = target.GetChild(item.Name, AbsolutePathType.Container);
|
||||
if (_createContainer != null
|
||||
&& resolvedTarget != null
|
||||
&& !await resolvedTarget.IsExistsAsync(item.Name))
|
||||
{
|
||||
await _createContainer.Invoke(resolvedTarget, container.Name);
|
||||
}
|
||||
|
||||
var childDirectories = (await container.GetContainers())!.Select(d => new AbsolutePath(d));
|
||||
var childFiles = (await container.GetElements())!.Select(f => new AbsolutePath(f));
|
||||
|
||||
await TraverseTree(childDirectories.Concat(childFiles), targetContainer, transportMode);
|
||||
if (_containerCopyDone != null) await _containerCopyDone.Invoke(new AbsolutePath(container));
|
||||
}
|
||||
else if (item is IElement element)
|
||||
{
|
||||
var targetName = await Helper.CommandHelper.GetNewNameAsync(resolvedTarget, element.Name, transportMode);
|
||||
if (targetName == null) continue;
|
||||
|
||||
OperationProgress? operation = null;
|
||||
var targetFolderPath = new AbsolutePath(target);
|
||||
var targetElementPath = target.GetChild(targetName, AbsolutePathType.Element);
|
||||
|
||||
if (_operationStatuses.TryGetValue(targetFolderPath, out var targetPathOperations))
|
||||
{
|
||||
var path = new AbsolutePath(element).Path;
|
||||
operation = targetPathOperations.Find(o => o.Key == path);
|
||||
}
|
||||
_currentOperationProgress = operation;
|
||||
|
||||
if (_copyOperation != null) await _copyOperation.Invoke(new AbsolutePath(element), targetElementPath, operation, new CopyCommandContext(UpdateProgress));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Task<CanCommandRun> CanRun(PointInTime startPoint)
|
||||
{
|
||||
//TODO: implement
|
||||
return Task.FromResult(CanCommandRun.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ using AsyncEvent;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command
|
||||
namespace FileTime.Core.Command.CreateContainer
|
||||
{
|
||||
public class CreateContainerCommand : IExecutableCommand
|
||||
{
|
||||
@@ -16,7 +16,6 @@ namespace FileTime.Core.Command
|
||||
public string DisplayLabel { get; }
|
||||
public IReadOnlyList<string> CanRunMessages { get; } = new List<string>().AsReadOnly();
|
||||
|
||||
|
||||
public CreateContainerCommand(AbsolutePath container, string newContainerName)
|
||||
{
|
||||
Container = container;
|
||||
@@ -2,7 +2,7 @@ using AsyncEvent;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command
|
||||
namespace FileTime.Core.Command.CreateElement
|
||||
{
|
||||
public class CreateElementCommand : IExecutableCommand
|
||||
{
|
||||
@@ -2,7 +2,7 @@ using AsyncEvent;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command
|
||||
namespace FileTime.Core.Command.Delete
|
||||
{
|
||||
public class DeleteCommand : IExecutableCommand
|
||||
{
|
||||
@@ -64,6 +64,11 @@ namespace FileTime.Core.Command
|
||||
{
|
||||
await TraverseTree((await item.ResolveAsync())!);
|
||||
}
|
||||
|
||||
foreach(var updatedParent in ItemsToDelete.Select(i => i.GetParent()).Distinct())
|
||||
{
|
||||
await timeRunner.RefreshContainer.InvokeAsync(this, updatedParent);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task TraverseTree(IItem item)
|
||||
@@ -3,7 +3,7 @@ using FileTime.Core.Interactions;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command
|
||||
namespace FileTime.Core.Command.Move
|
||||
{
|
||||
public class MoveCommand : ITransportationCommand
|
||||
{
|
||||
@@ -2,7 +2,7 @@ using AsyncEvent;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command
|
||||
namespace FileTime.Core.Command.Rename
|
||||
{
|
||||
public class RenameCommand : IExecutableCommand
|
||||
{
|
||||
@@ -27,7 +27,7 @@ namespace FileTime.Core.Command
|
||||
if (itemToRename != null)
|
||||
{
|
||||
await itemToRename.Rename(Target);
|
||||
if (timeRunner.RefreshContainer != null) await timeRunner.RefreshContainer.InvokeAsync(this, new AbsolutePath(itemToRename.GetParent()!));
|
||||
await timeRunner.RefreshContainer.InvokeAsync(this, new AbsolutePath(itemToRename.GetParent()!));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using FileTime.Core.Command;
|
||||
using FileTime.Core.Command.Copy;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
|
||||
@@ -61,6 +61,10 @@ namespace FileTime.Core.Components
|
||||
{
|
||||
if (_currentlySelecting) return false;
|
||||
|
||||
try
|
||||
{
|
||||
_currentlySelecting = true;
|
||||
|
||||
IItem? itemToSelect = null;
|
||||
if (value != null)
|
||||
{
|
||||
@@ -98,6 +102,11 @@ namespace FileTime.Core.Components
|
||||
|
||||
return !newToken.IsCancellationRequested;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_currentlySelecting = false;
|
||||
}
|
||||
}
|
||||
public async Task<IItem?> GetItemByLastPath(IContainer? container = null)
|
||||
{
|
||||
container ??= _currentLocation;
|
||||
@@ -211,6 +220,9 @@ namespace FileTime.Core.Components
|
||||
{
|
||||
if (token.IsCancellationRequested) return;
|
||||
|
||||
IItem? newSelectedItem = null;
|
||||
try
|
||||
{
|
||||
_currentlySelecting = true;
|
||||
if (AutoRefresh && currentLocation != null)
|
||||
{
|
||||
@@ -218,7 +230,6 @@ namespace FileTime.Core.Components
|
||||
if (token.IsCancellationRequested) return;
|
||||
}
|
||||
|
||||
IItem? newSelectedItem = null;
|
||||
foreach (var item in currentPossibleItems)
|
||||
{
|
||||
if (currentLocationItems.FirstOrDefault(i => i.Name == item.Name) is var possibleNewSelectedItem
|
||||
@@ -233,8 +244,11 @@ namespace FileTime.Core.Components
|
||||
{
|
||||
newSelectedItem = (await (await GetCurrentLocation(token)).GetItems(token))?.FirstOrDefault(i => i.Name == newSelectedItem.Name);
|
||||
}
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
_currentlySelecting = false;
|
||||
}
|
||||
await SetCurrentSelectedItem(newSelectedItem ?? (currentLocationItems.Count > 0 ? currentLocationItems[0] : null), token: token);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace FileTime.Core.Models
|
||||
Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default);
|
||||
|
||||
Task RefreshAsync(CancellationToken token = default);
|
||||
async Task<IItem?> GetByPath(string path, bool acceptDeepestMatch = false)
|
||||
public async Task<IItem?> GetByPath(string path, bool acceptDeepestMatch = false)
|
||||
{
|
||||
if (path == null) return this;
|
||||
var paths = path.Split(Constants.SeparatorChar);
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace FileTime.Core.Models
|
||||
string? NativePath { get; }
|
||||
bool IsHidden { get; }
|
||||
bool IsDestroyed { get; }
|
||||
bool IsExists { get; }
|
||||
SupportsDelete CanDelete { get; }
|
||||
bool CanRename { get; }
|
||||
IContentProvider Provider { get; }
|
||||
|
||||
@@ -37,6 +37,7 @@ namespace FileTime.Core.Models
|
||||
public AsyncEventHandler Refreshed { get; }
|
||||
|
||||
public bool IsDestroyed => BaseContainer.IsDestroyed;
|
||||
public bool IsExists => BaseContainer.IsExists;
|
||||
|
||||
private void RefreshAddBase(Func<object?, AsyncEventArgs, CancellationToken, Task> handler)
|
||||
{
|
||||
|
||||
@@ -37,12 +37,14 @@ namespace FileTime.Core.Providers
|
||||
|
||||
IContentProvider IItem.Provider => Provider;
|
||||
|
||||
public abstract bool IsExists { get; }
|
||||
|
||||
protected AbstractContainer(TProvider provider, IContainer parent, string name)
|
||||
{
|
||||
_parent = parent;
|
||||
Provider = provider;
|
||||
Name = name;
|
||||
FullName = (parent?.FullName ?? Name) + Constants.SeparatorChar + Name;
|
||||
FullName = parent.FullName == null ? Name : parent.FullName + Constants.SeparatorChar + Name;
|
||||
Exceptions = _exceptions.AsReadOnly();
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace FileTime.Core.Providers
|
||||
public bool SupportsDirectoryLevelSoftDelete => false;
|
||||
|
||||
public bool IsDestroyed => false;
|
||||
public bool IsExists => true;
|
||||
|
||||
public TopContainer(IEnumerable<IContentProvider> contentProviders)
|
||||
{
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace FileTime.Core.Timeline
|
||||
|
||||
//FIXME: currently this can be different of the real items NativePath, should be fixed
|
||||
public string? NativePath => FullName;
|
||||
public bool IsExists => true;
|
||||
|
||||
public TimeContainer(string name, IContainer parent, IContentProvider contentProvider, IContentProvider virtualContentProvider, PointInTime pointInTime)
|
||||
{
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace FileTime.Core.Timeline
|
||||
public IContentProvider VirtualProvider { get; }
|
||||
|
||||
public bool IsDestroyed { get; private set; }
|
||||
public bool IsExists => true;
|
||||
|
||||
public Task Delete(bool hardDelete = false) => Task.CompletedTask;
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ namespace FileTime.Core.Timeline
|
||||
public bool SupportsContentStreams => false;
|
||||
|
||||
public string Protocol => "time2://";
|
||||
public bool IsExists => true;
|
||||
|
||||
public TimeProvider(PointInTime pointInTime)
|
||||
{
|
||||
|
||||
@@ -24,8 +24,8 @@ namespace FileTime.Avalonia
|
||||
.BuildServiceProvider()
|
||||
.InitSerilog();
|
||||
|
||||
var _logger = ServiceProvider.GetService<ILogger<App>>();
|
||||
_logger?.LogInformation("App initialization completed.");
|
||||
var logger = ServiceProvider.GetService<ILogger<App>>();
|
||||
logger?.LogInformation("App initialization completed.");
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
|
||||
@@ -11,6 +11,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using FileTime.App.Core.Tab;
|
||||
using System.Threading;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Avalonia.Application
|
||||
{
|
||||
@@ -18,6 +19,7 @@ namespace FileTime.Avalonia.Application
|
||||
[Inject(typeof(ItemNameConverterService))]
|
||||
[Inject(typeof(LocalContentProvider))]
|
||||
[Inject(typeof(Tab))]
|
||||
[Inject(typeof(TimeRunner), propertyName: "_timeRunner")]
|
||||
public partial class TabContainer : INewItemProcessor
|
||||
{
|
||||
private bool _updateFromCode;
|
||||
@@ -77,6 +79,21 @@ namespace FileTime.Avalonia.Application
|
||||
partial void OnInitialize()
|
||||
{
|
||||
_tabState = new TabState(Tab);
|
||||
_timeRunner.RefreshContainer.Add(TimeRunnerContainerRefreshed);
|
||||
|
||||
}
|
||||
|
||||
private async Task TimeRunnerContainerRefreshed(object? sender, AbsolutePath container, CancellationToken token = default)
|
||||
{
|
||||
var currentLocation = await Tab.GetCurrentLocation();
|
||||
if (currentLocation != null)
|
||||
{
|
||||
var currentLocationPath = new AbsolutePath(currentLocation);
|
||||
if (currentLocationPath == container)
|
||||
{
|
||||
await currentLocation.RefreshAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Init(int tabNumber)
|
||||
|
||||
@@ -12,6 +12,12 @@ using FileTime.Avalonia.Misc;
|
||||
using FileTime.Avalonia.Models;
|
||||
using FileTime.Avalonia.ViewModels;
|
||||
using FileTime.Core.Command;
|
||||
using FileTime.Core.Command.Copy;
|
||||
using FileTime.Core.Command.CreateContainer;
|
||||
using FileTime.Core.Command.CreateElement;
|
||||
using FileTime.Core.Command.Delete;
|
||||
using FileTime.Core.Command.Move;
|
||||
using FileTime.Core.Command.Rename;
|
||||
using FileTime.Core.Components;
|
||||
using FileTime.Core.Interactions;
|
||||
using FileTime.Core.Models;
|
||||
@@ -229,7 +235,7 @@ namespace FileTime.Avalonia.Services
|
||||
var newTab = new Tab();
|
||||
await newTab.Init(newContainer);
|
||||
|
||||
tabContainer = new TabContainer(newTab, _localContentProvider, _itemNameConverterService);
|
||||
tabContainer = new TabContainer(_timeRunner, newTab, _localContentProvider, _itemNameConverterService);
|
||||
await tabContainer.Init(number);
|
||||
|
||||
var i = 0;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
@@ -13,6 +11,7 @@ using FileTime.Core.Providers;
|
||||
using FileTime.Providers.Local;
|
||||
using FileTime.Core.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Avalonia.Services
|
||||
{
|
||||
@@ -25,13 +24,15 @@ namespace FileTime.Avalonia.Services
|
||||
private readonly IEnumerable<IContentProvider> _contentProviders;
|
||||
private readonly LocalContentProvider _localContentProvider;
|
||||
private readonly ILogger<StatePersistenceService> _logger;
|
||||
private readonly TimeRunner _timeRunner;
|
||||
|
||||
public StatePersistenceService(
|
||||
AppState appState,
|
||||
ItemNameConverterService itemNameConverterService,
|
||||
IEnumerable<IContentProvider> contentProviders,
|
||||
LocalContentProvider localContentProvider,
|
||||
ILogger<StatePersistenceService> logger)
|
||||
ILogger<StatePersistenceService> logger,
|
||||
TimeRunner timeRunner)
|
||||
{
|
||||
_appState = appState;
|
||||
_itemNameConverterService = itemNameConverterService;
|
||||
@@ -45,6 +46,7 @@ namespace FileTime.Avalonia.Services
|
||||
PropertyNameCaseInsensitive = true,
|
||||
WriteIndented = true
|
||||
};
|
||||
this._timeRunner = timeRunner;
|
||||
}
|
||||
|
||||
public async Task LoadStatesAsync()
|
||||
@@ -151,7 +153,7 @@ namespace FileTime.Avalonia.Services
|
||||
}
|
||||
}
|
||||
|
||||
var newTabContainer = new TabContainer(newTab, _localContentProvider, _itemNameConverterService);
|
||||
var newTabContainer = new TabContainer(_timeRunner, newTab, _localContentProvider, _itemNameConverterService);
|
||||
await newTabContainer.Init(tab.Number);
|
||||
_appState.Tabs.Add(newTabContainer);
|
||||
}
|
||||
|
||||
@@ -154,10 +154,10 @@ namespace FileTime.Avalonia.ViewModels
|
||||
{
|
||||
_isRefreshing = true;
|
||||
|
||||
List<ContainerViewModel> newContainers = new List<ContainerViewModel>();
|
||||
List<ElementViewModel> newElements = new List<ElementViewModel>();
|
||||
List<ContainerViewModel> newContainers = new();
|
||||
List<ElementViewModel> newElements = new();
|
||||
|
||||
if (await _container.GetContainers() is IReadOnlyList<IContainer> containers)
|
||||
if (await _container.GetContainers(token) is IReadOnlyList<IContainer> containers)
|
||||
{
|
||||
foreach (var container in containers)
|
||||
{
|
||||
@@ -165,7 +165,7 @@ namespace FileTime.Avalonia.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
if (await _container.GetElements() is IReadOnlyList<IElement> elements)
|
||||
if (await _container.GetElements(token) is IReadOnlyList<IElement> elements)
|
||||
{
|
||||
foreach (var element in elements)
|
||||
{
|
||||
@@ -216,7 +216,7 @@ namespace FileTime.Avalonia.ViewModels
|
||||
_exceptions.Add(e);
|
||||
}
|
||||
|
||||
await _newItemProcessor.UpdateMarkedItems(this);
|
||||
await _newItemProcessor.UpdateMarkedItems(this, CancellationToken.None);
|
||||
|
||||
_isRefreshing = false;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace FileTime.Avalonia.ViewModels
|
||||
var tab = new Tab();
|
||||
await tab.Init(LocalContentProvider);
|
||||
|
||||
var tabContainer = new TabContainer(tab, LocalContentProvider, ItemNameConverterService);
|
||||
var tabContainer = new TabContainer(_timeRunner, tab, LocalContentProvider, ItemNameConverterService);
|
||||
await tabContainer.Init(1);
|
||||
tabContainer.IsSelected = true;
|
||||
AppState.Tabs.Add(tabContainer);
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace FileTime.Avalonia.Views
|
||||
|
||||
private void InputText_AttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
if (sender is TextBox inputText && inputText.DataContext is InputElementWrapper inputElementWrapper && inputElementWrapper == ViewModel!.AppState.Inputs.First())
|
||||
if (sender is TextBox inputText && inputText.IsVisible && inputText.DataContext is InputElementWrapper inputElementWrapper && inputElementWrapper == ViewModel!.AppState.Inputs[0])
|
||||
{
|
||||
inputText.Focus();
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace FileTime.Providers.Local
|
||||
|
||||
public bool IsDestroyed => false;
|
||||
public bool SupportsContentStreams => true;
|
||||
public bool IsExists => true;
|
||||
|
||||
public LocalContentProvider(ILogger<LocalContentProvider> logger)
|
||||
{
|
||||
@@ -49,8 +50,6 @@ namespace FileTime.Providers.Local
|
||||
? new DirectoryInfo("/").GetDirectories()
|
||||
: Environment.GetLogicalDrives().Select(d => new DirectoryInfo(d));
|
||||
|
||||
FullName = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "" : null;
|
||||
|
||||
_rootContainers = rootDirectories.Select(d => new LocalFolder(d, this, this)).OrderBy(d => d.Name).ToList().AsReadOnly();
|
||||
_items = _rootContainers.Cast<IItem>().ToList().AsReadOnly();
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace FileTime.Providers.Local
|
||||
|
||||
public string FullName { get; }
|
||||
public string? NativePath => File.FullName;
|
||||
public bool IsExists => File.Exists;
|
||||
|
||||
public IContentProvider Provider { get; }
|
||||
|
||||
|
||||
@@ -5,13 +5,14 @@ using FileTime.Providers.Local.Interop;
|
||||
|
||||
namespace FileTime.Providers.Local
|
||||
{
|
||||
public class LocalFolder : AbstractContainer<LocalContentProvider>
|
||||
public class LocalFolder : AbstractContainer<LocalContentProvider>, IContainer
|
||||
{
|
||||
public DirectoryInfo Directory { get; }
|
||||
|
||||
public string Attributes => GetAttributes();
|
||||
|
||||
public DateTime CreatedAt => Directory.CreationTime;
|
||||
public override bool IsExists => Directory.Exists;
|
||||
|
||||
public LocalFolder(DirectoryInfo directory, LocalContentProvider contentProvider, IContainer parent)
|
||||
: base(contentProvider, parent, directory.Name.TrimEnd(Path.DirectorySeparatorChar))
|
||||
@@ -52,7 +53,7 @@ namespace FileTime.Providers.Local
|
||||
return Task.FromResult(Enumerable.Empty<IItem>());
|
||||
}
|
||||
|
||||
public async Task<IItem?> GetByPath(string path, bool acceptDeepestMatch = false)
|
||||
async Task<IItem?> IContainer.GetByPath(string path, bool acceptDeepestMatch)
|
||||
{
|
||||
var paths = path.Split(Constants.SeparatorChar);
|
||||
|
||||
@@ -87,7 +88,7 @@ namespace FileTime.Providers.Local
|
||||
return (await GetElements())!.FirstOrDefault(e => Provider.NormalizePath(e.Name) == Provider.NormalizePath(name))!;
|
||||
}
|
||||
|
||||
public override async Task<bool> IsExistsAsync(string name) => (await GetItems())?.Any(i => Provider.NormalizePath(i.Name) == Provider.NormalizePath(name)) ?? false;
|
||||
public override async Task<bool> IsExistsAsync(string name) => (await GetItems())?.Any(i => i.IsExists && Provider.NormalizePath(i.Name) == Provider.NormalizePath(name)) ?? false;
|
||||
|
||||
public override Task Delete(bool hardDelete = false)
|
||||
{
|
||||
|
||||
@@ -43,6 +43,7 @@ namespace FileTime.Providers.Sftp
|
||||
public IContentProvider Provider => this;
|
||||
|
||||
public string Protocol => "sftp://";
|
||||
public bool IsExists => true;
|
||||
|
||||
public SftpContentProvider(IInputInterface inputInterface, ILogger<SftpContentProvider> logger)
|
||||
{
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace FileTime.Providers.Sftp
|
||||
|
||||
public IContentProvider Provider => throw new NotImplementedException();
|
||||
|
||||
public bool IsExists => throw new NotImplementedException();
|
||||
|
||||
public Task Delete(bool hardDelete = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace FileTime.Providers.Sftp
|
||||
public class SftpFolder : AbstractContainer<SftpContentProvider>
|
||||
{
|
||||
private readonly SftpServer _server;
|
||||
public override bool IsExists => true;
|
||||
|
||||
public SftpFolder(SftpContentProvider provider, SftpServer server, IContainer parent, string path) : base(provider, parent, path)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace FileTime.Providers.Sftp
|
||||
|
||||
public string? Username { get; private set; }
|
||||
public string? Password { get; private set; }
|
||||
public override bool IsExists => true;
|
||||
|
||||
public SftpServer(string name, SftpContentProvider sftpContentProvider, IInputInterface inputInterface, string? username = null, string? password = null)
|
||||
: base(sftpContentProvider, sftpContentProvider, name)
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace FileTime.Providers.Smb
|
||||
|
||||
public bool IsDestroyed => false;
|
||||
public bool SupportsContentStreams => true;
|
||||
public bool IsExists => true;
|
||||
|
||||
public SmbContentProvider(IInputInterface inputInterface, Persistence.PersistenceService persistenceService, ILogger<SmbContentProvider> logger)
|
||||
{
|
||||
|
||||
@@ -24,6 +24,8 @@ namespace FileTime.Providers.Smb
|
||||
public IContentProvider Provider { get; }
|
||||
|
||||
public bool IsDestroyed { get; private set; }
|
||||
//TODO: implement
|
||||
public bool IsExists => true;
|
||||
|
||||
public SmbFile(string name, SmbContentProvider provider, SmbShare smbShare, IContainer parent, SmbClientContext smbClientContext)
|
||||
{
|
||||
|
||||
@@ -8,8 +8,9 @@ namespace FileTime.Providers.Smb
|
||||
{
|
||||
private readonly SmbClientContext _smbClientContext;
|
||||
|
||||
|
||||
public SmbShare SmbShare { get; }
|
||||
//TODO: implement
|
||||
public override bool IsExists => true;
|
||||
|
||||
public SmbFolder(string name, SmbContentProvider contentProvider, SmbShare smbShare, IContainer parent, SmbClientContext smbClientContext)
|
||||
: base(contentProvider, parent, name)
|
||||
|
||||
@@ -8,7 +8,7 @@ using SMBLibrary.Client;
|
||||
|
||||
namespace FileTime.Providers.Smb
|
||||
{
|
||||
public class SmbServer : AbstractContainer<SmbContentProvider>
|
||||
public class SmbServer : AbstractContainer<SmbContentProvider>, IContainer
|
||||
{
|
||||
internal const int MAXRETRIES = 5;
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace FileTime.Providers.Smb
|
||||
|
||||
public string? Username { get; private set; }
|
||||
public string? Password { get; private set; }
|
||||
public override bool IsExists => true;
|
||||
|
||||
public SmbServer(string name, SmbContentProvider contentProvider, IInputInterface inputInterface, string? username = null, string? password = null)
|
||||
: base(contentProvider, contentProvider, name)
|
||||
@@ -52,7 +53,7 @@ namespace FileTime.Providers.Smb
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<IItem?> GetByPath(string path, bool acceptDeepestMatch = false)
|
||||
async Task<IItem?> IContainer.GetByPath(string path, bool acceptDeepestMatch)
|
||||
{
|
||||
var paths = path.Split(Constants.SeparatorChar);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace FileTime.Providers.Smb
|
||||
public class SmbShare : AbstractContainer<SmbContentProvider>
|
||||
{
|
||||
private readonly SmbClientContext _smbClientContext;
|
||||
public override bool IsExists => true;
|
||||
|
||||
public SmbShare(string name, SmbContentProvider contentProvider, IContainer parent, SmbClientContext smbClientContext)
|
||||
: base(contentProvider, parent, name)
|
||||
|
||||
Reference in New Issue
Block a user