New reactive core WIP

This commit is contained in:
2023-07-21 22:15:48 +02:00
parent 342fc0d047
commit b61c204e49
61 changed files with 1605 additions and 413 deletions

View File

@@ -10,12 +10,11 @@ public partial class ContainerViewModel : ItemViewModel, IContainerViewModel
{
public IContainer? Container => BaseItem as IContainer;
public ContainerViewModel(IItemNameConverterService itemNameConverterService, IAppState appState) : base(itemNameConverterService, appState)
public ContainerViewModel(IItemNameConverterService itemNameConverterService, IAppState appState)
: base(itemNameConverterService, appState)
{
}
public void Init(IContainer item, ITabViewModel parentTab, ItemViewModelType itemViewModelType)
{
Init((IItem)item, parentTab, itemViewModelType);
}
public void Init(IContainer item, ITabViewModel parentTab, ItemViewModelType itemViewModelType)
=> Init((IItem)item, parentTab, itemViewModelType);
}

View File

@@ -1,5 +1,6 @@
using System.ComponentModel;
using System.Reactive.Linq;
using DeclarativeProperty;
using DynamicData;
using FileTime.App.Core.Models;
using FileTime.App.Core.Models.Enums;
@@ -18,32 +19,23 @@ public abstract partial class ItemViewModel : IItemViewModel
{
private ITabViewModel? _parentTab;
[Property]
private IItem? _baseItem;
[Property] private IItem? _baseItem;
[Property]
private IObservable<IReadOnlyList<ItemNamePart>>? _displayName;
[Property] private IObservable<IReadOnlyList<ItemNamePart>>? _displayName;
[Property]
private string? _displayNameText;
[Property] private string? _displayNameText;
[Property]
private IObservable<bool>? _isSelected;
[Property] private IDeclarativeProperty<bool> _isSelected;
[Property]
private IObservable<bool>? _isMarked;
[Property] private IObservable<bool>? _isMarked;
[Property]
private IObservable<ItemViewMode> _viewMode;
[Property] private IObservable<ItemViewMode> _viewMode;
[Property]
private DateTime? _createdAt;
[Property] private DateTime? _createdAt;
[Property]
private string? _attributes;
[Property] private string? _attributes;
[Property]
private IObservable<bool> _isAlternative;
[Property] private IDeclarativeProperty<bool> _isAlternative;
public void Init(IItem item, ITabViewModel parentTab, ItemViewModelType itemViewModelType)
{
@@ -51,9 +43,9 @@ public abstract partial class ItemViewModel : IItemViewModel
var sourceCollection = itemViewModelType switch
{
ItemViewModelType.Main => parentTab.CurrentItemsCollectionObservable,
ItemViewModelType.Parent => parentTab.ParentsChildrenCollectionObservable,
ItemViewModelType.SelectedChild => parentTab.SelectedsChildrenCollectionObservable,
ItemViewModelType.Main => parentTab.CurrentItems,
ItemViewModelType.Parent => parentTab.ParentsChildren,
ItemViewModelType.SelectedChild => parentTab.SelectedsChildren,
_ => throw new InvalidEnumArgumentException()
};
@@ -66,10 +58,10 @@ public abstract partial class ItemViewModel : IItemViewModel
: Observable.Return(false);
IsSelected = itemViewModelType is ItemViewModelType.Main
? parentTab.CurrentSelectedItem.Select(EqualsTo)
: Observable.Return(IsInDeepestPath());
? parentTab.CurrentSelectedItem.Map(EqualsTo)
: new DeclarativeProperty<bool>(IsInDeepestPath());
IsAlternative = sourceCollection.Select(c => c?.Index().FirstOrDefault(i => EqualsTo(i.Value)).Key % 2 == 0);
IsAlternative = sourceCollection.Map(c => c?.Index().FirstOrDefault(i => EqualsTo(i.Value)).Key % 2 == 0);
ViewMode = Observable.CombineLatest(IsMarked, IsSelected, IsAlternative, GenerateViewMode).Throttle(TimeSpan.FromMilliseconds(10));
Attributes = item.Attributes;

View File

@@ -1,4 +1,7 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Reactive.Linq;
using DeclarativeProperty;
using DynamicData;
using DynamicData.Binding;
using FileTime.App.Core.Extensions;
@@ -10,6 +13,9 @@ using FileTime.Core.Models.Extensions;
using FileTime.Core.Services;
using InitableService;
using MvvmGen;
using ObservableComputations;
using IContainer = FileTime.Core.Models.IContainer;
using static System.DeferTools;
namespace FileTime.App.Core.ViewModels;
@@ -23,36 +29,23 @@ public partial class TabViewModel : ITabViewModel
private readonly SourceList<FullName> _markedItems = new();
private readonly List<IDisposable> _disposables = new();
private bool _disposed;
private OcConsumer? _currentItemsConsumer;
private OcConsumer? _selectedsChildrenConsumer;
private OcConsumer? _parentsChildrenConsumer;
public ITab? Tab { get; private set; }
public int TabNumber { get; private set; }
public IObservable<bool> IsSelected { get; }
public IObservable<IContainer?> CurrentLocation { get; private set; } = null!;
public IObservable<IItemViewModel?> CurrentSelectedItem { get; private set; } = null!;
public IObservable<IObservable<IChangeSet<IItemViewModel, string>>?> CurrentItems { get; private set; } = null!;
public IDeclarativeProperty<IContainer?> CurrentLocation { get; private set; }
public IDeclarativeProperty<IItemViewModel?> CurrentSelectedItem { get; private set; }
public IDeclarativeProperty<IContainerViewModel?> CurrentSelectedItemAsContainer { get; private set; }
public IDeclarativeProperty<ObservableCollection<IItemViewModel>?> CurrentItems { get; private set; }
public IObservable<IChangeSet<FullName>> MarkedItems { get; }
public IObservable<IObservable<IChangeSet<IItemViewModel, string>>?> SelectedsChildren { get; private set; } = null!;
public IObservable<IObservable<IChangeSet<IItemViewModel, string>>?> ParentsChildren { get; private set; } = null!;
public IDeclarativeProperty<ObservableCollection<IItemViewModel>?> SelectedsChildren { get; private set; }
public IDeclarativeProperty<ObservableCollection<IItemViewModel>?> ParentsChildren { get; private set; }
public IObservable<IReadOnlyCollection<IItemViewModel>?> CurrentItemsCollectionObservable { get; private set; } =
null!;
public IObservable<IReadOnlyCollection<IItemViewModel>?> ParentsChildrenCollectionObservable { get; private set; } =
null!;
public IObservable<IReadOnlyCollection<IItemViewModel>?>
SelectedsChildrenCollectionObservable
{ get; private set; } = null!;
[Property] private BindedCollection<IItemViewModel, string>? _currentItemsCollection;
[Property] private BindedCollection<IItemViewModel, string>? _parentsChildrenCollection;
[Property] private BindedCollection<IItemViewModel, string>? _selectedsChildrenCollection;
public IContainer? CachedCurrentLocation { get; private set; }
public TabViewModel(
IServiceProvider serviceProvider,
@@ -76,13 +69,19 @@ public partial class TabViewModel : ITabViewModel
tab.AddToDisposables(_disposables);
CurrentLocation = tab.CurrentLocation.AsObservable();
CurrentLocation.Subscribe(l => CachedCurrentLocation = l).AddToDisposables(_disposables);
CurrentLocation = tab.CurrentLocation;
CurrentItems = tab.CurrentItems
.Select(items => items?.Transform(i => MapItemToViewModel(i, ItemViewModelType.Main)))
.Publish(null)
.RefCount();
.Map((items, _) =>
Task.FromResult<ObservableCollection<IItemViewModel>?>(
items?.Selecting<IItem, IItemViewModel>(
i => MapItemToViewModel(i, ItemViewModelType.Main)
)
)
);
using var _ = Defer(
() => CurrentItems.Subscribe(c => UpdateConsumer(c, ref _currentItemsConsumer))
);
/*CurrentSelectedItem =
Observable.CombineLatest(
@@ -100,30 +99,65 @@ public partial class TabViewModel : ITabViewModel
.Publish(null)
.RefCount();*/
CurrentSelectedItem =
CurrentSelectedItem = DeclarativePropertyHelpers.CombineLatest(
tab.CurrentSelectedItem,
CurrentItems.Watch<ObservableCollection<IItemViewModel>, IItemViewModel>(),
(currentSelectedItem, currentItems) =>
Task.FromResult(currentItems?.FirstOrDefault(i => i.BaseItem?.FullName?.Path == currentSelectedItem?.Path.Path))
);
CurrentSelectedItemAsContainer = CurrentSelectedItem.Map(i => i as IContainerViewModel);
//CurrentSelectedItem = tab.CurrentSelectedItem.Map((item, _) => Task.FromResult(CurrentItems.Value?.FirstOrDefault(i => i.BaseItem?.FullName?.Path == item?.Path.Path)));
/*CurrentSelectedItem =
Observable.CombineLatest(
CurrentItems,
tab.CurrentSelectedItem,
(currentItems, currentSelectedItemPath) =>
CurrentItemsCollection?.Collection?.FirstOrDefault(i => i.BaseItem?.FullName?.Path == currentSelectedItemPath?.Path.Path)
)
)
.Publish(null)
.RefCount();
.RefCount();*/
SelectedsChildren = InitSelectedsChildren();
ParentsChildren = InitParentsChildren();
SelectedsChildren = CurrentSelectedItem
.Debounce(TimeSpan.FromMilliseconds(200), resetTimer: true)
.DistinctUntilChanged()
.Map(item =>
{
if (item is not IContainerViewModel {Container: { } container})
return (ObservableCollection<IItemViewModel>?) null;
CurrentItemsCollectionObservable = InitCollection(CurrentItems);
SelectedsChildrenCollectionObservable = InitCollection(SelectedsChildren);
ParentsChildrenCollectionObservable = InitCollection(ParentsChildren);
var items = container
.Items
.Selecting(i => MapItem(i))
.Ordering(i => i.Type)
.ThenOrdering(i => i.Name)
.Selecting(i => MapItemToViewModel(i, ItemViewModelType.SelectedChild));
CurrentItemsCollection = new(CurrentItems);
ParentsChildrenCollection = new(ParentsChildren);
SelectedsChildrenCollection = new(SelectedsChildren);
return items;
});
using var __ = Defer(() =>
SelectedsChildren.Subscribe(c => UpdateConsumer(c, ref _selectedsChildrenConsumer))
);
tab.CurrentLocation.Subscribe((_) => _markedItems.Clear()).AddToDisposables(_disposables);
ParentsChildren = CurrentLocation.Map(async (item, _) =>
{
if (item is null || item.Parent is null) return (ObservableCollection<IItemViewModel>?) null;
var parent = (IContainer) await item.Parent.ResolveAsync(itemInitializationSettings: new ItemInitializationSettings(true));
IObservable<IObservable<IChangeSet<IItemViewModel, string>>?> InitSelectedsChildren()
var items = parent.Items
.Selecting<AbsolutePath, IItem>(i => MapItem(i))
.Selecting(i => MapItemToViewModel(i, ItemViewModelType.SelectedChild));
return items;
});
using var ___ = Defer(() =>
ParentsChildren.Subscribe(c => UpdateConsumer(c, ref _parentsChildrenConsumer))
);
tab.CurrentLocation.Subscribe(_ => _markedItems.Clear()).AddToDisposables(_disposables);
/*IObservable<IObservable<IChangeSet<IItemViewModel, string>>?> InitSelectedsChildren()
{
var currentSelectedItemThrottled =
CurrentSelectedItem.Throttle(TimeSpan.FromMilliseconds(250)).Publish(null).RefCount();
@@ -135,16 +169,16 @@ public partial class TabViewModel : ITabViewModel
.Select(c => c.Container!.Items)
.Select(i =>
i
?.TransformAsync(MapItem)
?.TransformAsync(MapItemAsync)
.Transform(i => MapItemToViewModel(i, ItemViewModelType.SelectedChild))
.Sort(SortItems())
),
currentSelectedItemThrottled
.Where(c => c is null or not IContainerViewModel)
.Select(_ => (IObservable<IChangeSet<IItemViewModel, string>>?)null)
.Select(_ => (IObservable<IChangeSet<IItemViewModel, string>>?) null)
)
/*.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
.SubscribeOn(_rxSchedulerService.GetUIScheduler())*/
.SubscribeOn(_rxSchedulerService.GetUIScheduler())#1#
.Publish(null)
.RefCount();
}
@@ -160,35 +194,34 @@ public partial class TabViewModel : ITabViewModel
return Observable.Merge(
parentThrottled
.Where(p => p is not null)
.Select(p => Observable.FromAsync(async () => (IContainer)await p!.ResolveAsync()))
.Select(p => Observable.FromAsync(async () => (IContainer) await p!.ResolveAsync()))
.Switch()
.Select(p => p.Items)
.Select(items =>
items
?.TransformAsync(MapItem)
?.TransformAsync(MapItemAsync)
.Transform(i => MapItemToViewModel(i, ItemViewModelType.Parent))
.Sort(SortItems())
),
parentThrottled
.Where(p => p is null)
.Select(_ => (IObservable<IChangeSet<IItemViewModel, string>>?)null)
.Select(_ => (IObservable<IChangeSet<IItemViewModel, string>>?) null)
)
/*.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
.SubscribeOn(_rxSchedulerService.GetUIScheduler())*/
.SubscribeOn(_rxSchedulerService.GetUIScheduler())#1#
.Publish(null)
.RefCount();
}
}*/
}
IObservable<IReadOnlyCollection<IItemViewModel>?> InitCollection(
IObservable<IObservable<IChangeSet<IItemViewModel, string>>?> source)
{
return source
.Select(c =>
c != null ? c.ToCollection() : Observable.Return((IReadOnlyCollection<IItemViewModel>?)null))
.Switch()
.Publish(null)
.RefCount();
}
static void UpdateConsumer<T>(ObservableCollection<T>? collection, ref OcConsumer? consumer)
{
if (collection is not IComputing computing) return;
consumer?.Dispose();
consumer = new OcConsumer();
computing.For(consumer);
}
private static SortExpressionComparer<IItemViewModel> SortItems()
@@ -197,7 +230,14 @@ public partial class TabViewModel : ITabViewModel
.Ascending(i => i.BaseItem?.Type ?? AbsolutePathType.Unknown)
.ThenByAscending(i => i.DisplayNameText?.ToLower() ?? "");
private static async Task<IItem> MapItem(AbsolutePath item)
private static IItem MapItem(AbsolutePath item)
{
var t = Task.Run(async () => await MapItemAsync(item));
t.Wait();
return t.Result;
}
private static async Task<IItem> MapItemAsync(AbsolutePath item)
=> await item.ResolveAsync(forceResolve: true,
itemInitializationSettings: new ItemInitializationSettings(true));