diff --git a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/ITabViewModel.cs b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/ITabViewModel.cs index 1d79d65..62bd9c1 100644 --- a/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/ITabViewModel.cs +++ b/src/AppCommon/FileTime.App.Core.Abstraction/ViewModels/ITabViewModel.cs @@ -10,9 +10,9 @@ namespace FileTime.App.Core.ViewModels ITab? Tab { get; } int TabNumber { get; } IObservable IsSelected { get; } - IObservable? CurrentLocation { get; } - IObservable? CurrentSelectedItem { get; } - IObservable>? CurrentItems { get; } + IObservable CurrentLocation { get; } + IObservable CurrentSelectedItem { get; } + IObservable> CurrentItems { get; } IObservable> MarkedItems { get; } } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/Extensions/ViewModelExtensions.cs b/src/AppCommon/FileTime.App.Core/Extensions/ViewModelExtensions.cs new file mode 100644 index 0000000..faf432f --- /dev/null +++ b/src/AppCommon/FileTime.App.Core/Extensions/ViewModelExtensions.cs @@ -0,0 +1,14 @@ +using FileTime.App.Core.ViewModels; +using FileTime.Core.Models; + +namespace FileTime.App.Core.Extensions +{ + public static class ViewModelExtensions + { + public static IAbsolutePath ToAbsolutePath(this IItemViewModel itemViewModel) + { + 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); + } + } +} \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj b/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj index 19a40eb..a957c4c 100644 --- a/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj +++ b/src/AppCommon/FileTime.App.Core/FileTime.App.Core.csproj @@ -14,6 +14,7 @@ + diff --git a/src/AppCommon/FileTime.App.Core/Services/CommandHandlerService.cs b/src/AppCommon/FileTime.App.Core/Services/CommandHandlerService.cs index faaa5f6..7a68ea9 100644 --- a/src/AppCommon/FileTime.App.Core/Services/CommandHandlerService.cs +++ b/src/AppCommon/FileTime.App.Core/Services/CommandHandlerService.cs @@ -1,5 +1,6 @@ using System.Reactive.Linq; using FileTime.App.Core.Command; +using FileTime.App.Core.Extensions; using FileTime.App.Core.ViewModels; using FileTime.Core.Models; @@ -12,14 +13,16 @@ namespace FileTime.App.Core.Services private ITabViewModel? _selectedTab; private IContainer? _currentLocation; private IItemViewModel? _currentSelectedItem; + private List _currentItems = new(); public CommandHandlerService(IAppState appState) { _appState = appState; _appState.SelectedTab.Subscribe(t => _selectedTab = t); - _appState.SelectedTab.Select(t => t == null ? Observable.Return(null) : t.CurrentLocation!).Switch().Subscribe(l => _currentLocation = l); - _appState.SelectedTab.Select(t => t == null ? Observable.Return(null) : t.CurrentSelectedItem!).Switch().Subscribe(l => _currentSelectedItem = l); + _appState.SelectedTab.Select(t => t == null ? Observable.Return(null) : t.CurrentLocation).Switch().Subscribe(l => _currentLocation = l); + _appState.SelectedTab.Select(t => t == null ? Observable.Return(null) : t.CurrentSelectedItem).Switch().Subscribe(l => _currentSelectedItem = l); + _appState.SelectedTab.Select(t => t == null ? Observable.Return(Enumerable.Empty()) : t.CurrentItems).Switch().Subscribe(i => _currentItems = i.ToList()); _commandHandlers = new Dictionary> { @@ -44,9 +47,9 @@ namespace FileTime.App.Core.Services {Commands.GoUp, GoUp}, //{Commands.HardDelete, HardDelete}, //{Commands.Mark, MarkCurrentItem}, - //{Commands.MoveCursorDown, MoveCursorDown}, + {Commands.MoveCursorDown, MoveCursorDown}, //{Commands.MoveCursorDownPage, MoveCursorDownPage}, - //{Commands.MoveCursorUp, MoveCursorUp}, + {Commands.MoveCursorUp, MoveCursorUp}, //{Commands.MoveCursorUpPage, MoveCursorUpPage}, //{Commands.MoveToFirst, MoveToFirst}, //{Commands.MoveToLast, MoveToLast}, @@ -100,5 +103,27 @@ namespace FileTime.App.Core.Services if (_currentLocation?.Parent is not IAbsolutePath parentPath || await parentPath.ResolveAsync() is not IContainer newContainer) return; _selectedTab?.Tab?.SetCurrentLocation(newContainer); } + + private Task MoveCursorDown() + { + SelectNewSelectedItem(i => i.SkipWhile(i => i != _currentSelectedItem).Skip(1).FirstOrDefault()); + return Task.CompletedTask; + } + + private Task MoveCursorUp() + { + SelectNewSelectedItem(i => i.TakeWhile(i => i != _currentSelectedItem).LastOrDefault()); + return Task.CompletedTask; + } + + private void SelectNewSelectedItem(Func, IItemViewModel?> getNewSelected) + { + if (_selectedTab is null || _currentLocation is null) return; + + var newSelectedItem = getNewSelected(_currentItems); + if (newSelectedItem == null) return; + + _selectedTab.Tab?.SetSelectedItem(newSelectedItem.ToAbsolutePath()); + } } } \ No newline at end of file diff --git a/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs b/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs index 21dedd1..a21ab61 100644 --- a/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs +++ b/src/AppCommon/FileTime.App.Core/ViewModels/TabViewModel.cs @@ -22,9 +22,9 @@ namespace FileTime.App.Core.ViewModels public IObservable IsSelected { get; } - public IObservable? CurrentLocation { get; private set; } - public IObservable? CurrentSelectedItem { get; private set; } - public IObservable>? CurrentItems { get; private set; } + public IObservable CurrentLocation { get; private set; } = null!; + public IObservable CurrentSelectedItem { get; private set; } = null!; + public IObservable> CurrentItems { get; private set; } = null!; public IObservable> MarkedItems { get; } public TabViewModel( diff --git a/src/Core/FileTime.Core.Abstraction/Models/IItem.cs b/src/Core/FileTime.Core.Abstraction/Models/IItem.cs index d88a593..50074a1 100644 --- a/src/Core/FileTime.Core.Abstraction/Models/IItem.cs +++ b/src/Core/FileTime.Core.Abstraction/Models/IItem.cs @@ -17,5 +17,6 @@ namespace FileTime.Core.Models bool CanRename { get; } IContentProvider Provider { get; } string? Attributes { get; } + AbsolutePathType Type { get; } } } \ No newline at end of file diff --git a/src/Core/FileTime.Core.Models/Container.cs b/src/Core/FileTime.Core.Models/Container.cs index a9fb656..17213f6 100644 --- a/src/Core/FileTime.Core.Models/Container.cs +++ b/src/Core/FileTime.Core.Models/Container.cs @@ -22,5 +22,6 @@ namespace FileTime.Core.Models { BehaviorSubject IsLoading { get; } = new BehaviorSubject(false); IObservable IContainer.IsLoading => IsLoading.AsObservable(); + public AbsolutePathType Type => AbsolutePathType.Container; } } \ No newline at end of file diff --git a/src/Core/FileTime.Core.Models/Element.cs b/src/Core/FileTime.Core.Models/Element.cs index e5018a8..fee18b7 100644 --- a/src/Core/FileTime.Core.Models/Element.cs +++ b/src/Core/FileTime.Core.Models/Element.cs @@ -15,5 +15,8 @@ namespace FileTime.Core.Models SupportsDelete CanDelete, bool CanRename, string? Attributes, - IContentProvider Provider) : IElement; + IContentProvider Provider) : IElement + { + public AbsolutePathType Type => AbsolutePathType.Element; + } } \ No newline at end of file diff --git a/src/Core/FileTime.Core.Services/ContentProviderBase.cs b/src/Core/FileTime.Core.Services/ContentProviderBase.cs index d05e576..534f41a 100644 --- a/src/Core/FileTime.Core.Services/ContentProviderBase.cs +++ b/src/Core/FileTime.Core.Services/ContentProviderBase.cs @@ -39,6 +39,8 @@ namespace FileTime.Core.Services IObservable IContainer.IsLoading => IsLoading.AsObservable(); + public AbsolutePathType Type => AbsolutePathType.Container; + protected ContentProviderBase(string name) { DisplayName = Name = name; diff --git a/src/Core/FileTime.Core.Services/Tab.cs b/src/Core/FileTime.Core.Services/Tab.cs index f33575e..6dbfd44 100644 --- a/src/Core/FileTime.Core.Services/Tab.cs +++ b/src/Core/FileTime.Core.Services/Tab.cs @@ -40,11 +40,7 @@ namespace FileTime.Core.Services .Publish(null) .RefCount(); - CurrentSelectedItem.Subscribe(s => - { - _currentSelectedItemCached = s; - _currentSelectedItem.OnNext(s); - }); + CurrentSelectedItem.Subscribe(s => _currentSelectedItemCached = s); } private async Task> MapItems(IReadOnlyList items) @@ -83,7 +79,7 @@ namespace FileTime.Core.Services private IObservable GetSelectedItemByLocation(IContainer? currentLocation) { //TODO: - return currentLocation?.Items?.Select(i => i.FirstOrDefault()) ?? Observable.Never((IAbsolutePath?)null); + return currentLocation?.Items?.Select(i => i.Count == 0 ? null : i[0]) ?? Observable.Return((IAbsolutePath?)null); } public void SetCurrentLocation(IContainer newLocation) => _currentLocation.OnNext(newLocation);