Enter/Exit folder

This commit is contained in:
2022-04-11 22:09:32 +02:00
parent b6b8a7b3f8
commit 6245744612
56 changed files with 835 additions and 152 deletions

View File

@@ -3,6 +3,5 @@ namespace FileTime.Core.Models
public static class Constants
{
public const char SeparatorChar = '/';
public const int MaximumObservableMergeOperations = 4;
}
}

View File

@@ -6,7 +6,7 @@ namespace FileTime.Core.Models
{
if (Path is null) return null;
var pathParts = Path.Split(Constants.SeparatorChar);
var pathParts = Path.TrimEnd(Constants.SeparatorChar).Split(Constants.SeparatorChar);
return pathParts.Length switch
{
> 1 => new(string.Join(Constants.SeparatorChar, pathParts.SkipLast(1))),

View File

@@ -9,5 +9,7 @@ namespace FileTime.Core.Models
IContentProvider? VirtualContentProvider { get; }
FullName Path { get; }
AbsolutePathType Type { get; }
Task<IItem> ResolveAsync();
}
}

View File

@@ -9,7 +9,7 @@ namespace FileTime.Core.Models
string DisplayName { get; }
FullName? FullName { get; }
NativePath? NativePath { get; }
FullName? Parent { get; }
IAbsolutePath? Parent { get; }
bool IsHidden { get; }
bool IsExists { get; }
DateTime? CreatedAt { get; }

View File

@@ -0,0 +1,7 @@
namespace FileTime.Core.Models
{
public record ItemsTransformator(
string Name,
Func<IEnumerable<IItem>, Task<IEnumerable<IItem>>> Transformator
);
}

View File

@@ -1,5 +1,6 @@
using FileTime.Core.Models;
using InitableService;
using System.Reactive.Subjects;
namespace FileTime.Core.Services
{
@@ -9,6 +10,10 @@ namespace FileTime.Core.Services
IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
IObservable<IEnumerable<IItem>> CurrentItems { get; }
void ChangeLocation(IContainer newLocation);
void SetCurrentLocation(IContainer newLocation);
void AddSelectedItemsTransformator(ItemsTransformator transformator);
void RemoveSelectedItemsTransformator(ItemsTransformator transformator);
void RemoveSelectedItemsTransformatorByName(string name);
void SetSelectedItem(IAbsolutePath newSelectedItem);
}
}

View File

@@ -18,5 +18,11 @@ namespace FileTime.Core.Models
VirtualContentProvider = virtualContentProvider;
Type = type;
}
public async Task<IItem> ResolveAsync()
{
var provider = VirtualContentProvider ?? ContentProvider;
return await provider.GetItemByFullNameAsync(Path);
}
}
}

View File

@@ -10,7 +10,7 @@ namespace FileTime.Core.Models
string DisplayName,
FullName FullName,
NativePath NativePath,
FullName Parent,
IAbsolutePath? Parent,
bool IsHidden,
bool IsExists,
DateTime? CreatedAt,

View File

@@ -8,7 +8,7 @@ namespace FileTime.Core.Models
string DisplayName,
FullName FullName,
NativePath NativePath,
FullName Parent,
IAbsolutePath? Parent,
bool IsHidden,
bool IsExists,
DateTime? CreatedAt,

View File

@@ -8,7 +8,7 @@ namespace FileTime.Core.Models
string DisplayName,
FullName FullName,
NativePath NativePath,
FullName Parent,
IAbsolutePath? Parent,
bool IsHidden,
bool IsExists,
DateTime? CreatedAt,

View File

@@ -29,7 +29,7 @@ namespace FileTime.Core.Services
public IContentProvider Provider => this;
public FullName? Parent => null;
public IAbsolutePath? Parent => null;
public DateTime? CreatedAt => null;

View File

@@ -7,6 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Interactive.Async" Version="6.0.1" />
<PackageReference Include="System.Linq.Async" Version="6.0.1" />
<PackageReference Include="System.Reactive" Version="5.0.0" />
</ItemGroup>

View File

@@ -8,45 +8,71 @@ namespace FileTime.Core.Services
{
private readonly BehaviorSubject<IContainer?> _currentLocation = new(null);
private readonly BehaviorSubject<IAbsolutePath?> _currentSelectedItem = new(null);
private readonly List<ItemsTransformator> _transformators = new();
private IAbsolutePath? _currentSelectedItemCached;
public IObservable<IContainer?> CurrentLocation { get; }
public IObservable<IEnumerable<IItem>> CurrentItems { get; }
public IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
public Tab()
{
CurrentLocation = _currentLocation.AsObservable();
CurrentItems =
CurrentLocation = _currentLocation.DistinctUntilChanged().Do(_ => {; }).Publish(null).RefCount();
CurrentItems =
Observable.Merge(
_currentLocation
CurrentLocation
.Where(c => c is not null)
.Select(c => c!.Items)
.Switch()
.Select(
i => Observable.FromAsync(async () =>
await i
.ToAsyncEnumerable()
.SelectAwait(
async i =>
{
try
{
//TODO: force create by AbsolutePath name
return await i.ContentProvider.GetItemByFullNameAsync(i.Path);
}
catch { return null!; }
}
)
.Where(i => i != null)
.ToListAsync()
)
)
.Merge(Constants.MaximumObservableMergeOperations),
_currentLocation
.Select(i => Observable.FromAsync(async () => await MapItems(i)))
.Switch(),
CurrentLocation
.Where(c => c is null)
.Select(c => Enumerable.Empty<IItem>())
);
.Select(_ => Enumerable.Empty<IItem>())
)
.Publish(Enumerable.Empty<IItem>())
.RefCount();
CurrentSelectedItem = CurrentLocation.Select(GetSelectedItemByLocation).Switch().Merge(_currentSelectedItem).Throttle(TimeSpan.FromMilliseconds(500));
CurrentSelectedItem = CurrentLocation
.Select(GetSelectedItemByLocation)
.Switch()
.Merge(_currentSelectedItem)
.DistinctUntilChanged()
.Publish(null)
.RefCount();
CurrentSelectedItem.Subscribe(s =>
{
_currentSelectedItemCached = s;
_currentSelectedItem.OnNext(s);
});
}
private async Task<IEnumerable<IItem>> MapItems(IReadOnlyList<IAbsolutePath> items)
{
IEnumerable<IItem> resolvedItems = await items
.ToAsyncEnumerable()
.SelectAwait(
async i =>
{
try
{
//TODO: force create by AbsolutePath name
return await i.ContentProvider.GetItemByFullNameAsync(i.Path);
}
catch { return null!; }
}
)
.Where(i => i != null)
.ToListAsync();
return _transformators.Count == 0
? resolvedItems
: (await _transformators
.ToAsyncEnumerable()
.Scan(resolvedItems, (acc, t) => new ValueTask<IEnumerable<IItem>>(t.Transformator(acc)))
.ToListAsync()
)
.SelectMany(t => t);
}
public void Init(IContainer currentLocation)
@@ -56,12 +82,25 @@ namespace FileTime.Core.Services
private IObservable<IAbsolutePath?> GetSelectedItemByLocation(IContainer? currentLocation)
{
//TODO:
return currentLocation?.Items?.Select(i => i.FirstOrDefault()) ?? Observable.Never((IAbsolutePath?)null);
}
public void ChangeLocation(IContainer newLocation)
public void SetCurrentLocation(IContainer newLocation) => _currentLocation.OnNext(newLocation);
public void SetSelectedItem(IAbsolutePath newSelectedItem) => _currentSelectedItem.OnNext(newSelectedItem);
public void AddSelectedItemsTransformator(ItemsTransformator transformator) => _transformators.Add(transformator);
public void RemoveSelectedItemsTransformator(ItemsTransformator transformator) => _transformators.Remove(transformator);
public void RemoveSelectedItemsTransformatorByName(string name) => _transformators.RemoveAll(t => t.Name == name);
public async Task OpenSelected()
{
_currentLocation.OnNext(newLocation);
if (_currentSelectedItemCached == null) return;
var resolvedSelectedItem = await _currentSelectedItemCached.ContentProvider.GetItemByFullNameAsync(_currentSelectedItemCached.Path);
if (resolvedSelectedItem is not IContainer resolvedContainer) return;
SetCurrentLocation(resolvedContainer);
}
}
}