Top navigation, search delete
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public interface IContentProviderRegistry
|
||||
{
|
||||
IEnumerable<IContentProvider> ContentProviders { get; }
|
||||
ReadOnlyObservableCollection<IContentProvider> ContentProviders { get; }
|
||||
void AddContentProvider(IContentProvider contentProvider);
|
||||
void RemoveContentProvider(IContentProvider contentProvider);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public interface IRootContentProvider : IContentProvider
|
||||
{
|
||||
|
||||
}
|
||||
@@ -4,25 +4,29 @@ public record FullName(string Path)
|
||||
{
|
||||
public FullName? GetParent()
|
||||
{
|
||||
if (Path.Length == 0) return null;
|
||||
var pathParts = Path.TrimEnd(Constants.SeparatorChar).Split(Constants.SeparatorChar);
|
||||
return pathParts.Length switch
|
||||
{
|
||||
> 1 => CreateSafe(string.Join(Constants.SeparatorChar, pathParts.SkipLast(1))),
|
||||
_ => null
|
||||
_ => CreateSafe("")
|
||||
};
|
||||
}
|
||||
|
||||
public static FullName? CreateSafe(string? path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
if (path is null)
|
||||
return null;
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
return new FullName("");
|
||||
|
||||
return new(path);
|
||||
}
|
||||
|
||||
public string GetName()
|
||||
=> Path.Split(Constants.SeparatorChar).Last();
|
||||
|
||||
public FullName GetChild(string childName)
|
||||
public FullName GetChild(string childName)
|
||||
=> new(Path + Constants.SeparatorChar + childName);
|
||||
|
||||
public override string ToString() => Path;
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
namespace FileTime.Core.Models;
|
||||
|
||||
public readonly struct ItemInitializationSettings
|
||||
public sealed class ItemInitializationSettings
|
||||
{
|
||||
public readonly bool SkipChildInitialization;
|
||||
|
||||
public ItemInitializationSettings(bool skipChildInitialization)
|
||||
{
|
||||
SkipChildInitialization = skipChildInitialization;
|
||||
}
|
||||
public bool SkipChildInitialization { get; init; }
|
||||
public AbsolutePath? Parent { get; init; }
|
||||
}
|
||||
@@ -52,7 +52,10 @@ public class DeleteCommand : CommandBase, IExecutableCommand
|
||||
new DeleteStrategy()
|
||||
);
|
||||
|
||||
var parents = ItemsToDelete.Select(i => i.GetParent()).OfType<FullName>().Distinct();
|
||||
var parents = ItemsToDelete
|
||||
.Select(i => i.GetParent())
|
||||
.OfType<FullName>()
|
||||
.Distinct();
|
||||
foreach (var parent in parents)
|
||||
{
|
||||
await _commandSchedulerNotifier.RefreshContainer(parent);
|
||||
@@ -68,18 +71,26 @@ public class DeleteCommand : CommandBase, IExecutableCommand
|
||||
foreach (var itemToDeleteName in itemsToDelete)
|
||||
{
|
||||
var itemToDelete = await _timelessContentProvider.GetItemByFullNameAsync(itemToDeleteName, currentTime);
|
||||
IItemDeleter itemDeleter;
|
||||
IItemDeleter? itemDeleter = null;
|
||||
|
||||
if (itemDeleters.ContainsKey(itemToDelete.Provider.Name))
|
||||
if (itemDeleters.TryGetValue(itemToDelete.Provider.Name, out var deleter))
|
||||
{
|
||||
itemDeleter = itemDeleters[itemToDelete.Provider.Name];
|
||||
itemDeleter = deleter;
|
||||
}
|
||||
else
|
||||
{
|
||||
itemDeleter = _contentAccessorFactory.GetItemDeleter(itemToDelete.Provider);
|
||||
itemDeleters.Add(itemToDelete.Provider.Name, itemDeleter);
|
||||
try
|
||||
{
|
||||
itemDeleter = _contentAccessorFactory.GetItemDeleter(itemToDelete.Provider);
|
||||
itemDeleters.Add(itemToDelete.Provider.Name, itemDeleter);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (itemDeleter is null) continue;
|
||||
|
||||
if (itemToDelete is IContainer container)
|
||||
{
|
||||
await TraverseTree(
|
||||
@@ -95,7 +106,7 @@ public class DeleteCommand : CommandBase, IExecutableCommand
|
||||
}
|
||||
}
|
||||
|
||||
await itemDeleter.DeleteAsync(itemToDelete.Provider, itemToDelete.FullName!);
|
||||
await deleteStrategy.DeleteItem(itemToDelete, itemDeleter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,6 @@ namespace FileTime.Core.Command.Delete;
|
||||
|
||||
public class DeleteStrategy : IDeleteStrategy
|
||||
{
|
||||
public async Task DeleteItem(IItem item, IItemDeleter deleter)
|
||||
{
|
||||
await deleter.DeleteAsync(item.Provider, item.FullName!);
|
||||
}
|
||||
public async Task DeleteItem(IItem item, IItemDeleter deleter)
|
||||
=> await deleter.DeleteAsync(item.Provider, item.FullName!);
|
||||
}
|
||||
@@ -32,7 +32,7 @@ public abstract class ContentProviderBase : IContentProvider
|
||||
|
||||
public IContentProvider Provider => this;
|
||||
|
||||
public AbsolutePath? Parent => null;
|
||||
public AbsolutePath? Parent { get; }
|
||||
|
||||
public DateTime? CreatedAt => null;
|
||||
|
||||
@@ -46,14 +46,15 @@ public abstract class ContentProviderBase : IContentProvider
|
||||
public bool AllowRecursiveDeletion => false;
|
||||
|
||||
public AbsolutePathType Type => AbsolutePathType.Container;
|
||||
public PointInTime PointInTime { get; } = PointInTime.Eternal;
|
||||
public PointInTime PointInTime => PointInTime.Eternal;
|
||||
|
||||
public ObservableCollection<Exception> Exceptions { get; } = new();
|
||||
|
||||
ReadOnlyExtensionCollection IItem.Extensions => _extensions;
|
||||
|
||||
protected ContentProviderBase(string name)
|
||||
protected ContentProviderBase(string name, ITimelessContentProvider timelessContentProvider)
|
||||
{
|
||||
Parent = new AbsolutePath(timelessContentProvider, PointInTime.Eternal, new FullName(""), AbsolutePathType.Container);
|
||||
DisplayName = Name = name;
|
||||
FullName = FullName.CreateSafe(name);
|
||||
Extensions = new ExtensionCollection();
|
||||
|
||||
@@ -1,21 +1,64 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public class ContentProviderRegistry : IContentProviderRegistry
|
||||
{
|
||||
private readonly object _lock = new();
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly Lazy<IList<IContentProvider>> _defaultContentProviders;
|
||||
private readonly List<IContentProvider> _additionalContentProviders = new();
|
||||
private readonly ObservableCollection<IContentProvider> _contentProviders = new();
|
||||
private readonly ReadOnlyObservableCollection<IContentProvider> _contentProvidersReadOnly;
|
||||
private bool _initialized;
|
||||
|
||||
public ContentProviderRegistry(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_defaultContentProviders = new Lazy<IList<IContentProvider>>(() => serviceProvider.GetServices<IContentProvider>().ToList());
|
||||
_contentProvidersReadOnly = new ReadOnlyObservableCollection<IContentProvider>(_contentProviders);
|
||||
}
|
||||
|
||||
public IEnumerable<IContentProvider> ContentProviders => _defaultContentProviders.Value.Concat(_additionalContentProviders);
|
||||
public ReadOnlyObservableCollection<IContentProvider> ContentProviders
|
||||
{
|
||||
get
|
||||
{
|
||||
InitializeContentProviderListIfNeeded();
|
||||
return _contentProvidersReadOnly;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddContentProvider(IContentProvider contentProvider) => _additionalContentProviders.Add(contentProvider);
|
||||
public void RemoveContentProvider(IContentProvider contentProvider) => _additionalContentProviders.Remove(contentProvider);
|
||||
private void InitializeContentProviderListIfNeeded()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
foreach (var contentProvider in _serviceProvider.GetServices<IContentProvider>())
|
||||
{
|
||||
_contentProviders.Add(contentProvider);
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddContentProvider(IContentProvider contentProvider)
|
||||
{
|
||||
InitializeContentProviderListIfNeeded();
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_contentProviders.Add(contentProvider);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveContentProvider(IContentProvider contentProvider)
|
||||
{
|
||||
InitializeContentProviderListIfNeeded();
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
_contentProviders.Remove(contentProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
87
src/Core/FileTime.Core.ContentAccess/RootContentProvider.cs
Normal file
87
src/Core/FileTime.Core.ContentAccess/RootContentProvider.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reactive.Linq;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
using ObservableComputations;
|
||||
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public class RootContentProvider : IRootContentProvider
|
||||
{
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
public string Name => "root";
|
||||
public string DisplayName => "Root";
|
||||
public FullName? FullName => null;
|
||||
public NativePath? NativePath => null;
|
||||
public AbsolutePath? Parent => null;
|
||||
public bool IsHidden => false;
|
||||
public bool IsExists => true;
|
||||
public DateTime? CreatedAt => null;
|
||||
public SupportsDelete CanDelete => SupportsDelete.False;
|
||||
public bool CanRename => false;
|
||||
public IContentProvider Provider => this;
|
||||
public string? Attributes => null;
|
||||
public AbsolutePathType Type => AbsolutePathType.Container;
|
||||
public PointInTime PointInTime => PointInTime.Eternal;
|
||||
public ObservableCollection<Exception> Exceptions { get; } = new();
|
||||
public ReadOnlyExtensionCollection Extensions { get; } = new(new ExtensionCollection());
|
||||
public ObservableCollection<AbsolutePath> Items { get; }
|
||||
public IObservable<bool> IsLoading => Observable.Return(false);
|
||||
public bool? IsLoaded => true;
|
||||
public Task WaitForLoaded(CancellationToken token = default) => Task.CompletedTask;
|
||||
|
||||
public bool AllowRecursiveDeletion => false;
|
||||
public Task OnEnter() => Task.CompletedTask;
|
||||
|
||||
public bool SupportsContentStreams => false;
|
||||
|
||||
public RootContentProvider(
|
||||
IContentProviderRegistry contentProviderRegistry,
|
||||
ITimelessContentProvider timelessContentProvider)
|
||||
{
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
Items = contentProviderRegistry
|
||||
.ContentProviders
|
||||
.Selecting<IContentProvider, AbsolutePath>(c =>
|
||||
new AbsolutePath(timelessContentProvider, c)
|
||||
);
|
||||
}
|
||||
|
||||
public async Task<IItem> GetItemByFullNameAsync(
|
||||
FullName fullName,
|
||||
PointInTime pointInTime,
|
||||
bool forceResolve = false,
|
||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||
ItemInitializationSettings itemInitializationSettings = default)
|
||||
=> await _timelessContentProvider.GetItemByFullNameAsync(
|
||||
fullName,
|
||||
pointInTime,
|
||||
forceResolve,
|
||||
forceResolvePathType,
|
||||
itemInitializationSettings);
|
||||
|
||||
public async Task<IItem> GetItemByNativePathAsync(
|
||||
NativePath nativePath,
|
||||
PointInTime pointInTime,
|
||||
bool forceResolve = false,
|
||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||
ItemInitializationSettings itemInitializationSettings = default)
|
||||
=> await _timelessContentProvider.GetItemByNativePathAsync(
|
||||
nativePath,
|
||||
pointInTime
|
||||
) ?? throw new FileNotFoundException();
|
||||
|
||||
public NativePath GetNativePath(FullName fullName) => throw new NotImplementedException();
|
||||
|
||||
public FullName GetFullName(NativePath nativePath) => throw new NotImplementedException();
|
||||
|
||||
public Task<byte[]?> GetContentAsync(
|
||||
IElement element,
|
||||
int? maxLength = null,
|
||||
CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
||||
|
||||
public bool CanHandlePath(NativePath path) => throw new NotImplementedException();
|
||||
|
||||
public bool CanHandlePath(FullName path) => throw new NotImplementedException();
|
||||
}
|
||||
@@ -140,7 +140,7 @@ public class Tab : ITab
|
||||
{
|
||||
var itemNameToSelect = LastDeepestSelectedPath.Path
|
||||
.Split(Constants.SeparatorChar)
|
||||
.Skip(parentPath.Split(Constants.SeparatorChar).Length)
|
||||
.Skip(parentPath == "" ? 0 : parentPath.Split(Constants.SeparatorChar).Length)
|
||||
.FirstOrDefault();
|
||||
|
||||
var itemToSelect = items.FirstOrDefault(i => i.FullName?.GetName() == itemNameToSelect);
|
||||
|
||||
@@ -2,18 +2,24 @@ using System.Reactive.Subjects;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Models;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace FileTime.Core.Timeline;
|
||||
|
||||
public class TimelessContentProvider : ITimelessContentProvider
|
||||
{
|
||||
private readonly IContentProviderRegistry _contentProviderRegistry;
|
||||
private readonly Lazy<IRootContentProvider> _rootContentProvider;
|
||||
|
||||
public BehaviorSubject<PointInTime> CurrentPointInTime { get; } = new(PointInTime.Present);
|
||||
|
||||
public TimelessContentProvider(IContentProviderRegistry contentProviderRegistry)
|
||||
public TimelessContentProvider(
|
||||
IContentProviderRegistry contentProviderRegistry,
|
||||
IServiceProvider serviceProvider
|
||||
)
|
||||
{
|
||||
_contentProviderRegistry = contentProviderRegistry;
|
||||
_rootContentProvider = new Lazy<IRootContentProvider>(serviceProvider.GetRequiredService<IRootContentProvider>);
|
||||
}
|
||||
|
||||
public async Task<IItem> GetItemByFullNameAsync(FullName fullName, PointInTime? pointInTime,
|
||||
@@ -23,6 +29,8 @@ public class TimelessContentProvider : ITimelessContentProvider
|
||||
{
|
||||
//TODO time modifications
|
||||
var contentProviderName = fullName.Path.Split(Constants.SeparatorChar).FirstOrDefault();
|
||||
if (contentProviderName == "") return _rootContentProvider.Value;
|
||||
|
||||
var contentProvider = _contentProviderRegistry.ContentProviders.FirstOrDefault(p => p.Name == contentProviderName);
|
||||
|
||||
if (contentProvider is null)
|
||||
@@ -37,7 +45,7 @@ public class TimelessContentProvider : ITimelessContentProvider
|
||||
{
|
||||
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
||||
{
|
||||
if(!contentProvider.CanHandlePath(nativePath)) continue;
|
||||
if (!contentProvider.CanHandlePath(nativePath)) continue;
|
||||
|
||||
return await contentProvider.GetItemByNativePathAsync(nativePath, pointInTime ?? PointInTime.Present);
|
||||
}
|
||||
@@ -49,7 +57,7 @@ public class TimelessContentProvider : ITimelessContentProvider
|
||||
{
|
||||
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
||||
{
|
||||
if(!contentProvider.CanHandlePath(nativePath)) continue;
|
||||
if (!contentProvider.CanHandlePath(nativePath)) continue;
|
||||
|
||||
return contentProvider.GetFullName(nativePath);
|
||||
}
|
||||
@@ -61,7 +69,7 @@ public class TimelessContentProvider : ITimelessContentProvider
|
||||
{
|
||||
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
||||
{
|
||||
if(!contentProvider.CanHandlePath(fullName)) continue;
|
||||
if (!contentProvider.CanHandlePath(fullName)) continue;
|
||||
|
||||
return contentProvider.GetNativePath(fullName);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user