Incremental item loading, movement does not respect order

This commit is contained in:
2023-02-22 23:09:40 +01:00
parent 3dccaa5243
commit 188b9593ce
6 changed files with 91 additions and 25 deletions

View File

@@ -82,7 +82,6 @@ public partial class TabViewModel : ITabViewModel
CurrentItems = tab.CurrentItems CurrentItems = tab.CurrentItems
.Select(items => items?.Transform(i => MapItemToViewModel(i, ItemViewModelType.Main))) .Select(items => items?.Transform(i => MapItemToViewModel(i, ItemViewModelType.Main)))
.Select(items => items?.Sort(SortItems()))
.Publish(null) .Publish(null)
.RefCount(); .RefCount();

View File

@@ -22,7 +22,6 @@ public interface IContentProvider : IContainer, IOnContainerEnter
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
ItemInitializationSettings itemInitializationSettings = default); ItemInitializationSettings itemInitializationSettings = default);
Task<List<AbsolutePath>> GetItemsByContainerAsync(FullName fullName, PointInTime pointInTime);
NativePath GetNativePath(FullName fullName); NativePath GetNativePath(FullName fullName);
Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default); Task<byte[]?> GetContentAsync(IElement element, int? maxLength = null, CancellationToken cancellationToken = default);

View File

@@ -78,7 +78,6 @@ public abstract class ContentProviderBase : IContentProvider
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown, AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
ItemInitializationSettings itemInitializationSettings = default); ItemInitializationSettings itemInitializationSettings = default);
public abstract Task<List<AbsolutePath>> GetItemsByContainerAsync(FullName fullName, PointInTime pointInTime);
public abstract NativePath GetNativePath(FullName fullName); public abstract NativePath GetNativePath(FullName fullName);
public abstract Task<byte[]?> GetContentAsync(IElement element, public abstract Task<byte[]?> GetContentAsync(IElement element,

View File

@@ -26,7 +26,14 @@ public record Container(
ReadOnlyExtensionCollection Extensions, ReadOnlyExtensionCollection Extensions,
IObservable<IObservable<IChangeSet<AbsolutePath, string>>?> Items) : IContainer IObservable<IObservable<IChangeSet<AbsolutePath, string>>?> Items) : IContainer
{ {
BehaviorSubject<bool> IsLoading { get; } = new(false); private readonly CancellationTokenSource _loadingCancellationTokenSource = new();
public CancellationToken LoadingCancellationToken => _loadingCancellationTokenSource.Token;
public BehaviorSubject<bool> IsLoading { get; } = new(false);
IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable(); IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable();
public AbsolutePathType Type => AbsolutePathType.Container; public AbsolutePathType Type => AbsolutePathType.Container;
public void CancelLoading()
{
_loadingCancellationTokenSource.Cancel();
}
} }

View File

@@ -2,6 +2,7 @@ using System.Reactive.Linq;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using DynamicData; using DynamicData;
using DynamicData.Alias; using DynamicData.Alias;
using DynamicData.Binding;
using FileTime.Core.Helper; using FileTime.Core.Helper;
using FileTime.Core.Models; using FileTime.Core.Models;
using FileTime.Core.Timeline; using FileTime.Core.Timeline;
@@ -52,7 +53,11 @@ public class Tab : ITab
.Switch() .Switch()
.Select(items => items?.TransformAsync(MapItem)), .Select(items => items?.TransformAsync(MapItem)),
_itemFilters.Connect().StartWithEmpty().ToCollection(), _itemFilters.Connect().StartWithEmpty().ToCollection(),
(items, filters) => items?.Where(i => filters.All(f => f.Filter(i)))), (items, filters) =>
items
?.Where(i => filters.All(f => f.Filter(i)))
.Sort(SortItems())
),
CurrentLocation CurrentLocation
.Where(c => c is null) .Where(c => c is null)
.Select(_ => (IObservable<IChangeSet<IItem, string>>?)null) .Select(_ => (IObservable<IChangeSet<IItem, string>>?)null)
@@ -89,6 +94,12 @@ public class Tab : ITab
}); });
} }
private static SortExpressionComparer<IItem> SortItems()
//TODO: Order
=> SortExpressionComparer<IItem>
.Ascending(i => i.Type)
.ThenByAscending(i => i.DisplayName?.ToLower() ?? "");
private async Task<IItem> MapItem(AbsolutePath item) => await item.ResolveAsync(true); private async Task<IItem> MapItem(AbsolutePath item) => await item.ResolveAsync(true);
public void Init(IContainer currentLocation) public void Init(IContainer currentLocation)

View File

@@ -177,23 +177,6 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
throw new NotImplementedException(); throw new NotImplementedException();
} }
public override Task<List<AbsolutePath>> GetItemsByContainerAsync(FullName fullName, PointInTime pointInTime)
=> Task.FromResult(GetItemsByContainer(fullName, pointInTime));
private List<AbsolutePath> GetItemsByContainer(FullName fullName, PointInTime pointInTime)
=> GetItemsByContainer(new DirectoryInfo(GetNativePath(fullName).Path), pointInTime);
private List<AbsolutePath> GetItemsByContainer(DirectoryInfo directoryInfo, PointInTime pointInTime)
=> directoryInfo
.GetDirectories()
.Select(d => DirectoryToAbsolutePath(d, pointInTime))
.Concat(
directoryInfo
.GetFiles()
.Select(f => FileToAbsolutePath(f, pointInTime))
)
.ToList();
private AbsolutePath DirectoryToAbsolutePath(DirectoryInfo directoryInfo, PointInTime pointInTime) private AbsolutePath DirectoryToAbsolutePath(DirectoryInfo directoryInfo, PointInTime pointInTime)
{ {
var fullName = GetFullName(directoryInfo); var fullName = GetFullName(directoryInfo);
@@ -221,7 +204,9 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
AbsolutePathType.Container); AbsolutePathType.Container);
var exceptions = new BehaviorSubject<IEnumerable<Exception>>(Enumerable.Empty<Exception>()); var exceptions = new BehaviorSubject<IEnumerable<Exception>>(Enumerable.Empty<Exception>());
return new Container( var children = new SourceCache<AbsolutePath, string>(i => i.Path.Path);
var container = new Container(
directoryInfo.Name, directoryInfo.Name,
directoryInfo.Name, directoryInfo.Name,
fullName, fullName,
@@ -239,10 +224,13 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
exceptions, exceptions,
new ExtensionCollection().AsReadOnly(), new ExtensionCollection().AsReadOnly(),
//Observable.FromAsync(async () => await Task.Run(InitChildrenHelper) //Observable.FromAsync(async () => await Task.Run(InitChildrenHelper)
Observable.Return(InitChildren()) //Observable.Return(InitChildren())
Observable.Return(children.Connect())
); );
Task<IObservable<IChangeSet<AbsolutePath, string>>?> InitChildrenHelper() => Task.FromResult(InitChildren()); Task.Run(() => LoadChildren(container, directoryInfo, children, pointInTime));
return container;
IObservable<IChangeSet<AbsolutePath, string>>? InitChildren() IObservable<IChangeSet<AbsolutePath, string>>? InitChildren()
{ {
@@ -267,6 +255,69 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
} }
} }
private void LoadChildren(
Container container,
DirectoryInfo directoryInfo,
SourceCache<AbsolutePath, string> children,
PointInTime pointInTime)
{
var lockobj = new object();
var loadingIndicatorCancellation = new CancellationTokenSource();
Task.Run(DelayedLoadingIndicator);
LoadChildren();
lock (lockobj)
{
loadingIndicatorCancellation.Cancel();
container.IsLoading.OnNext(false);
}
void LoadChildren()
{
foreach (var directory in directoryInfo.EnumerateDirectories())
{
if (container.LoadingCancellationToken.IsCancellationRequested) break;
var absolutePath = DirectoryToAbsolutePath(directory, pointInTime);
children.AddOrUpdate(absolutePath);
}
foreach (var file in directoryInfo.EnumerateFiles())
{
if (container.LoadingCancellationToken.IsCancellationRequested) break;
var absolutePath = FileToAbsolutePath(file, pointInTime);
children.AddOrUpdate(absolutePath);
}
}
async Task DelayedLoadingIndicator()
{
var token = loadingIndicatorCancellation.Token;
try
{
await Task.Delay(500, token);
}
catch { }
lock (lockobj)
{
if (token.IsCancellationRequested) return;
container.IsLoading.OnNext(true);
}
}
}
private List<AbsolutePath> GetItemsByContainer(DirectoryInfo directoryInfo, PointInTime pointInTime)
=> directoryInfo
.GetDirectories()
.Select(d => DirectoryToAbsolutePath(d, pointInTime))
.Concat(
directoryInfo
.GetFiles()
.Select(f => FileToAbsolutePath(f, pointInTime))
)
.ToList();
private Element FileToElement(FileInfo fileInfo, PointInTime pointInTime) private Element FileToElement(FileInfo fileInfo, PointInTime pointInTime)
{ {
var fullName = GetFullName(fileInfo); var fullName = GetFullName(fileInfo);