Refactor: items with DynamicData
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using DynamicData;
|
||||||
|
|
||||||
|
namespace FileTime.App.Core.Models
|
||||||
|
{
|
||||||
|
public class BindedCollection<T> : IDisposable
|
||||||
|
{
|
||||||
|
private readonly IDisposable _disposable;
|
||||||
|
public ReadOnlyObservableCollection<T> Collection { get; }
|
||||||
|
public BindedCollection(IObservable<IChangeSet<T>> dynamicList)
|
||||||
|
{
|
||||||
|
_disposable = dynamicList
|
||||||
|
.Bind(out var collection)
|
||||||
|
.DisposeMany()
|
||||||
|
.Subscribe();
|
||||||
|
|
||||||
|
Collection = collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_disposable.Dispose();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ using InitableService;
|
|||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels
|
||||||
{
|
{
|
||||||
public interface IContainerSizeContainerViewModel : IItemViewModel, IInitable<IContainer, ITabViewModel, int>
|
public interface IContainerSizeContainerViewModel : IItemViewModel, IInitable<IContainer, ITabViewModel>
|
||||||
{
|
{
|
||||||
long Size { get; set; }
|
long Size { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using InitableService;
|
|||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels
|
||||||
{
|
{
|
||||||
public interface IContainerViewModel : IItemViewModel, IInitable<IContainer, ITabViewModel, int>
|
public interface IContainerViewModel : IItemViewModel, IInitable<IContainer, ITabViewModel>
|
||||||
{
|
{
|
||||||
IContainer? Container { get; }
|
IContainer? Container { get; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using InitableService;
|
|||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels
|
||||||
{
|
{
|
||||||
public interface IElementViewModel : IItemViewModel, IInitable<IElement, ITabViewModel, int>
|
public interface IElementViewModel : IItemViewModel, IInitable<IElement, ITabViewModel>
|
||||||
{
|
{
|
||||||
long? Size { get; set; }
|
long? Size { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ using InitableService;
|
|||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels
|
||||||
{
|
{
|
||||||
public interface IFileViewModel : IElementViewModel, IInitable<IFileElement, ITabViewModel, int>
|
public interface IFileViewModel : IElementViewModel, IInitable<IFileElement, ITabViewModel>
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using System.Reactive.Subjects;
|
|
||||||
using FileTime.App.Core.Models;
|
using FileTime.App.Core.Models;
|
||||||
using FileTime.App.Core.Models.Enums;
|
using FileTime.App.Core.Models.Enums;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
@@ -6,16 +5,17 @@ using InitableService;
|
|||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels
|
||||||
{
|
{
|
||||||
public interface IItemViewModel : IInitable<IItem, ITabViewModel, int>
|
public interface IItemViewModel : IInitable<IItem, ITabViewModel>
|
||||||
{
|
{
|
||||||
IItem? BaseItem { get; set; }
|
IItem? BaseItem { get; set; }
|
||||||
IObservable<IReadOnlyList<ItemNamePart>>? DisplayName { get; set; }
|
IObservable<IReadOnlyList<ItemNamePart>>? DisplayName { get; set; }
|
||||||
string? DisplayNameText { get; set; }
|
string? DisplayNameText { get; set; }
|
||||||
IObservable<bool>? IsSelected { get; set; }
|
IObservable<bool>? IsSelected { get; set; }
|
||||||
IObservable<bool>? IsMarked { get; set; }
|
IObservable<bool>? IsMarked { get; set; }
|
||||||
BehaviorSubject<bool> IsAlternative { get; }
|
IObservable<bool> IsAlternative { get; }
|
||||||
IObservable<ItemViewMode> ViewMode { get; set; }
|
IObservable<ItemViewMode> ViewMode { get; set; }
|
||||||
DateTime? CreatedAt { get; set; }
|
DateTime? CreatedAt { get; set; }
|
||||||
string? Attributes { get; set; }
|
string? Attributes { get; set; }
|
||||||
|
bool EqualsTo(IItemViewModel? itemViewModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
|
|
||||||
|
using DynamicData;
|
||||||
|
using FileTime.App.Core.Models;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
using InitableService;
|
using InitableService;
|
||||||
@@ -12,9 +14,13 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
IObservable<bool> IsSelected { get; }
|
IObservable<bool> IsSelected { get; }
|
||||||
IObservable<IContainer?> CurrentLocation { get; }
|
IObservable<IContainer?> CurrentLocation { get; }
|
||||||
IObservable<IItemViewModel?> CurrentSelectedItem { get; }
|
IObservable<IItemViewModel?> CurrentSelectedItem { get; }
|
||||||
IObservable<IReadOnlyList<IItemViewModel>> CurrentItems { get; }
|
IObservable<IObservable<IChangeSet<IItemViewModel>>?> CurrentItems { get; }
|
||||||
IObservable<IEnumerable<FullName>> MarkedItems { get; }
|
IObservable<IEnumerable<FullName>> MarkedItems { get; }
|
||||||
IObservable<IReadOnlyList<IItemViewModel>?> SelectedsChildren { get; }
|
IObservable<IObservable<IChangeSet<IItemViewModel>>?> SelectedsChildren { get; }
|
||||||
IObservable<IReadOnlyList<IItemViewModel>?> ParentsChildren { get; }
|
IObservable<IObservable<IChangeSet<IItemViewModel>>?> ParentsChildren { get; }
|
||||||
|
BindedCollection<IItemViewModel>? CurrentItemsCollection { get; }
|
||||||
|
BindedCollection<IItemViewModel>? SelectedsChildrenCollection { get; }
|
||||||
|
BindedCollection<IItemViewModel>? ParentsChildrenCollection { get; }
|
||||||
|
IObservable<IReadOnlyCollection<IItemViewModel>?> CurrentItemsCollectionObservable { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,7 +8,7 @@ namespace FileTime.App.Core.Extensions
|
|||||||
public static IAbsolutePath ToAbsolutePath(this IItemViewModel itemViewModel)
|
public static IAbsolutePath ToAbsolutePath(this IItemViewModel itemViewModel)
|
||||||
{
|
{
|
||||||
var item = itemViewModel.BaseItem ?? throw new ArgumentException($"{nameof(itemViewModel)} does not have {nameof(IItemViewModel.BaseItem)}");
|
var item = itemViewModel.BaseItem ?? throw new ArgumentException($"{nameof(itemViewModel)} does not have {nameof(IItemViewModel.BaseItem)}");
|
||||||
return new AbsolutePath(item.Provider, item.FullName ?? throw new ArgumentException($"Parameter does not have {nameof(IItem.FullName)}"), item.Type);
|
return new AbsolutePath(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16,6 +16,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Core\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
<ProjectReference Include="..\..\Core\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||||
<ProjectReference Include="..\..\Core\FileTime.Core.Models\FileTime.Core.Models.csproj" />
|
<ProjectReference Include="..\..\Core\FileTime.Core.Models\FileTime.Core.Models.csproj" />
|
||||||
|
<ProjectReference Include="..\..\Tools\FileTime.Tools\FileTime.Tools.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace FileTime.App.Core.Services.CommandHandler
|
|||||||
private ITabViewModel? _selectedTab;
|
private ITabViewModel? _selectedTab;
|
||||||
private IContainer? _currentLocation;
|
private IContainer? _currentLocation;
|
||||||
private IItemViewModel? _currentSelectedItem;
|
private IItemViewModel? _currentSelectedItem;
|
||||||
private List<IItemViewModel> _currentItems = new();
|
private IEnumerable<IItemViewModel> _currentItems = Enumerable.Empty<IItemViewModel>();
|
||||||
|
|
||||||
public NavigationCommandHandler(IAppState appState)
|
public NavigationCommandHandler(IAppState appState)
|
||||||
{
|
{
|
||||||
@@ -21,7 +21,7 @@ namespace FileTime.App.Core.Services.CommandHandler
|
|||||||
_appState.SelectedTab.Subscribe(t => _selectedTab = t);
|
_appState.SelectedTab.Subscribe(t => _selectedTab = t);
|
||||||
_appState.SelectedTab.Select(t => t == null ? Observable.Return<IContainer?>(null) : t.CurrentLocation).Switch().Subscribe(l => _currentLocation = l);
|
_appState.SelectedTab.Select(t => t == null ? Observable.Return<IContainer?>(null) : t.CurrentLocation).Switch().Subscribe(l => _currentLocation = l);
|
||||||
_appState.SelectedTab.Select(t => t == null ? Observable.Return<IItemViewModel?>(null) : t.CurrentSelectedItem).Switch().Subscribe(l => _currentSelectedItem = l);
|
_appState.SelectedTab.Select(t => t == null ? Observable.Return<IItemViewModel?>(null) : t.CurrentSelectedItem).Switch().Subscribe(l => _currentSelectedItem = l);
|
||||||
_appState.SelectedTab.Select(t => t == null ? Observable.Return(Enumerable.Empty<IItemViewModel>()) : t.CurrentItems).Switch().Subscribe(i => _currentItems = i.ToList());
|
_appState.SelectedTab.Select(t => t?.CurrentItemsCollectionObservable ?? Observable.Return((IEnumerable<IItemViewModel>?)Enumerable.Empty<IItemViewModel>())).Switch().Subscribe(i => _currentItems = i ?? Enumerable.Empty<IItemViewModel>());
|
||||||
|
|
||||||
AddCommandHandlers(new (Commands, Func<Task>)[]
|
AddCommandHandlers(new (Commands, Func<Task>)[]
|
||||||
{
|
{
|
||||||
@@ -48,13 +48,13 @@ namespace FileTime.App.Core.Services.CommandHandler
|
|||||||
|
|
||||||
private Task MoveCursorDown()
|
private Task MoveCursorDown()
|
||||||
{
|
{
|
||||||
SelectNewSelectedItem(i => i.SkipWhile(i => i != _currentSelectedItem).Skip(1).FirstOrDefault());
|
SelectNewSelectedItem(i => i.SkipWhile(i => i.EqualsTo(_currentSelectedItem)).Skip(1).FirstOrDefault());
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task MoveCursorUp()
|
private Task MoveCursorUp()
|
||||||
{
|
{
|
||||||
SelectNewSelectedItem(i => i.TakeWhile(i => i != _currentSelectedItem).LastOrDefault());
|
SelectNewSelectedItem(i => i.TakeWhile(i => i.EqualsTo(_currentSelectedItem)).LastOrDefault());
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
using FileTime.App.Core.Models.Enums;
|
using FileTime.App.Core.Models.Enums;
|
||||||
using FileTime.App.Core.ViewModels;
|
|
||||||
using MvvmGen;
|
using MvvmGen;
|
||||||
using MoreLinq;
|
using MoreLinq;
|
||||||
|
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init(IContainer item, ITabViewModel parentTab, int index)
|
public void Init(IContainer item, ITabViewModel parentTab)
|
||||||
{
|
{
|
||||||
Init((IItem)item, parentTab, index);
|
Init((IItem)item, parentTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,9 +13,9 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init(IContainer item, ITabViewModel parentTab, int index)
|
public void Init(IContainer item, ITabViewModel parentTab)
|
||||||
{
|
{
|
||||||
Init((IItem)item, parentTab, index);
|
Init((IItem)item, parentTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,9 +14,9 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init(IElement item, ITabViewModel parentTab, int index)
|
public void Init(IElement item, ITabViewModel parentTab)
|
||||||
{
|
{
|
||||||
Init((IItem)item, parentTab, index);
|
Init((IItem)item, parentTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,9 +11,9 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Init(IFileElement item, ITabViewModel parentTab, int index)
|
public void Init(IFileElement item, ITabViewModel parentTab)
|
||||||
{
|
{
|
||||||
Init((IElement)item, parentTab, index);
|
Init((IElement)item, parentTab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
|
||||||
using FileTime.App.Core.Models;
|
using FileTime.App.Core.Models;
|
||||||
using FileTime.App.Core.Models.Enums;
|
using FileTime.App.Core.Models.Enums;
|
||||||
using FileTime.App.Core.Services;
|
using FileTime.App.Core.Services;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
using MoreLinq;
|
||||||
using MvvmGen;
|
using MvvmGen;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels
|
||||||
@@ -38,16 +38,16 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
private string? _attributes;
|
private string? _attributes;
|
||||||
|
|
||||||
[Property]
|
[Property]
|
||||||
private BehaviorSubject<bool> _isAlternative = new(false);
|
private IObservable<bool> _isAlternative;
|
||||||
|
|
||||||
public void Init(IItem item, ITabViewModel parentTab, int index)
|
public void Init(IItem item, ITabViewModel parentTab)
|
||||||
{
|
{
|
||||||
BaseItem = item;
|
BaseItem = item;
|
||||||
DisplayName = _appState.SearchText.Select(s => _itemNameConverterService.GetDisplayName(item.DisplayName, s));
|
DisplayName = _appState.SearchText.Select(s => _itemNameConverterService.GetDisplayName(item.DisplayName, s));
|
||||||
DisplayNameText = item.DisplayName;
|
DisplayNameText = item.DisplayName;
|
||||||
IsMarked = parentTab.MarkedItems.Select(m => m.Contains(item.FullName));
|
IsMarked = parentTab.MarkedItems.Select(m => m.Contains(item.FullName));
|
||||||
IsSelected = parentTab.CurrentSelectedItem.Select(i => i == this);
|
IsSelected = parentTab.CurrentSelectedItem.Select(EqualsTo);
|
||||||
IsAlternative.OnNext(index % 2 == 0);
|
IsAlternative = parentTab.CurrentItemsCollectionObservable.Select(c => c?.Index().FirstOrDefault(i => EqualsTo(i.Value)).Key % 2 == 0);
|
||||||
ViewMode = Observable.CombineLatest(IsMarked, IsSelected, IsAlternative, GenerateViewMode);
|
ViewMode = Observable.CombineLatest(IsMarked, IsSelected, IsAlternative, GenerateViewMode);
|
||||||
Attributes = item.Attributes;
|
Attributes = item.Attributes;
|
||||||
CreatedAt = item.CreatedAt;
|
CreatedAt = item.CreatedAt;
|
||||||
@@ -63,5 +63,10 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
(true, false, false) => ItemViewMode.Marked,
|
(true, false, false) => ItemViewMode.Marked,
|
||||||
_ => ItemViewMode.Default
|
_ => ItemViewMode.Default
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public bool EqualsTo(IItemViewModel? itemViewModel)
|
||||||
|
{
|
||||||
|
return BaseItem?.FullName?.Path is string path && path == itemViewModel?.BaseItem?.FullName?.Path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,15 +1,19 @@
|
|||||||
using System.Reactive.Concurrency;
|
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
|
using DynamicData;
|
||||||
using FileTime.App.Core.Extensions;
|
using FileTime.App.Core.Extensions;
|
||||||
|
using FileTime.App.Core.Models;
|
||||||
using FileTime.App.Core.Services;
|
using FileTime.App.Core.Services;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
|
using FileTime.Tools.Extensions;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using MvvmGen;
|
||||||
|
|
||||||
namespace FileTime.App.Core.ViewModels
|
namespace FileTime.App.Core.ViewModels
|
||||||
{
|
{
|
||||||
public class TabViewModel : ITabViewModel, IDisposable
|
[ViewModel]
|
||||||
|
public partial class TabViewModel : ITabViewModel, IDisposable
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly IItemNameConverterService _itemNameConverterService;
|
private readonly IItemNameConverterService _itemNameConverterService;
|
||||||
@@ -26,10 +30,22 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
|
|
||||||
public IObservable<IContainer?> CurrentLocation { get; private set; } = null!;
|
public IObservable<IContainer?> CurrentLocation { get; private set; } = null!;
|
||||||
public IObservable<IItemViewModel?> CurrentSelectedItem { get; private set; } = null!;
|
public IObservable<IItemViewModel?> CurrentSelectedItem { get; private set; } = null!;
|
||||||
public IObservable<IReadOnlyList<IItemViewModel>> CurrentItems { get; private set; } = null!;
|
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> CurrentItems { get; private set; } = null!;
|
||||||
public IObservable<IEnumerable<FullName>> MarkedItems { get; }
|
public IObservable<IEnumerable<FullName>> MarkedItems { get; }
|
||||||
public IObservable<IReadOnlyList<IItemViewModel>?> SelectedsChildren { get; private set; } = null!;
|
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> SelectedsChildren { get; private set; } = null!;
|
||||||
public IObservable<IReadOnlyList<IItemViewModel>?> ParentsChildren { get; private set; } = null!;
|
public IObservable<IObservable<IChangeSet<IItemViewModel>>?> ParentsChildren { get; private set; } = null!;
|
||||||
|
|
||||||
|
public IObservable<IReadOnlyCollection<IItemViewModel>?> CurrentItemsCollectionObservable { get; private set; } = null!;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private BindedCollection<IItemViewModel>? _currentItemsCollection;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private BindedCollection<IItemViewModel>? _parentsChildrenCollection;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private BindedCollection<IItemViewModel>? _selectedsChildrenCollection;
|
||||||
|
|
||||||
|
|
||||||
public TabViewModel(
|
public TabViewModel(
|
||||||
IServiceProvider serviceProvider,
|
IServiceProvider serviceProvider,
|
||||||
@@ -53,100 +69,125 @@ namespace FileTime.App.Core.ViewModels
|
|||||||
|
|
||||||
CurrentLocation = tab.CurrentLocation.AsObservable();
|
CurrentLocation = tab.CurrentLocation.AsObservable();
|
||||||
CurrentItems = tab.CurrentItems
|
CurrentItems = tab.CurrentItems
|
||||||
.Select(items =>
|
.Select(items => items?.Transform(MapItemToViewModel))
|
||||||
items == null
|
|
||||||
? new List<IItemViewModel>()
|
|
||||||
: items.Select(MapItemToViewModel).ToList())
|
|
||||||
.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
||||||
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
||||||
.Publish(new List<IItemViewModel>())
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
CurrentSelectedItem =
|
CurrentSelectedItem =
|
||||||
Observable.CombineLatest(
|
Observable.CombineLatest(
|
||||||
CurrentItems,
|
CurrentItems,
|
||||||
tab.CurrentSelectedItem,
|
tab.CurrentSelectedItem,
|
||||||
(currentItems, currentSelectedItemPath) => currentItems.FirstOrDefault(i => i.BaseItem?.FullName == currentSelectedItemPath?.Path)
|
(currentItems, currentSelectedItemPath) =>
|
||||||
|
currentItems == null
|
||||||
|
? Observable.Return((IItemViewModel?)null)
|
||||||
|
: currentItems
|
||||||
|
.ToCollection()
|
||||||
|
.Select(items => items.FirstOrDefault(i => i.BaseItem?.FullName == currentSelectedItemPath?.Path))
|
||||||
)
|
)
|
||||||
|
.Switch()
|
||||||
.Publish(null)
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
|
SelectedsChildren = InitSelectedsChildren();
|
||||||
|
ParentsChildren = InitParentsChildren();
|
||||||
|
|
||||||
|
CurrentItemsCollectionObservable = CurrentItems
|
||||||
|
.Select(c => c != null ? c.ToCollection() : Observable.Return((IReadOnlyCollection<IItemViewModel>?)null))
|
||||||
|
.Switch()
|
||||||
|
.Publish(null)
|
||||||
|
.RefCount();
|
||||||
|
|
||||||
|
CurrentItems.Subscribe(children =>
|
||||||
|
{
|
||||||
|
CurrentItemsCollection?.Dispose();
|
||||||
|
CurrentItemsCollection = children.MapNull(c => new BindedCollection<IItemViewModel>(c!));
|
||||||
|
});
|
||||||
|
|
||||||
|
ParentsChildren.Subscribe(children =>
|
||||||
|
{
|
||||||
|
ParentsChildrenCollection?.Dispose();
|
||||||
|
ParentsChildrenCollection = children.MapNull(c => new BindedCollection<IItemViewModel>(c!));
|
||||||
|
});
|
||||||
|
|
||||||
|
SelectedsChildren.Subscribe(children =>
|
||||||
|
{
|
||||||
|
SelectedsChildrenCollection?.Dispose();
|
||||||
|
SelectedsChildrenCollection = children.MapNull(c => new BindedCollection<IItemViewModel>(c!));
|
||||||
|
});
|
||||||
|
|
||||||
|
tab.CurrentLocation.Subscribe((_) => _markedItems.OnNext(Enumerable.Empty<FullName>()));
|
||||||
|
|
||||||
|
IObservable<IObservable<IChangeSet<IItemViewModel>>?> InitSelectedsChildren()
|
||||||
|
{
|
||||||
var currentSelectedItemThrottled = CurrentSelectedItem.Throttle(TimeSpan.FromMilliseconds(250)).Publish(null).RefCount();
|
var currentSelectedItemThrottled = CurrentSelectedItem.Throttle(TimeSpan.FromMilliseconds(250)).Publish(null).RefCount();
|
||||||
SelectedsChildren = Observable.Merge(
|
return Observable.Merge(
|
||||||
currentSelectedItemThrottled
|
currentSelectedItemThrottled
|
||||||
.WhereNotNull()
|
.WhereNotNull()
|
||||||
.OfType<IContainerViewModel>()
|
.OfType<IContainerViewModel>()
|
||||||
.Where(c => c?.Container is not null)
|
.Where(c => c?.Container is not null)
|
||||||
.Select(c => c.Container!.Items)
|
.Select(c => c.Container!.Items)
|
||||||
.Switch()
|
.Switch()
|
||||||
.Select(items => Observable.FromAsync(async () => await Map(items)))
|
.Select(i => i?.TransformAsync(MapItem).Transform(MapItemToViewModel)),
|
||||||
.Switch()
|
|
||||||
.Select(items => items?.Select(MapItemToViewModel).ToList()),
|
|
||||||
currentSelectedItemThrottled
|
currentSelectedItemThrottled
|
||||||
.Where(c => c is null || c is not IContainerViewModel)
|
.Where(c => c is null || c is not IContainerViewModel)
|
||||||
.Select(_ => (IReadOnlyList<IItemViewModel>?)null)
|
.Select(_ => (IObservable<IChangeSet<IItemViewModel>>?)null)
|
||||||
)
|
)
|
||||||
.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
||||||
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
||||||
.Publish(null)
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
IObservable<IObservable<IChangeSet<IItemViewModel>>?> InitParentsChildren()
|
||||||
|
{
|
||||||
var parentThrottled = CurrentLocation
|
var parentThrottled = CurrentLocation
|
||||||
.Select(l => l?.Parent)
|
.Select(l => l?.Parent)
|
||||||
.DistinctUntilChanged()
|
.DistinctUntilChanged()
|
||||||
.Publish(null)
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
ParentsChildren = Observable.Merge(
|
return Observable.Merge(
|
||||||
parentThrottled
|
parentThrottled
|
||||||
.Where(p => p is not null)
|
.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()
|
.Switch()
|
||||||
.Select(p => p.Items)
|
.Select(p => p.Items)
|
||||||
.Switch()
|
.Switch()
|
||||||
.Select(items => Observable.FromAsync(async () => await Map(items)))
|
.Select(items => items?.TransformAsync(MapItem).Transform(MapItemToViewModel)),
|
||||||
.Switch()
|
|
||||||
.Select(items => items?.Select(MapItemToViewModel).ToList()),
|
|
||||||
parentThrottled
|
parentThrottled
|
||||||
.Where(p => p is null)
|
.Where(p => p is null)
|
||||||
.Select(_ => (IReadOnlyList<IItemViewModel>?)null)
|
.Select(_ => (IObservable<IChangeSet<IItemViewModel>>?)null)
|
||||||
)
|
)
|
||||||
.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
||||||
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
.SubscribeOn(_rxSchedulerService.GetUIScheduler())
|
||||||
.Publish(null)
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
tab.CurrentLocation.Subscribe((_) => _markedItems.OnNext(Enumerable.Empty<FullName>()));
|
|
||||||
|
|
||||||
static async Task<List<IItem>?> Map(IEnumerable<IAbsolutePath>? items)
|
|
||||||
{
|
|
||||||
if (items == null) return null;
|
|
||||||
|
|
||||||
return await items
|
|
||||||
.ToAsyncEnumerable()
|
|
||||||
.SelectAwait(async i => await i.ResolveAsync(forceResolve: true, itemInitializationSettings: new ItemInitializationSettings(true)))
|
|
||||||
.ToListAsync();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IItemViewModel MapItemToViewModel(IItem item, int index)
|
private static async Task<IItem> MapItem(IAbsolutePath item)
|
||||||
|
=> await item.ResolveAsync(forceResolve: true, itemInitializationSettings: new ItemInitializationSettings(true));
|
||||||
|
|
||||||
|
private IItemViewModel MapItemToViewModel(IItem item)
|
||||||
{
|
{
|
||||||
if (item is IContainer container)
|
if (item is IContainer container)
|
||||||
{
|
{
|
||||||
var containerViewModel = _serviceProvider.GetInitableResolver<IContainer, ITabViewModel, int>(container, this, index).GetRequiredService<IContainerViewModel>();
|
var containerViewModel = _serviceProvider.GetInitableResolver<IContainer, ITabViewModel>(container, this).GetRequiredService<IContainerViewModel>();
|
||||||
|
|
||||||
return containerViewModel;
|
return containerViewModel;
|
||||||
}
|
}
|
||||||
else if (item is IFileElement fileElement)
|
else if (item is IFileElement fileElement)
|
||||||
{
|
{
|
||||||
var fileViewModel = _serviceProvider.GetInitableResolver<IFileElement, ITabViewModel, int>(fileElement, this, index).GetRequiredService<IFileViewModel>();
|
var fileViewModel = _serviceProvider.GetInitableResolver<IFileElement, ITabViewModel>(fileElement, this).GetRequiredService<IFileViewModel>();
|
||||||
fileViewModel.Size = fileElement.Size;
|
fileViewModel.Size = fileElement.Size;
|
||||||
|
|
||||||
return fileViewModel;
|
return fileViewModel;
|
||||||
}
|
}
|
||||||
else if (item is IElement element)
|
else if (item is IElement element)
|
||||||
{
|
{
|
||||||
var elementViewModel = _serviceProvider.GetInitableResolver<IElement, ITabViewModel, int>(element, this, index).GetRequiredService<IElementViewModel>();
|
var elementViewModel = _serviceProvider.GetInitableResolver<IElement, ITabViewModel>(element, this).GetRequiredService<IElementViewModel>();
|
||||||
|
|
||||||
return elementViewModel;
|
return elementViewModel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="DynamicData" Version="7.6.7" />
|
||||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
using DynamicData;
|
||||||
|
|
||||||
namespace FileTime.Core.Models
|
namespace FileTime.Core.Models
|
||||||
{
|
{
|
||||||
public interface IContainer : IItem
|
public interface IContainer : IItem
|
||||||
{
|
{
|
||||||
IObservable<IEnumerable<IAbsolutePath>?> Items { get; }
|
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> Items { get; }
|
||||||
IObservable<bool> IsLoading { get; }
|
IObservable<bool> IsLoading { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using DynamicData;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using InitableService;
|
using InitableService;
|
||||||
|
|
||||||
@@ -7,7 +8,7 @@ namespace FileTime.Core.Services
|
|||||||
{
|
{
|
||||||
IObservable<IContainer?> CurrentLocation { get; }
|
IObservable<IContainer?> CurrentLocation { get; }
|
||||||
IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
|
IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
|
||||||
IObservable<IEnumerable<IItem>?> CurrentItems { get; }
|
IObservable<IObservable<IChangeSet<IItem>>?> CurrentItems { get; }
|
||||||
|
|
||||||
void SetCurrentLocation(IContainer newLocation);
|
void SetCurrentLocation(IContainer newLocation);
|
||||||
void AddSelectedItemsTransformator(ItemsTransformator transformator);
|
void AddSelectedItemsTransformator(ItemsTransformator transformator);
|
||||||
|
|||||||
@@ -19,6 +19,14 @@ namespace FileTime.Core.Models
|
|||||||
Type = type;
|
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)
|
public async Task<IItem> ResolveAsync(bool forceResolve = false, ItemInitializationSettings itemInitializationSettings = default)
|
||||||
{
|
{
|
||||||
var provider = VirtualContentProvider ?? ContentProvider;
|
var provider = VirtualContentProvider ?? ContentProvider;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
|
using DynamicData;
|
||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
|
|
||||||
@@ -19,7 +20,7 @@ namespace FileTime.Core.Models
|
|||||||
string? Attributes,
|
string? Attributes,
|
||||||
IContentProvider Provider,
|
IContentProvider Provider,
|
||||||
IObservable<IEnumerable<Exception>> Exceptions,
|
IObservable<IEnumerable<Exception>> Exceptions,
|
||||||
IObservable<IEnumerable<IAbsolutePath>?> Items) : IContainer
|
IObservable<IObservable<IChangeSet<IAbsolutePath>>?> Items) : IContainer
|
||||||
{
|
{
|
||||||
BehaviorSubject<bool> IsLoading { get; } = new BehaviorSubject<bool>(false);
|
BehaviorSubject<bool> IsLoading { get; } = new BehaviorSubject<bool>(false);
|
||||||
IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable();
|
IObservable<bool> IContainer.IsLoading => IsLoading.AsObservable();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
|
using DynamicData;
|
||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
@@ -7,9 +8,9 @@ namespace FileTime.Core.Services
|
|||||||
{
|
{
|
||||||
public abstract class ContentProviderBase : IContentProvider
|
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; }
|
public string Name { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Tools\FileTime.Tools\FileTime.Tools.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
<ProjectReference Include="..\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||||
<ProjectReference Include="..\FileTime.Core.Models\FileTime.Core.Models.csproj" />
|
<ProjectReference Include="..\FileTime.Core.Models\FileTime.Core.Models.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
|
using DynamicData;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.Core.Services
|
namespace FileTime.Core.Services
|
||||||
@@ -10,8 +11,9 @@ namespace FileTime.Core.Services
|
|||||||
private readonly BehaviorSubject<IAbsolutePath?> _currentSelectedItem = new(null);
|
private readonly BehaviorSubject<IAbsolutePath?> _currentSelectedItem = new(null);
|
||||||
private readonly List<ItemsTransformator> _transformators = new();
|
private readonly List<ItemsTransformator> _transformators = new();
|
||||||
private IAbsolutePath? _currentSelectedItemCached;
|
private IAbsolutePath? _currentSelectedItemCached;
|
||||||
|
|
||||||
public IObservable<IContainer?> CurrentLocation { get; }
|
public IObservable<IContainer?> CurrentLocation { get; }
|
||||||
public IObservable<IEnumerable<IItem>?> CurrentItems { get; }
|
public IObservable<IObservable<IChangeSet<IItem>>?> CurrentItems { get; }
|
||||||
public IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
|
public IObservable<IAbsolutePath?> CurrentSelectedItem { get; }
|
||||||
|
|
||||||
public Tab()
|
public Tab()
|
||||||
@@ -23,53 +25,54 @@ namespace FileTime.Core.Services
|
|||||||
.Where(c => c is not null)
|
.Where(c => c is not null)
|
||||||
.Select(c => c!.Items)
|
.Select(c => c!.Items)
|
||||||
.Switch()
|
.Switch()
|
||||||
.Select(i => i == null ? Observable.Return<IEnumerable<IItem>?>(null) : Observable.FromAsync(async () => await MapItems(i)))
|
.Select(items => items?.TransformAsync(MapItem)),
|
||||||
.Switch(),
|
|
||||||
CurrentLocation
|
CurrentLocation
|
||||||
.Where(c => c is null)
|
.Where(c => c is null)
|
||||||
.Select(_ => Enumerable.Empty<IItem>())
|
.Select(_ => (IObservable<IChangeSet<IItem>>?)null)
|
||||||
)
|
)
|
||||||
.Publish(Enumerable.Empty<IItem>())
|
.Publish((IObservable<IChangeSet<IItem>>?)null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
CurrentSelectedItem = CurrentLocation
|
CurrentSelectedItem =
|
||||||
.Select(GetSelectedItemByLocation)
|
Observable.CombineLatest(
|
||||||
.Switch()
|
CurrentItems
|
||||||
.Merge(_currentSelectedItem)
|
.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()
|
.DistinctUntilChanged()
|
||||||
.Publish(null)
|
.Publish(null)
|
||||||
.RefCount();
|
.RefCount();
|
||||||
|
|
||||||
CurrentSelectedItem.Subscribe(s => _currentSelectedItemCached = s);
|
CurrentSelectedItem.Subscribe(s =>
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<IEnumerable<IItem>> MapItems(IEnumerable<IAbsolutePath> items)
|
|
||||||
{
|
{
|
||||||
IEnumerable<IItem> resolvedItems = await items
|
_currentSelectedItemCached = s;
|
||||||
.ToAsyncEnumerable()
|
_currentSelectedItem.OnNext(s);
|
||||||
.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)
|
public void Init(IContainer currentLocation)
|
||||||
{
|
{
|
||||||
_currentLocation.OnNext(currentLocation);
|
_currentLocation.OnNext(currentLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IObservable<IAbsolutePath?> GetSelectedItemByLocation(IContainer? currentLocation)
|
private static IAbsolutePath? GetSelectedItemByItems(IEnumerable<IItem> items)
|
||||||
{
|
{
|
||||||
//TODO:
|
//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);
|
public void SetCurrentLocation(IContainer newLocation) => _currentLocation.OnNext(newLocation);
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.Providers.Local.Ab
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.GuiApp.Abstractions", "GuiApp\Avalonia\FileTime.GuiApp.Abstractions\FileTime.GuiApp.Abstractions.csproj", "{D7D1C76A-05B0-49BC-BCFF-06340E264EC1}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.GuiApp.Abstractions", "GuiApp\Avalonia\FileTime.GuiApp.Abstractions\FileTime.GuiApp.Abstractions.csproj", "{D7D1C76A-05B0-49BC-BCFF-06340E264EC1}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{8C3CFEFE-78A5-4940-B388-D15FCE02ECE9}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Tools", "Tools\FileTime.Tools\FileTime.Tools.csproj", "{B7A45654-E56C-43C8-998E-0F4661395540}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -113,6 +117,10 @@ Global
|
|||||||
{D7D1C76A-05B0-49BC-BCFF-06340E264EC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D7D1C76A-05B0-49BC-BCFF-06340E264EC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D7D1C76A-05B0-49BC-BCFF-06340E264EC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D7D1C76A-05B0-49BC-BCFF-06340E264EC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{D7D1C76A-05B0-49BC-BCFF-06340E264EC1}.Release|Any CPU.Build.0 = Release|Any CPU
|
{D7D1C76A-05B0-49BC-BCFF-06340E264EC1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B7A45654-E56C-43C8-998E-0F4661395540}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B7A45654-E56C-43C8-998E-0F4661395540}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B7A45654-E56C-43C8-998E-0F4661395540}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B7A45654-E56C-43C8-998E-0F4661395540}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@@ -134,6 +142,7 @@ Global
|
|||||||
{4B742649-225F-4C73-B118-1B29FE2A5774} = {01F231DE-4A65-435F-B4BB-77EE5221890C}
|
{4B742649-225F-4C73-B118-1B29FE2A5774} = {01F231DE-4A65-435F-B4BB-77EE5221890C}
|
||||||
{1500A537-2116-4111-B216-7632040619B0} = {2FC40FE1-4446-44AB-BF77-00F94D995FA3}
|
{1500A537-2116-4111-B216-7632040619B0} = {2FC40FE1-4446-44AB-BF77-00F94D995FA3}
|
||||||
{D7D1C76A-05B0-49BC-BCFF-06340E264EC1} = {01F231DE-4A65-435F-B4BB-77EE5221890C}
|
{D7D1C76A-05B0-49BC-BCFF-06340E264EC1} = {01F231DE-4A65-435F-B4BB-77EE5221890C}
|
||||||
|
{B7A45654-E56C-43C8-998E-0F4661395540} = {8C3CFEFE-78A5-4940-B388-D15FCE02ECE9}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {859FB3DF-C60A-46B1-82E5-90274905D1EF}
|
SolutionGuid = {859FB3DF-C60A-46B1-82E5-90274905D1EF}
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
AutoScrollToSelectedItem="True"
|
AutoScrollToSelectedItem="True"
|
||||||
Classes="ContentListView"
|
Classes="ContentListView"
|
||||||
IsTabStop="True"
|
IsTabStop="True"
|
||||||
Items="{Binding AppState.SelectedTab^.ParentsChildren^}"
|
Items="{Binding AppState.SelectedTab^.ParentsChildrenCollection.Collection}"
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
|
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
|
||||||
ScrollViewer.VerticalScrollBarVisibility="Visible">
|
ScrollViewer.VerticalScrollBarVisibility="Visible">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
@@ -146,7 +146,7 @@
|
|||||||
AutoScrollToSelectedItem="True"
|
AutoScrollToSelectedItem="True"
|
||||||
Classes="ContentListView"
|
Classes="ContentListView"
|
||||||
IsTabStop="True"
|
IsTabStop="True"
|
||||||
Items="{Binding AppState.SelectedTab^.CurrentItems^}"
|
Items="{Binding AppState.SelectedTab^.CurrentItemsCollection.Collection}"
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
|
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
|
||||||
ScrollViewer.VerticalScrollBarVisibility="Visible">
|
ScrollViewer.VerticalScrollBarVisibility="Visible">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
@@ -166,7 +166,7 @@
|
|||||||
x:CompileBindings="False"
|
x:CompileBindings="False"
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
Foreground="{DynamicResource ErrorBrush}"
|
Foreground="{DynamicResource ErrorBrush}"
|
||||||
IsVisible="{Binding AppState.SelectedTab^.CurrentLocation^.Items^.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
|
IsVisible="{Binding AppState.SelectedTab^.CurrentItemsCollection.Collection.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
|
||||||
Empty
|
Empty
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</Grid>
|
</Grid>
|
||||||
@@ -180,14 +180,14 @@
|
|||||||
Fill="{DynamicResource ContentSeparatorBrush}" />
|
Fill="{DynamicResource ContentSeparatorBrush}" />
|
||||||
|
|
||||||
<Grid Grid.Column="4">
|
<Grid Grid.Column="4">
|
||||||
<Grid IsVisible="{Binding AppState.SelectedTab^.SelectedsChildren^, Converter={x:Static ObjectConverters.IsNotNull}}">
|
<Grid IsVisible="{Binding AppState.SelectedTab^.SelectedsChildrenCollection.Collection, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
<ListBox
|
<ListBox
|
||||||
x:Name="ChildItems"
|
x:Name="ChildItems"
|
||||||
x:CompileBindings="False"
|
x:CompileBindings="False"
|
||||||
AutoScrollToSelectedItem="True"
|
AutoScrollToSelectedItem="True"
|
||||||
Classes="ContentListView"
|
Classes="ContentListView"
|
||||||
IsVisible="{Binding AppState.SelectedTab^.SelectedsChildren^.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}"
|
IsVisible="{Binding AppState.SelectedTab^.SelectedsChildrenCollection.Collection.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}"
|
||||||
Items="{Binding AppState.SelectedTab^.SelectedsChildren^}">
|
Items="{Binding AppState.SelectedTab^.SelectedsChildrenCollection.Collection}">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate x:DataType="corevm:IItemViewModel">
|
<DataTemplate x:DataType="corevm:IItemViewModel">
|
||||||
<local:ItemView />
|
<local:ItemView />
|
||||||
@@ -202,13 +202,13 @@
|
|||||||
x:CompileBindings="False"
|
x:CompileBindings="False"
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
Foreground="{DynamicResource ErrorBrush}"
|
Foreground="{DynamicResource ErrorBrush}"
|
||||||
IsVisible="{Binding AppState.SelectedTab^.SelectedsChildren^.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
|
IsVisible="{Binding AppState.SelectedTab^.SelectedsChildrenCollection.Collection.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
|
||||||
Empty
|
Empty
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
IsVisible="{Binding AppState.SelectedTab^.SelectedsChildren^, Converter={x:Static ObjectConverters.IsNull}, ConverterParameter=0}"
|
IsVisible="{Binding AppState.SelectedTab^.SelectedsChildrenCollection, Converter={x:Static ObjectConverters.IsNull}, ConverterParameter=0}"
|
||||||
RowDefinitions="Auto, Auto">
|
RowDefinitions="Auto, Auto">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="0,0,0,10"
|
Margin="0,0,0,10"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="DynamicData" Version="7.6.7" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,24 @@
|
|||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
using DynamicData;
|
||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Services;
|
using FileTime.Core.Services;
|
||||||
|
|
||||||
namespace FileTime.Providers.Local
|
namespace FileTime.Providers.Local
|
||||||
{
|
{
|
||||||
public partial class LocalContentProvider : ContentProviderBase, ILocalContentProvider
|
public sealed partial class LocalContentProvider : ContentProviderBase, ILocalContentProvider
|
||||||
{
|
{
|
||||||
protected bool IsCaseInsensitive { get; init; }
|
private readonly SourceList<IAbsolutePath> _rootDirectories = new();
|
||||||
|
private readonly bool _isCaseInsensitive;
|
||||||
public LocalContentProvider() : base("local")
|
public LocalContentProvider() : base("local")
|
||||||
{
|
{
|
||||||
IsCaseInsensitive = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
_isCaseInsensitive = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
|
|
||||||
RefreshRootDirectories();
|
RefreshRootDirectories();
|
||||||
|
|
||||||
|
Items.OnNext(_rootDirectories.Connect());
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task OnEnter()
|
public override Task OnEnter()
|
||||||
@@ -29,7 +34,11 @@ namespace FileTime.Providers.Local
|
|||||||
? new DirectoryInfo("/").GetDirectories()
|
? new DirectoryInfo("/").GetDirectories()
|
||||||
: Environment.GetLogicalDrives().Select(d => new DirectoryInfo(d));
|
: Environment.GetLogicalDrives().Select(d => new DirectoryInfo(d));
|
||||||
|
|
||||||
Items.OnNext(rootDirectories.Select(DirectoryToAbsolutePath).ToList());
|
_rootDirectories.Edit(actions =>
|
||||||
|
{
|
||||||
|
actions.Clear();
|
||||||
|
actions.AddRange(rootDirectories.Select(DirectoryToAbsolutePath));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<IItem> GetItemByNativePathAsync(
|
public override Task<IItem> GetItemByNativePathAsync(
|
||||||
@@ -108,7 +117,7 @@ namespace FileTime.Providers.Local
|
|||||||
"???",
|
"???",
|
||||||
this,
|
this,
|
||||||
nonNullExceptions,
|
nonNullExceptions,
|
||||||
Observable.Return<IEnumerable<IAbsolutePath>?>(null)
|
Observable.Return<IObservable<IChangeSet<IAbsolutePath>>?>(null)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,19 +169,24 @@ namespace FileTime.Providers.Local
|
|||||||
Observable.FromAsync(async () => await Task.Run(InitChildren))
|
Observable.FromAsync(async () => await Task.Run(InitChildren))
|
||||||
);
|
);
|
||||||
|
|
||||||
Task<List<IAbsolutePath>?> InitChildren()
|
Task<IObservable<IChangeSet<IAbsolutePath>>?> InitChildren()
|
||||||
{
|
{
|
||||||
List<IAbsolutePath>? result = null;
|
SourceList<IAbsolutePath>? result = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
result = initializeChildren ? (List<IAbsolutePath>?)GetItemsByContainer(directoryInfo) : null;
|
var items = initializeChildren ? (List<IAbsolutePath>?)GetItemsByContainer(directoryInfo) : null;
|
||||||
|
if (items != null)
|
||||||
|
{
|
||||||
|
result = new SourceList<IAbsolutePath>();
|
||||||
|
result.AddRange(items);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
exceptions.OnNext(new List<Exception>() { e });
|
exceptions.OnNext(new List<Exception>() { e });
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(result);
|
return Task.FromResult(result?.Connect());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
11
src/Tools/FileTime.Tools/Extensions/ObjectExtensions.cs
Normal file
11
src/Tools/FileTime.Tools/Extensions/ObjectExtensions.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
namespace FileTime.Tools.Extensions
|
||||||
|
{
|
||||||
|
public static class ObjectExtensions
|
||||||
|
{
|
||||||
|
public static TResult? MapNull<T, TResult>(this T obj, Func<TResult?> nullHandler, Func<T, TResult?> valueHandler)
|
||||||
|
=> obj == null ? nullHandler() : valueHandler(obj);
|
||||||
|
|
||||||
|
public static TResult? MapNull<T, TResult>(this T obj, Func<T, TResult?> valueHandler)
|
||||||
|
=> obj == null ? default : valueHandler(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/Tools/FileTime.Tools/FileTime.Tools.csproj
Normal file
9
src/Tools/FileTime.Tools/FileTime.Tools.csproj
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user