diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/Models/Enums/ItemViewModelType.cs b/src/AppCommon/FileTime.App.Core.Abstraction/Models/Enums/ItemViewModelType.cs new file mode 100644 index 0000000..9f549d1 --- /dev/null +++ b/src/AppCommon/FileTime.App.Core.Abstraction/Models/Enums/ItemViewModelType.cs @@ -0,0 +1,8 @@ +namespace FileTime.App.Core.Models.Enums; + +public enum ItemViewModelType +{ + Main, + SelectedChild, + Parent +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerSizeContainerViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerSizeContainerViewModel.cs index 7d95dbb..fef5745 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerSizeContainerViewModel.cs +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerSizeContainerViewModel.cs @@ -1,9 +1,10 @@ +using FileTime.App.Core.Models.Enums; using FileTime.Core.Models; using InitableService; namespace FileTime.App.Core.ViewModels; -public interface IContainerSizeContainerViewModel : IItemViewModel, IInitable +public interface IContainerSizeContainerViewModel : IItemViewModel, IInitable { long Size { get; set; } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerViewModel.cs index 387d7f1..5f2f464 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerViewModel.cs +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IContainerViewModel.cs @@ -1,9 +1,10 @@ +using FileTime.App.Core.Models.Enums; using FileTime.Core.Models; using InitableService; namespace FileTime.App.Core.ViewModels; -public interface IContainerViewModel : IItemViewModel, IInitable +public interface IContainerViewModel : IItemViewModel, IInitable { IContainer? Container { get; } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IElementViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IElementViewModel.cs index 5ea0814..504e3e1 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IElementViewModel.cs +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IElementViewModel.cs @@ -1,9 +1,10 @@ +using FileTime.App.Core.Models.Enums; using FileTime.Core.Models; using InitableService; namespace FileTime.App.Core.ViewModels; -public interface IElementViewModel : IItemViewModel, IInitable +public interface IElementViewModel : IItemViewModel, IInitable { long? Size { get; set; } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IFileViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IFileViewModel.cs index e3f0c0f..2ce77df 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IFileViewModel.cs +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IFileViewModel.cs @@ -1,8 +1,9 @@ +using FileTime.App.Core.Models.Enums; using FileTime.Core.Models; using InitableService; namespace FileTime.App.Core.ViewModels; -public interface IFileViewModel : IElementViewModel, IInitable +public interface IFileViewModel : IElementViewModel, IInitable { } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IItemViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IItemViewModel.cs index 15daeae..3f373e1 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IItemViewModel.cs +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/IItemViewModel.cs @@ -5,7 +5,7 @@ using InitableService; namespace FileTime.App.Core.ViewModels; -public interface IItemViewModel : IInitable +public interface IItemViewModel : IInitable { IItem? BaseItem { get; set; } IObservable>? DisplayName { get; set; } diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/ITabViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/ITabViewModel.cs index be498e7..65ae0b1 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/ITabViewModel.cs +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/ITabViewModel.cs @@ -22,6 +22,8 @@ public interface ITabViewModel : IInitable BindedCollection? SelectedsChildrenCollection { get; } BindedCollection? ParentsChildrenCollection { get; } IObservable?> CurrentItemsCollectionObservable { get; } + IObservable?> ParentsChildrenCollectionObservable { get; } + IObservable?> SelectedsChildrenCollectionObservable { get; } void ClearMarkedItems(); void RemoveMarkedItem(IAbsolutePath item); void AddMarkedItem(IAbsolutePath item); diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/ContainerSizeContainerViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/ContainerSizeContainerViewModel.cs index 66eb239..1d37c43 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/ContainerSizeContainerViewModel.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/ContainerSizeContainerViewModel.cs @@ -1,3 +1,4 @@ +using FileTime.App.Core.Models.Enums; using FileTime.App.Core.Services; using FileTime.Core.Models; using MvvmGen; @@ -10,12 +11,12 @@ public partial class ContainerSizeContainerViewModel : ItemViewModel, IContainer [Property] private long _size; - public ContainerSizeContainerViewModel(IItemNameConverterService _itemNameConverterService, IAppState _appState) : base(_itemNameConverterService, _appState) + public ContainerSizeContainerViewModel(IItemNameConverterService itemNameConverterService, IAppState appState) : base(itemNameConverterService, appState) { } - public void Init(IContainer item, ITabViewModel parentTab) + public void Init(IContainer item, ITabViewModel parentTab, ItemViewModelType itemViewModelType) { - Init((IItem)item, parentTab); + Init((IItem)item, parentTab, itemViewModelType); } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/ContainerViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/ContainerViewModel.cs index d793d28..593289a 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/ContainerViewModel.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/ContainerViewModel.cs @@ -1,3 +1,4 @@ +using FileTime.App.Core.Models.Enums; using FileTime.App.Core.Services; using FileTime.Core.Models; using MvvmGen; @@ -9,12 +10,12 @@ 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) + public void Init(IContainer item, ITabViewModel parentTab, ItemViewModelType itemViewModelType) { - Init((IItem)item, parentTab); + Init((IItem)item, parentTab, itemViewModelType); } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/ElementViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/ElementViewModel.cs index c9eb96c..f4dce66 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/ElementViewModel.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/ElementViewModel.cs @@ -1,3 +1,4 @@ +using FileTime.App.Core.Models.Enums; using FileTime.App.Core.Services; using FileTime.Core.Models; using MvvmGen; @@ -10,12 +11,12 @@ public partial class ElementViewModel : ItemViewModel, IElementViewModel [Property] private long? _size; - public ElementViewModel(IItemNameConverterService _itemNameConverterService, IAppState _appState) : base(_itemNameConverterService, _appState) + public ElementViewModel(IItemNameConverterService itemNameConverterService, IAppState appState) : base(itemNameConverterService, appState) { } - public void Init(IElement item, ITabViewModel parentTab) + public void Init(IElement item, ITabViewModel parentTab, ItemViewModelType itemViewModelType) { - Init((IItem)item, parentTab); + Init((IItem)item, parentTab, itemViewModelType); } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/FileViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/FileViewModel.cs index 7ba9fe0..cd5867a 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/FileViewModel.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/FileViewModel.cs @@ -1,3 +1,4 @@ +using FileTime.App.Core.Models.Enums; using FileTime.App.Core.Services; using FileTime.Core.Models; using MvvmGen; @@ -7,12 +8,12 @@ namespace FileTime.App.Core.ViewModels; [ViewModel(GenerateConstructor = false)] public partial class FileViewModel : ElementViewModel, IFileViewModel { - public FileViewModel(IItemNameConverterService _itemNameConverterService, IAppState _appState) : base(_itemNameConverterService, _appState) + public FileViewModel(IItemNameConverterService itemNameConverterService, IAppState appState) : base(itemNameConverterService, appState) { } - public void Init(IFileElement item, ITabViewModel parentTab) + public void Init(IFileElement item, ITabViewModel parentTab, ItemViewModelType itemViewModelType) { - Init((IElement)item, parentTab); + Init((IElement)item, parentTab, itemViewModelType); } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/ItemViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/ItemViewModel.cs index 0b690c2..93551a0 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/ItemViewModel.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/ItemViewModel.cs @@ -1,3 +1,4 @@ +using System.ComponentModel; using System.Reactive.Linq; using DynamicData; using FileTime.App.Core.Models; @@ -41,21 +42,29 @@ public abstract partial class ItemViewModel : IItemViewModel [Property] private IObservable _isAlternative; - public void Init(IItem item, ITabViewModel parentTab) + public void Init(IItem item, ITabViewModel parentTab, ItemViewModelType itemViewModelType) { + var sourceCollection = itemViewModelType switch + { + ItemViewModelType.Main => parentTab.CurrentItemsCollectionObservable, + ItemViewModelType.Parent => parentTab.ParentsChildrenCollectionObservable, + ItemViewModelType.SelectedChild => parentTab.SelectedsChildrenCollectionObservable, + _ => throw new InvalidEnumArgumentException() + }; + BaseItem = item; DisplayName = _appState.SearchText.Select(s => _itemNameConverterService.GetDisplayName(item.DisplayName, s)); DisplayNameText = item.DisplayName; IsMarked = parentTab.MarkedItems.ToCollection().Select(m => m.Any(i => i.Path.Path == item.FullName?.Path)); IsSelected = parentTab.CurrentSelectedItem.Select(EqualsTo); - IsAlternative = parentTab.CurrentItemsCollectionObservable.Select(c => c?.Index().FirstOrDefault(i => EqualsTo(i.Value)).Key % 2 == 0); + IsAlternative = sourceCollection.Select(c => c?.Index().FirstOrDefault(i => EqualsTo(i.Value)).Key % 2 == 0); ViewMode = Observable.CombineLatest(IsMarked, IsSelected, IsAlternative, GenerateViewMode); Attributes = item.Attributes; CreatedAt = item.CreatedAt; } - private ItemViewMode GenerateViewMode(bool isMarked, bool isSelected, bool sAlternative) - => (isMarked, isSelected, sAlternative) switch + private ItemViewMode GenerateViewMode(bool isMarked, bool isSelected, bool isAlternative) + => (isMarked, isSelected, isAlternative) switch { (true, true, _) => ItemViewMode.MarkedSelected, (true, false, true) => ItemViewMode.MarkedAlternative, diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs index 87cf897..353e141 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs @@ -2,6 +2,7 @@ using System.Reactive.Linq; using DynamicData; using FileTime.App.Core.Extensions; using FileTime.App.Core.Models; +using FileTime.App.Core.Models.Enums; using FileTime.App.Core.Services; using FileTime.Core.Models; using FileTime.Core.Services; @@ -35,15 +36,14 @@ public partial class TabViewModel : ITabViewModel, IDisposable public IObservable>?> ParentsChildren { get; private set; } = null!; public IObservable?> CurrentItemsCollectionObservable { get; private set; } = null!; + public IObservable?> ParentsChildrenCollectionObservable { get; private set; } = null!; + public IObservable?> SelectedsChildrenCollectionObservable { get; private set; } = null!; - [Property] - private BindedCollection? _currentItemsCollection; + [Property] private BindedCollection? _currentItemsCollection; - [Property] - private BindedCollection? _parentsChildrenCollection; + [Property] private BindedCollection? _parentsChildrenCollection; - [Property] - private BindedCollection? _selectedsChildrenCollection; + [Property] private BindedCollection? _selectedsChildrenCollection; public TabViewModel( IServiceProvider serviceProvider, @@ -67,7 +67,7 @@ public partial class TabViewModel : ITabViewModel, IDisposable CurrentLocation = tab.CurrentLocation.AsObservable(); CurrentItems = tab.CurrentItems - .Select(items => items?.Transform(MapItemToViewModel)) + .Select(items => items?.Transform(i => MapItemToViewModel(i, ItemViewModelType.Main))) .ObserveOn(_rxSchedulerService.GetWorkerScheduler()) .SubscribeOn(_rxSchedulerService.GetUIScheduler()) .Publish(null) @@ -79,10 +79,11 @@ public partial class TabViewModel : ITabViewModel, IDisposable tab.CurrentSelectedItem, (currentItems, currentSelectedItemPath) => currentItems == null - ? Observable.Return((IItemViewModel?)null) + ? Observable.Return((IItemViewModel?) null) : currentItems .ToCollection() - .Select(items => items.FirstOrDefault(i => i.BaseItem?.FullName == currentSelectedItemPath?.Path)) + .Select(items => + items.FirstOrDefault(i => i.BaseItem?.FullName == currentSelectedItemPath?.Path)) ) .Switch() .Publish(null) @@ -91,11 +92,9 @@ public partial class TabViewModel : ITabViewModel, IDisposable SelectedsChildren = InitSelectedsChildren(); ParentsChildren = InitParentsChildren(); - CurrentItemsCollectionObservable = CurrentItems - .Select(c => c != null ? c.ToCollection() : Observable.Return((IReadOnlyCollection?)null)) - .Switch() - .Publish(null) - .RefCount(); + CurrentItemsCollectionObservable = InitAsd(CurrentItems); + SelectedsChildrenCollectionObservable = InitAsd(SelectedsChildren); + ParentsChildrenCollectionObservable = InitAsd(ParentsChildren); CurrentItems.Subscribe(children => { @@ -119,7 +118,8 @@ public partial class TabViewModel : ITabViewModel, IDisposable IObservable>?> InitSelectedsChildren() { - var currentSelectedItemThrottled = CurrentSelectedItem.Throttle(TimeSpan.FromMilliseconds(250)).Publish(null).RefCount(); + var currentSelectedItemThrottled = + CurrentSelectedItem.Throttle(TimeSpan.FromMilliseconds(250)).Publish(null).RefCount(); return Observable.Merge( currentSelectedItemThrottled .WhereNotNull() @@ -127,10 +127,12 @@ public partial class TabViewModel : ITabViewModel, IDisposable .Where(c => c?.Container is not null) .Select(c => c.Container!.Items) .Switch() - .Select(i => i?.TransformAsync(MapItem).Transform(MapItemToViewModel)), + .Select(i => + i?.TransformAsync(MapItem) + .Transform(i => MapItemToViewModel(i, ItemViewModelType.SelectedChild))), currentSelectedItemThrottled .Where(c => c is null || c is not IContainerViewModel) - .Select(_ => (IObservable>?)null) + .Select(_ => (IObservable>?) null) ) .ObserveOn(_rxSchedulerService.GetWorkerScheduler()) .SubscribeOn(_rxSchedulerService.GetUIScheduler()) @@ -149,43 +151,63 @@ public partial class TabViewModel : ITabViewModel, IDisposable 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) .Switch() - .Select(items => items?.TransformAsync(MapItem).Transform(MapItemToViewModel)), + .Select(items => + items?.TransformAsync(MapItem) + .Transform(i => MapItemToViewModel(i, ItemViewModelType.Parent))), parentThrottled .Where(p => p is null) - .Select(_ => (IObservable>?)null) + .Select(_ => (IObservable>?) null) ) .ObserveOn(_rxSchedulerService.GetWorkerScheduler()) .SubscribeOn(_rxSchedulerService.GetUIScheduler()) .Publish(null) .RefCount(); } + + IObservable?> InitAsd( + IObservable>?> source) + { + return source + .Select(c => + c != null ? c.ToCollection() : Observable.Return((IReadOnlyCollection?) null)) + .Switch() + .Publish(null) + .RefCount(); + } } private static async Task MapItem(IAbsolutePath item) - => await item.ResolveAsync(forceResolve: true, itemInitializationSettings: new ItemInitializationSettings(true)); + => await item.ResolveAsync(forceResolve: true, + itemInitializationSettings: new ItemInitializationSettings(true)); - private IItemViewModel MapItemToViewModel(IItem item) + private IItemViewModel MapItemToViewModel(IItem item, ItemViewModelType type) { if (item is IContainer container) { - var containerViewModel = _serviceProvider.GetInitableResolver(container, this).GetRequiredService(); + var containerViewModel = _serviceProvider + .GetInitableResolver(container, this, type) + .GetRequiredService(); return containerViewModel; } else if (item is IFileElement fileElement) { - var fileViewModel = _serviceProvider.GetInitableResolver(fileElement, this).GetRequiredService(); + var fileViewModel = _serviceProvider + .GetInitableResolver(fileElement, this, type) + .GetRequiredService(); fileViewModel.Size = fileElement.Size; return fileViewModel; } else if (item is IElement element) { - var elementViewModel = _serviceProvider.GetInitableResolver(element, this).GetRequiredService(); + var elementViewModel = _serviceProvider + .GetInitableResolver(element, this, type) + .GetRequiredService(); return elementViewModel; } @@ -237,9 +259,12 @@ public partial class TabViewModel : ITabViewModel, IDisposable { disposable.Dispose(); } - catch { } + catch + { + } } } + disposed = true; } } \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml b/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml index 7c51834..c04fdb9 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml +++ b/src/GuiApp/Avalonia/FileTime.GuiApp.App/App.axaml @@ -44,33 +44,39 @@ - - + - + - - + + - + - - + + - - + - + - + + @@ -182,4 +191,4 @@ - + \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/CommandToCommandNameConverter.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/CommandToCommandNameConverter.cs new file mode 100644 index 0000000..75e8c13 --- /dev/null +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Converters/CommandToCommandNameConverter.cs @@ -0,0 +1,21 @@ +using System.Globalization; +using Avalonia.Data.Converters; +using FileTime.App.Core.Command; + +namespace FileTime.GuiApp.Converters; + +public class CommandToCommandNameConverter : IValueConverter +{ + public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture) + { + if(value is not Commands command) return value; + + //TODO: implement + return command.ToString(); + } + + public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs index 3ceb0ed..fbee23b 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/ViewModels/MainWindowViewModel.cs @@ -14,7 +14,7 @@ using MvvmGen; namespace FileTime.GuiApp.ViewModels; [ViewModel] -[Inject(typeof(IAppState), "_appState")] +[Inject(typeof(IGuiAppState), "_appState")] [Inject(typeof(ILocalContentProvider), "_localContentProvider")] [Inject(typeof(IServiceProvider), PropertyName = "_serviceProvider")] [Inject(typeof(ILogger), PropertyName = "_logger")] @@ -22,7 +22,7 @@ namespace FileTime.GuiApp.ViewModels; public partial class MainWindowViewModel : IMainWindowViewModelBase { public bool Loading => false; - public IAppState AppState => _appState; + public IGuiAppState AppState => _appState; public string Title { get; private set; } partial void OnInitialize() @@ -30,7 +30,7 @@ public partial class MainWindowViewModel : IMainWindowViewModelBase _logger?.LogInformation($"Starting {nameof(MainWindowViewModel)} initialization..."); var version = Assembly.GetEntryAssembly()!.GetName().Version; - var versionString = "Unknwon version"; + var versionString = "Unknown version"; if (version != null) { versionString = $"{version.Major}.{version.Minor}.{version.Build}"; diff --git a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml index e22fb0c..41e5103 100644 --- a/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml +++ b/src/GuiApp/Avalonia/FileTime.GuiApp/Views/MainWindow.axaml @@ -7,6 +7,7 @@ xmlns:local="using:FileTime.GuiApp.Views" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="using:FileTime.GuiApp.ViewModels" + xmlns:config="using:FileTime.GuiApp.Configuration" Title="FileTime" d:DesignHeight="450" d:DesignWidth="800" @@ -180,7 +181,8 @@ Fill="{DynamicResource ContentSeparatorBrush}" /> - + + + + + + + + + + + + + + + + + + + + + + + + + + + +