Async core refactor

This commit is contained in:
2022-01-20 18:16:01 +01:00
parent 016100a565
commit 215503a4e3
33 changed files with 761 additions and 463 deletions

View File

@@ -16,38 +16,39 @@ namespace FileTime.Core.Command
throw new NotImplementedException();
}
public void Execute(Action<IAbsolutePath, IAbsolutePath> copy)
public async Task Execute(Action<IAbsolutePath, IAbsolutePath> copy)
{
DoCopy(Sources, Target, TransportMode, copy);
await DoCopy(Sources, Target, TransportMode, copy);
}
private void DoCopy(IEnumerable<IAbsolutePath> sources, IContainer target, TransportMode transportMode, Action<IAbsolutePath, IAbsolutePath> copy)
private async Task DoCopy(IEnumerable<IAbsolutePath> sources, IContainer target, TransportMode transportMode, Action<IAbsolutePath, IAbsolutePath> copy)
{
foreach (var source in sources)
{
var item = source.ContentProvider.GetByPath(source.Path);
var item = await source.ContentProvider.GetByPath(source.Path);
if (item is IContainer container)
{
var targetContainer = target.Containers.FirstOrDefault(d => d.Name == container.Name) ?? (target.CreateContainer(container.Name)!);
var targetContainer = (await target.GetContainers())?.FirstOrDefault(d => d.Name == container.Name) ?? (await target.CreateContainer(container.Name)!);
var childDirectories = container.Containers.Select(d => new AbsolutePath(item.Provider, d.FullName!));
var childFiles = container.Elements.Select(f => new AbsolutePath(item.Provider, f.FullName!));
var childDirectories = (await container.GetContainers())!.Select(d => new AbsolutePath(item.Provider, d.FullName!));
var childFiles = (await container.GetElements())!.Select(f => new AbsolutePath(item.Provider, f.FullName!));
DoCopy(childDirectories.Concat(childFiles), targetContainer, transportMode, copy);
await DoCopy(childDirectories.Concat(childFiles), targetContainer, transportMode, copy);
}
else if (item is IElement element)
{
var targetName = element.Name;
var targetNameExists = await target.IsExists(targetName);
if (transportMode == TransportMode.Merge)
{
for (var i = 0; target.IsExists(targetName); i++)
for (var i = 0; targetNameExists; i++)
{
targetName = element.Name + (i == 0 ? "_" : $"_{i}");
}
}
else if (transportMode == TransportMode.Skip && target.IsExists(targetName))
else if (transportMode == TransportMode.Skip && targetNameExists)
{
continue;
}

View File

@@ -12,29 +12,29 @@ namespace FileTime.Core.Command
throw new NotImplementedException();
}
public void Execute()
public async Task Execute()
{
foreach (var item in ItemsToDelete)
{
DoDelete(item.ContentProvider.GetByPath(item.Path)!);
await DoDelete(await item.ContentProvider.GetByPath(item.Path)!);
}
}
private void DoDelete(IItem item)
private async Task DoDelete(IItem item)
{
if (item is IContainer container)
{
foreach (var child in container.Items)
foreach (var child in await container.GetItems())
{
DoDelete(child);
child.Delete();
await DoDelete(child);
await child.Delete();
}
item.Delete();
await item.Delete();
}
else if(item is IElement element)
{
element.Delete();
await element.Delete();
}
}
}

View File

@@ -2,6 +2,6 @@ namespace FileTime.Core.Command
{
public interface IExecutableCommand : ICommand
{
void Execute();
Task Execute();
}
}

View File

@@ -1,3 +1,4 @@
using AsyncEvent;
using FileTime.Core.Models;
namespace FileTime.Core.Components
@@ -7,7 +8,7 @@ namespace FileTime.Core.Components
private IItem? _currentSelectedItem;
private IContainer _currentLocation;
public IContainer CurrentLocation
/* public IContainer CurrentLocation
{
get => _currentLocation;
private set
@@ -38,75 +39,122 @@ namespace FileTime.Core.Components
CurrentSelectedItemChanged?.Invoke(this, EventArgs.Empty);
}
}
}
} */
public int CurrentSelectedIndex { get; private set; }
public event EventHandler CurrentLocationChanged;
public event EventHandler CurrentSelectedItemChanged;
public Tab(IContainer currentPath)
public async Task Init(IContainer currentPath)
{
CurrentLocation = currentPath;
CurrentSelectedItem = CurrentLocation.Items.Count > 0 ? CurrentLocation.Items[0] : null;
await SetCurrentLocation(currentPath);
}
private void HandleCurrentLocationRefresh(object? sender, EventArgs e)
public Task<IContainer> GetCurrentLocation()
{
var currentSelectedName = CurrentSelectedItem?.FullName;
return Task.FromResult(_currentLocation);
}
public async Task SetCurrentLocation(IContainer value)
{
if (_currentLocation != value)
{
if (_currentLocation != null)
{
_currentLocation.Refreshed.Remove(HandleCurrentLocationRefresh);
}
_currentLocation = value;
CurrentLocationChanged?.Invoke(this, EventArgs.Empty);
var currentLocationItems = (await (await GetCurrentLocation()).GetItems())!;
await SetCurrentSelectedItem(currentLocationItems.Count > 0 ? currentLocationItems[0] : null);
_currentLocation.Refreshed.Add(HandleCurrentLocationRefresh);
}
}
public Task<IItem?> GetCurrentSelectedItem()
{
return Task.FromResult(_currentSelectedItem);
}
public async Task SetCurrentSelectedItem(IItem? value)
{
if (_currentSelectedItem != value)
{
var contains = (await _currentLocation.GetItems())?.Contains(value) ?? false;
if(value != null && !contains) throw new IndexOutOfRangeException("Provided item does not exists in the current container.");
_currentSelectedItem = value;
CurrentSelectedIndex = await GetItemIndex(value);
CurrentSelectedItemChanged?.Invoke(this, EventArgs.Empty);
}
}
private async Task HandleCurrentLocationRefresh(object? sender, AsyncEventArgs e)
{
var currentSelectedName = (await GetCurrentSelectedItem())?.FullName;
var currentLocationItems = (await (await GetCurrentLocation()).GetItems())!;
if (currentSelectedName != null)
{
CurrentSelectedItem = CurrentLocation.Items.FirstOrDefault(i => i.FullName == currentSelectedName) ?? _currentLocation.Items.FirstOrDefault();
await SetCurrentSelectedItem(currentLocationItems.FirstOrDefault(i => i.FullName == currentSelectedName) ?? currentLocationItems.FirstOrDefault());
}
else if (CurrentLocation.Items.Count > 0)
else if (currentLocationItems.Count > 0)
{
CurrentSelectedItem = CurrentLocation.Items[0];
await SetCurrentSelectedItem(currentLocationItems[0]);
}
}
public void SelectFirstItem()
public async Task SelectFirstItem()
{
if (CurrentLocation.Items.Count > 0)
var currentLocationItems = (await (await GetCurrentLocation()).GetItems())!;
if (currentLocationItems.Count > 0)
{
CurrentSelectedItem = CurrentLocation.Items[0];
await SetCurrentSelectedItem(currentLocationItems[0]);
}
}
public void SelectLastItem()
public async Task SelectLastItem()
{
if (CurrentLocation.Items.Count > 0)
var currentLocationItems = (await (await GetCurrentLocation()).GetItems())!;
if (currentLocationItems.Count > 0)
{
CurrentSelectedItem = CurrentLocation.Items[CurrentLocation.Items.Count - 1];
await SetCurrentSelectedItem(currentLocationItems[currentLocationItems.Count - 1]);
}
}
public void SelectPreviousItem(int skip = 0)
public async Task SelectPreviousItem(int skip = 0)
{
var possibleItemsToSelect = CurrentLocation.Items.Take(CurrentSelectedIndex).Reverse().Skip(skip).ToList();
var currentLocationItems = (await (await GetCurrentLocation()).GetItems())!;
var possibleItemsToSelect = currentLocationItems.Take(CurrentSelectedIndex).Reverse().Skip(skip).ToList();
if (possibleItemsToSelect.Count == 0) possibleItemsToSelect = CurrentLocation.Items.ToList();
SelectItem(possibleItemsToSelect);
if (possibleItemsToSelect.Count == 0) possibleItemsToSelect = currentLocationItems.ToList();
await SelectItem(possibleItemsToSelect);
}
public void SelectNextItem(int skip = 0)
public async Task SelectNextItem(int skip = 0)
{
var possibleItemsToSelect = CurrentLocation.Items.Skip(CurrentSelectedIndex + 1 + skip).ToList();
var currentLocationItems = (await (await GetCurrentLocation()).GetItems())!;
var possibleItemsToSelect = currentLocationItems.Skip(CurrentSelectedIndex + 1 + skip).ToList();
if (possibleItemsToSelect.Count == 0) possibleItemsToSelect = CurrentLocation.Items.Reverse().ToList();
SelectItem(possibleItemsToSelect);
if (possibleItemsToSelect.Count == 0) possibleItemsToSelect = currentLocationItems.Reverse().ToList();
await SelectItem(possibleItemsToSelect);
}
private void SelectItem(IEnumerable<IItem> currentPossibleItems)
private async Task SelectItem(IEnumerable<IItem> currentPossibleItems)
{
if (!currentPossibleItems.Any()) return;
if (CurrentSelectedItem != null)
var currentLocationItems = (await (await GetCurrentLocation()).GetItems())!;
if (await GetCurrentSelectedItem() != null)
{
CurrentLocation.Refresh();
(await GetCurrentLocation())?.Refresh();
IItem? newSelectedItem = null;
foreach (var item in currentPossibleItems)
{
if (CurrentLocation.Items.FirstOrDefault(i => i.Name == item.Name) is var possibleNewSelectedItem
if (currentLocationItems.FirstOrDefault(i => i.Name == item.Name) is var possibleNewSelectedItem
&& possibleNewSelectedItem is not null)
{
newSelectedItem = possibleNewSelectedItem;
@@ -114,78 +162,89 @@ namespace FileTime.Core.Components
}
}
CurrentSelectedItem = newSelectedItem ?? (CurrentLocation.Items.Count > 0 ? CurrentLocation.Items[0] : null);
if(newSelectedItem != null)
{
newSelectedItem = (await (await GetCurrentLocation()).GetItems())?.FirstOrDefault(i => i.Name == newSelectedItem.Name);
}
await SetCurrentSelectedItem(newSelectedItem ?? (currentLocationItems.Count > 0 ? currentLocationItems[0] : null));
}
else
{
CurrentSelectedItem = CurrentLocation.Items.Count > 0 ? CurrentLocation.Items[0] : null;
await SetCurrentSelectedItem(currentLocationItems.Count > 0 ? currentLocationItems[0] : null);
}
}
public void GoToProvider()
public async Task GoToProvider()
{
if (CurrentLocation == null) return;
var currentLocatin = await GetCurrentLocation();
if (currentLocatin == null) return;
CurrentLocation = CurrentLocation.Provider;
await SetCurrentLocation(currentLocatin.Provider);
}
public void GoToRoot()
public async Task GoToRoot()
{
if (CurrentLocation == null) return;
var currentLocatin = await GetCurrentLocation();
if (currentLocatin == null) return;
var root = CurrentLocation;
var root = currentLocatin;
while (root!.GetParent() != null)
{
root = root.GetParent();
}
CurrentLocation = root;
await SetCurrentLocation(root);
}
public void GoUp()
public async Task GoUp()
{
var lastCurrentLocation = CurrentLocation;
var parent = CurrentLocation.GetParent();
var currentLocationItems = (await (await GetCurrentLocation()).GetItems())!;
var lastCurrentLocation = await GetCurrentLocation();
var parent = (await GetCurrentLocation()).GetParent();
if (parent is not null)
{
if (lastCurrentLocation is VirtualContainer lastCurrentVirtualContainer)
{
CurrentLocation = lastCurrentVirtualContainer.CloneVirtualChainFor(parent, v => v.IsPermanent);
CurrentSelectedItem = lastCurrentVirtualContainer.GetRealContainer();
await SetCurrentLocation(lastCurrentVirtualContainer.CloneVirtualChainFor(parent, v => v.IsPermanent));
await SetCurrentSelectedItem(lastCurrentVirtualContainer.GetRealContainer());
}
else
{
CurrentLocation = parent;
CurrentSelectedItem = lastCurrentLocation;
await SetCurrentLocation(parent);
var newCurrentLocation = (await (await GetCurrentLocation()).GetItems())?.FirstOrDefault(i => i.Name == lastCurrentLocation.Name);
await SetCurrentSelectedItem(newCurrentLocation);
}
}
}
public void Open()
public async Task Open()
{
var currentLocationItems = (await (await GetCurrentLocation()).GetItems())!;
if (_currentSelectedItem is IContainer childContainer)
{
if (CurrentLocation is VirtualContainer currentVirtuakContainer)
if (await GetCurrentLocation() is VirtualContainer currentVirtuakContainer)
{
CurrentLocation = currentVirtuakContainer.CloneVirtualChainFor(childContainer, v => v.IsPermanent);
await SetCurrentLocation(currentVirtuakContainer.CloneVirtualChainFor(childContainer, v => v.IsPermanent));
}
else
{
CurrentLocation = childContainer;
await SetCurrentLocation(childContainer);
}
}
}
public void OpenContainer(IContainer container) => CurrentLocation = container;
public async Task OpenContainer(IContainer container) => await SetCurrentLocation(container);
private int GetItemIndex(IItem? item)
private async Task<int> GetItemIndex(IItem? item)
{
if (item == null) return -1;
var currentLocationItems = (await (await GetCurrentLocation()).GetItems())!;
for (var i = 0; i < CurrentLocation.Items.Count; i++)
for (var i = 0; i < currentLocationItems.Count; i++)
{
if (CurrentLocation.Items[i] == item) return i;
if (currentLocationItems[i] == item) return i;
}
return -1;

View File

@@ -2,6 +2,7 @@
<ItemGroup>
<ProjectReference Include="..\..\AppCommon\FileTime.App.Style\FileTime.App.Style.csproj" />
<ProjectReference Include="..\AsyncEvent\AsyncEvent.csproj" />
</ItemGroup>
<PropertyGroup>

View File

@@ -2,6 +2,6 @@ namespace FileTime.Core.Interactions
{
public interface IInputInterface
{
string?[] ReadInputs(IEnumerable<InputElement> fields);
Task<string?[]> ReadInputs(IEnumerable<InputElement> fields);
}
}

View File

@@ -1,19 +1,21 @@
using AsyncEvent;
namespace FileTime.Core.Models
{
public interface IContainer : IItem
{
IReadOnlyList<IItem> Items { get; }
IReadOnlyList<IContainer> Containers { get; }
IReadOnlyList<IElement> Elements { get; }
Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default);
Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default);
Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default);
void Refresh();
Task Refresh();
IContainer? GetParent();
IItem? GetByPath(string path);
IContainer CreateContainer(string name);
IElement CreateElement(string name);
Task<IItem?> GetByPath(string path);
Task<IContainer> CreateContainer(string name);
Task<IElement> CreateElement(string name);
bool IsExists(string name);
Task<bool> IsExists(string name);
event EventHandler? Refreshed;
AsyncEventHandler Refreshed { get; }
}
}

View File

@@ -8,6 +8,6 @@ namespace FileTime.Core.Models
string? FullName { get; }
bool IsHidden { get; }
IContentProvider Provider { get; }
void Delete();
Task Delete();
}
}

View File

@@ -1,3 +1,4 @@
using AsyncEvent;
using FileTime.Core.Providers;
namespace FileTime.Core.Models
@@ -12,11 +13,11 @@ namespace FileTime.Core.Models
public bool IsPermanent { get; }
public bool IsTransitive { get; }
public string? VirtualContainerName { get; }
public IReadOnlyList<IItem> Items { get; private set; }
public IReadOnlyList<IItem>? Items { get; private set; }
public IReadOnlyList<IContainer> Containers { get; private set; }
public IReadOnlyList<IContainer>? Containers { get; private set; }
public IReadOnlyList<IElement> Elements { get; private set; }
public IReadOnlyList<IElement>? Elements { get; private set; }
public string Name => BaseContainer.Name;
@@ -26,10 +27,15 @@ namespace FileTime.Core.Models
public IContentProvider Provider => BaseContainer.Provider;
public event EventHandler? Refreshed
public AsyncEventHandler Refreshed { get; }
private void RefreshAddBase(Func<object?, AsyncEventArgs, Task> handler)
{
add => BaseContainer.Refreshed += value;
remove => BaseContainer.Refreshed -= value;
BaseContainer.Refreshed.Add(handler);
}
private void RefreshRemoveBase(Func<object?, AsyncEventArgs, Task> handler)
{
BaseContainer.Refreshed.Add(handler);
}
public VirtualContainer(
@@ -40,32 +46,40 @@ namespace FileTime.Core.Models
bool isTransitive = false,
string? virtualContainerName = null)
{
Refreshed = new (RefreshAddBase, RefreshRemoveBase);
BaseContainer = baseContainer;
_containerTransformators = containerTransformators;
_elementTransformators = elementTransformators;
InitItems();
IsPermanent = isPermanent;
IsTransitive = isTransitive;
VirtualContainerName = virtualContainerName;
}
private void InitItems()
public async Task Init()
{
Containers = _containerTransformators.Aggregate(BaseContainer.Containers.AsEnumerable(), (a, t) => t(a)).ToList().AsReadOnly();
Elements = _elementTransformators.Aggregate(BaseContainer.Elements.AsEnumerable(), (a, t) => t(a)).ToList().AsReadOnly();
Items = Containers.Cast<IItem>().Concat(Elements).ToList().AsReadOnly();
await InitItems();
}
public IItem? GetByPath(string path) => BaseContainer.GetByPath(path);
private async Task InitItems()
{
Containers = _containerTransformators.Aggregate((await BaseContainer.GetContainers())?.AsEnumerable(), (a, t) => t(a!))?.ToList()?.AsReadOnly();
Elements = _elementTransformators.Aggregate((await BaseContainer.GetElements())?.AsEnumerable(), (a, t) => t(a!))?.ToList()?.AsReadOnly();
Items = (Elements != null
? Containers?.Cast<IItem>().Concat(Elements)
: Containers?.Cast<IItem>())
?.ToList().AsReadOnly();
}
public async Task<IItem?> GetByPath(string path) => await BaseContainer.GetByPath(path);
public IContainer? GetParent() => BaseContainer.GetParent();
public void Refresh()
public async Task Refresh()
{
BaseContainer.Refresh();
InitItems();
await BaseContainer.Refresh();
await InitItems();
}
public IContainer GetRealContainer() =>
@@ -113,10 +127,23 @@ namespace FileTime.Core.Models
: baseContainer;
}
public IContainer CreateContainer(string name) => BaseContainer.CreateContainer(name);
public IElement CreateElement(string name) => BaseContainer.CreateElement(name);
public bool IsExists(string name) => BaseContainer.IsExists(name);
public async Task<IContainer> CreateContainer(string name) => await BaseContainer.CreateContainer(name);
public async Task<IElement> CreateElement(string name) => await BaseContainer.CreateElement(name);
public async Task<bool> IsExists(string name) => await BaseContainer.IsExists(name);
public void Delete() => BaseContainer.Delete();
public Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default)
{
return Task.FromResult(Items);
}
public Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default)
{
return Task.FromResult(Containers);
}
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default)
{
return Task.FromResult(Elements);
}
public async Task Delete() => await BaseContainer.Delete();
}
}

View File

@@ -4,7 +4,7 @@ namespace FileTime.Core.Providers
{
public interface IContentProvider : IContainer
{
IReadOnlyList<IContainer> RootContainers { get; }
Task<IReadOnlyList<IContainer>> GetRootContainers(CancellationToken token = default);
bool CanHandlePath(string path);

View File

@@ -1,4 +1,5 @@
using AsyncEvent;
using FileTime.Core.Models;
namespace FileTime.Core.Providers
@@ -6,12 +7,9 @@ namespace FileTime.Core.Providers
public class TopContainer : IContainer
{
private readonly List<IContentProvider> _contentProviders;
public IReadOnlyList<IItem> Items => Containers;
public IReadOnlyList<IContainer> Containers { get; }
public IReadOnlyList<IElement> Elements { get; } = new List<IElement>().AsReadOnly();
private readonly IReadOnlyList<IContainer>? _containers;
private readonly IReadOnlyList<IItem>? _items;
private readonly IReadOnlyList<IElement>? _elements = new List<IElement>().AsReadOnly();
public string Name => null;
@@ -21,12 +19,13 @@ namespace FileTime.Core.Providers
public IContentProvider Provider => null;
public event EventHandler? Refreshed;
public AsyncEventHandler Refreshed { get; } = new();
public TopContainer(IEnumerable<IContentProvider> contentProviders)
{
_contentProviders = new List<IContentProvider>(contentProviders);
Containers = _contentProviders.AsReadOnly();
_containers = _contentProviders.AsReadOnly();
_items = _containers.Cast<IItem>().ToList().AsReadOnly();
foreach (var contentProvider in contentProviders)
{
@@ -34,21 +33,34 @@ namespace FileTime.Core.Providers
}
}
public IContainer CreateContainer(string name) => throw new NotImplementedException();
public Task<IContainer> CreateContainer(string name) => throw new NotImplementedException();
public IElement CreateElement(string name) => throw new NotImplementedException();
public Task<IElement> CreateElement(string name) => throw new NotImplementedException();
public void Delete() => throw new NotImplementedException();
public Task Delete() => throw new NotImplementedException();
public IItem? GetByPath(string path) => throw new NotImplementedException();
public Task<IItem?> GetByPath(string path) => throw new NotImplementedException();
public IContainer? GetParent() => null;
public bool IsExists(string name) => throw new NotImplementedException();
public Task<bool> IsExists(string name) => throw new NotImplementedException();
public void Refresh()
public Task Refresh()
{
return Task.CompletedTask;
}
public Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default)
{
return Task.FromResult(_items);
}
public Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default)
{
return Task.FromResult(_containers);
}
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default)
{
return Task.FromResult(_elements);
}
}
}