Refactor: items with DynamicData

This commit is contained in:
2022-04-22 09:09:14 +02:00
parent da3ccf4317
commit 76c6e30154
31 changed files with 281 additions and 141 deletions

View File

@@ -7,6 +7,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="DynamicData" Version="7.6.7" />
<PackageReference Include="System.Reactive" Version="5.0.0" />
</ItemGroup>

View File

@@ -1,8 +1,10 @@
using DynamicData;
namespace FileTime.Core.Models
{
public interface IContainer : IItem
{
IObservable<IEnumerable<IAbsolutePath>?> Items { get; }
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> Items { get; }
IObservable<bool> IsLoading { get; }
}
}

View File

@@ -1,3 +1,4 @@
using DynamicData;
using FileTime.Core.Models;
using InitableService;
@@ -7,7 +8,7 @@ namespace FileTime.Core.Services
{
IObservable<IContainer?> CurrentLocation { get; }
IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
IObservable<IEnumerable<IItem>?> CurrentItems { get; }
IObservable<IObservable<IChangeSet<IItem>>?> CurrentItems { get; }
void SetCurrentLocation(IContainer newLocation);
void AddSelectedItemsTransformator(ItemsTransformator transformator);

View File

@@ -19,6 +19,14 @@ namespace FileTime.Core.Models
Type = type;
}
public AbsolutePath(IItem item, IContentProvider? virtualContentProvider = null)
{
ContentProvider = item.Provider;
Path = item.FullName ?? throw new ArgumentException($"{nameof(item.FullName)} can not be null.", nameof(item));
VirtualContentProvider = virtualContentProvider;
Type = item.Type;
}
public async Task<IItem> ResolveAsync(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default)
{
var provider = VirtualContentProvider ?? ContentProvider;

View File

@@ -1,5 +1,6 @@
using System.Reactive.Linq;
using System.Reactive.Subjects;
using DynamicData;
using FileTime.Core.Enums;
using FileTime.Core.Services;
@@ -19,7 +20,7 @@ namespace FileTime.Core.Models
string? Attributes,
IContentProvider Provider,
IObservable<IEnumerable<Exception>> Exceptions,
IObservable<IEnumerable<IAbsolutePath>?> Items) : IContainer
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> Items) : IContainer
{
BehaviorSubject<bool> IsLoading { get; } = new BehaviorSubject<bool>(false);
IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable();

View File

@@ -1,5 +1,6 @@
using System.Reactive.Linq;
using System.Reactive.Subjects;
using DynamicData;
using FileTime.Core.Enums;
using FileTime.Core.Models;
@@ -7,9 +8,9 @@ namespace FileTime.Core.Services
{
public abstract class ContentProviderBase : IContentProvider
{
protected BehaviorSubject<IReadOnlyList<IAbsolutePath>> Items { get; } = new BehaviorSubject<IReadOnlyList<IAbsolutePath>>(new List<IAbsolutePath>());
protected BehaviorSubject<IObservable<IChangeSet<IAbsolutePath>>?> Items { get; } = new (null);
IObservable<IEnumerable<IAbsolutePath>> IContainer.Items => Items;
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> IContainer.Items => Items;
public string Name { get; }

View File

@@ -13,6 +13,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Tools\FileTime.Tools\FileTime.Tools.csproj" />
<ProjectReference Include="..\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
<ProjectReference Include="..\FileTime.Core.Models\FileTime.Core.Models.csproj" />
</ItemGroup>

View File

@@ -1,5 +1,6 @@
using System.Reactive.Linq;
using System.Reactive.Subjects;
using DynamicData;
using FileTime.Core.Models;
namespace FileTime.Core.Services
@@ -10,8 +11,9 @@ namespace FileTime.Core.Services
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<IObservable<IChangeSet<IItem>>?> CurrentItems { get; }
public IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
public Tab()
@@ -23,53 +25,54 @@ namespace FileTime.Core.Services
.Where(c => c is not null)
.Select(c => c!.Items)
.Switch()
.Select(i => i == null ? Observable.Return<IEnumerable<IItem>?>(null) : Observable.FromAsync(async () => await MapItems(i)))
.Switch(),
.Select(items => items?.TransformAsync(MapItem)),
CurrentLocation
.Where(c => c is null)
.Select(_ => Enumerable.Empty<IItem>())
.Select(_ => (IObservable<IChangeSet<IItem>>?)null)
)
.Publish(Enumerable.Empty<IItem>())
.Publish((IObservable<IChangeSet<IItem>>?)null)
.RefCount();
CurrentSelectedItem = CurrentLocation
.Select(GetSelectedItemByLocation)
.Switch()
.Merge(_currentSelectedItem)
CurrentSelectedItem =
Observable.CombineLatest(
CurrentItems
.Select(c =>
c == null
? Observable.Return<IReadOnlyCollection<IItem>?>(null)
: c.ToCollection()
)
.Switch(),
_currentSelectedItem,
(items, selected) =>
{
if (selected != null && (items?.Any(i => i.FullName == selected.Path) ?? true)) return selected;
if (items == null || items.Count == 0) return null;
return GetSelectedItemByItems(items);
}
)
.DistinctUntilChanged()
.Publish(null)
.RefCount();
CurrentSelectedItem.Subscribe(s => _currentSelectedItemCached = s);
CurrentSelectedItem.Subscribe(s =>
{
_currentSelectedItemCached = s;
_currentSelectedItem.OnNext(s);
});
}
private async Task<IEnumerable<IItem>> MapItems(IEnumerable<IAbsolutePath> items)
{
IEnumerable<IItem> resolvedItems = await items
.ToAsyncEnumerable()
.SelectAwait(async i => await i.ResolveAsync(true))
.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);
}
private async Task<IItem> MapItem(IAbsolutePath item) => await item.ResolveAsync(true);
public void Init(IContainer currentLocation)
{
_currentLocation.OnNext(currentLocation);
}
private IObservable<IAbsolutePath?> GetSelectedItemByLocation(IContainer? currentLocation)
private static IAbsolutePath? GetSelectedItemByItems(IEnumerable<IItem> items)
{
//TODO:
return currentLocation?.Items?.Select(i => i?.FirstOrDefault()) ?? Observable.Return((IAbsolutePath?)null);
return new AbsolutePath(items.First());
}
public void SetCurrentLocation(IContainer newLocation) => _currentLocation.OnNext(newLocation);