Tabs: open, close

This commit is contained in:
2022-05-11 22:21:23 +02:00
parent e24045c670
commit 14a2f19a8a
6 changed files with 106 additions and 12 deletions

View File

@@ -16,6 +16,7 @@ public enum Command
Cut, Cut,
Edit, Edit,
EnterRapidTravel, EnterRapidTravel,
ExitRapidTravel,
FindByName, FindByName,
FindByNameRegex, FindByNameRegex,
GoToHome, GoToHome,

View File

@@ -5,14 +5,16 @@ namespace FileTime.App.Core.ViewModels;
public interface IAppState public interface IAppState
{ {
ObservableCollection<ITabViewModel> Tabs { get; } ReadOnlyObservableCollection<ITabViewModel> Tabs { get; }
IObservable<ITabViewModel?> SelectedTab { get; } IObservable<ITabViewModel?> SelectedTab { get; }
IObservable<string?> SearchText { get; } IObservable<string?> SearchText { get; }
IObservable<ViewMode> ViewMode { get; } IObservable<ViewMode> ViewMode { get; }
string RapidTravelText { get; set; } string RapidTravelText { get; set; }
ITabViewModel? CurrentSelectedTab { get; }
void AddTab(ITabViewModel tabViewModel); void AddTab(ITabViewModel tabViewModel);
void RemoveTab(ITabViewModel tabViewModel); void RemoveTab(ITabViewModel tabViewModel);
void SetSearchText(string? searchText); void SetSearchText(string? searchText);
void SwitchViewMode(ViewMode newViewMode); void SwitchViewMode(ViewMode newViewMode);
void SetSelectedTab(ITabViewModel tabToSelect);
} }

View File

@@ -20,6 +20,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="..\..\Providers\FileTime.Providers.Local.Abstractions\FileTime.Providers.Local.Abstractions.csproj" />
<ProjectReference Include="..\..\Tools\FileTime.Tools\FileTime.Tools.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" />
<ProjectReference Include="..\..\Core\FileTime.Core.Command\FileTime.Core.Command.csproj" /> <ProjectReference Include="..\..\Core\FileTime.Core.Command\FileTime.Core.Command.csproj" />

View File

@@ -4,33 +4,60 @@ using FileTime.App.Core.Extensions;
using FileTime.App.Core.Models.Enums; using FileTime.App.Core.Models.Enums;
using FileTime.App.Core.ViewModels; using FileTime.App.Core.ViewModels;
using FileTime.Core.Models; using FileTime.Core.Models;
using FileTime.Core.Services;
using FileTime.Providers.Local;
using Microsoft.Extensions.DependencyInjection;
namespace FileTime.App.Core.Services.CommandHandler; namespace FileTime.App.Core.Services.CommandHandler;
public class NavigationCommandHandler : CommandHandlerBase public class NavigationCommandHandler : CommandHandlerBase
{ {
private readonly IAppState _appState; private readonly IAppState _appState;
private readonly IServiceProvider _serviceProvider;
private readonly ILocalContentProvider _localContentProvider;
private readonly ICommandHandlerService _commandHandlerService;
private ITabViewModel? _selectedTab; private ITabViewModel? _selectedTab;
private IContainer? _currentLocation; private IContainer? _currentLocation;
private IItemViewModel? _currentSelectedItem; private IItemViewModel? _currentSelectedItem;
private IEnumerable<IItemViewModel> _currentItems = Enumerable.Empty<IItemViewModel>(); private IEnumerable<IItemViewModel> _currentItems = Enumerable.Empty<IItemViewModel>();
private ViewMode _viewMode;
public NavigationCommandHandler(IAppState appState) : base(appState) public NavigationCommandHandler(
IAppState appState,
IServiceProvider serviceProvider,
ILocalContentProvider localContentProvider,
ICommandHandlerService commandHandlerService) : base(appState)
{ {
_appState = appState; _appState = appState;
_serviceProvider = serviceProvider;
_localContentProvider = localContentProvider;
_commandHandlerService = commandHandlerService;
SaveSelectedTab(t => _selectedTab = t); SaveSelectedTab(t => _selectedTab = t);
SaveCurrentSelectedItem(i => _currentSelectedItem = i); SaveCurrentSelectedItem(i => _currentSelectedItem = i);
SaveCurrentLocation(l => _currentLocation = l); SaveCurrentLocation(l => _currentLocation = l);
SaveCurrentItems(i => _currentItems = i); SaveCurrentItems(i => _currentItems = i);
appState.ViewMode.Subscribe(v => _viewMode = v);
AddCommandHandlers(new (Command.Command, Func<Task>)[] AddCommandHandlers(new (Command.Command, Func<Task>)[]
{ {
(Command.Command.CloseTab, CloseTab),
(Command.Command.EnterRapidTravel, EnterRapidTravel), (Command.Command.EnterRapidTravel, EnterRapidTravel),
(Command.Command.ExitRapidTravel, ExitRapidTravel),
(Command.Command.GoUp, GoUp), (Command.Command.GoUp, GoUp),
(Command.Command.MoveCursorDown, MoveCursorDown), (Command.Command.MoveCursorDown, MoveCursorDown),
(Command.Command.MoveCursorUp, MoveCursorUp), (Command.Command.MoveCursorUp, MoveCursorUp),
(Command.Command.Open, OpenContainer), (Command.Command.Open, OpenContainer),
(Command.Command.SwitchToLastTab, async () => await SwitchToTab(-1)),
(Command.Command.SwitchToTab1, async () => await SwitchToTab(1)),
(Command.Command.SwitchToTab2, async () => await SwitchToTab(2)),
(Command.Command.SwitchToTab3, async () => await SwitchToTab(3)),
(Command.Command.SwitchToTab4, async () => await SwitchToTab(4)),
(Command.Command.SwitchToTab5, async () => await SwitchToTab(5)),
(Command.Command.SwitchToTab6, async () => await SwitchToTab(6)),
(Command.Command.SwitchToTab7, async () => await SwitchToTab(7)),
(Command.Command.SwitchToTab8, async () => await SwitchToTab(8)),
}); });
} }
@@ -75,4 +102,47 @@ public class NavigationCommandHandler : CommandHandlerBase
_appState.SwitchViewMode(ViewMode.RapidTravel); _appState.SwitchViewMode(ViewMode.RapidTravel);
return Task.CompletedTask; return Task.CompletedTask;
} }
private Task ExitRapidTravel()
{
_appState.SwitchViewMode(ViewMode.Default);
return Task.CompletedTask;
}
private Task SwitchToTab(int number)
{
var tabViewModel = _appState.Tabs.FirstOrDefault(t => t.TabNumber == number);
if (number == -1)
{
var greatestNumber = _appState.Tabs.Max(t => t.TabNumber);
tabViewModel = _appState.Tabs.FirstOrDefault(t => t.TabNumber == greatestNumber);
}
else if (tabViewModel == null)
{
var tab = _serviceProvider.GetInitableResolver<IContainer>(_currentLocation ?? _localContentProvider).GetRequiredService<ITab>();
var newTabViewModel = _serviceProvider.GetInitableResolver(tab, number).GetRequiredService<ITabViewModel>();
_appState.AddTab(newTabViewModel);
tabViewModel = newTabViewModel;
}
if (_viewMode == ViewMode.RapidTravel)
{
_commandHandlerService.HandleCommandAsync(Command.Command.ExitRapidTravel);
}
_appState.SetSelectedTab(tabViewModel!);
return Task.CompletedTask;
}
private Task CloseTab()
{
if (_appState.Tabs.Count < 2) return Task.CompletedTask;
_appState.RemoveTab(_selectedTab!);
return Task.CompletedTask;
}
} }

View File

@@ -1,6 +1,7 @@
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using DynamicData;
using FileTime.App.Core.Models.Enums; using FileTime.App.Core.Models.Enums;
using MvvmGen; using MvvmGen;
using MoreLinq; using MoreLinq;
@@ -12,15 +13,16 @@ public abstract partial class AppStateBase : IAppState
{ {
private readonly BehaviorSubject<string?> _searchText = new(null); private readonly BehaviorSubject<string?> _searchText = new(null);
private readonly BehaviorSubject<ITabViewModel?> _selectedTab = new(null); private readonly BehaviorSubject<ITabViewModel?> _selectedTab = new(null);
private readonly BehaviorSubject<IEnumerable<ITabViewModel>> _tabs = new(Enumerable.Empty<ITabViewModel>());
private readonly BehaviorSubject<ViewMode> _viewMode = new(Models.Enums.ViewMode.Default); private readonly BehaviorSubject<ViewMode> _viewMode = new(Models.Enums.ViewMode.Default);
private readonly SourceList<ITabViewModel> _tabs = new();
public IObservable<ViewMode> ViewMode { get; private set; } public IObservable<ViewMode> ViewMode { get; private set; }
public ObservableCollection<ITabViewModel> Tabs { get; } = new(); public ReadOnlyObservableCollection<ITabViewModel> Tabs { get; private set; }
public IObservable<string?> SearchText { get; private set; } public IObservable<string?> SearchText { get; private set; }
public IObservable<ITabViewModel?> SelectedTab { get; private set; } public IObservable<ITabViewModel?> SelectedTab { get; private set; }
public ITabViewModel? CurrentSelectedTab { get; private set; }
[Property] private string _rapidTravelText = ""; [Property] private string _rapidTravelText = "";
@@ -28,21 +30,39 @@ public abstract partial class AppStateBase : IAppState
{ {
ViewMode = _viewMode.AsObservable(); ViewMode = _viewMode.AsObservable();
Tabs.CollectionChanged += (_, _) => _tabs.OnNext(Tabs); var tabsObservable = _tabs.Connect();
SearchText = _searchText.AsObservable(); SearchText = _searchText.AsObservable();
SelectedTab = Observable.CombineLatest(_tabs, _selectedTab, GetSelectedTab); SelectedTab = Observable.CombineLatest(tabsObservable.ToCollection(), _selectedTab.DistinctUntilChanged(), GetSelectedTab);
SelectedTab.Subscribe(t =>
{
_selectedTab.OnNext(t);
CurrentSelectedTab = t;
});
tabsObservable
.Bind(out var collection)
.DisposeMany()
.Subscribe();
Tabs = collection;
} }
public void AddTab(ITabViewModel tabViewModel) public void AddTab(ITabViewModel tabViewModel)
{ {
Tabs.Add(tabViewModel); if (_tabs.Items.Any(t => t.TabNumber == tabViewModel.TabNumber))
throw new ArgumentException($"There is a tab with the same tab number {tabViewModel.TabNumber}.", nameof(tabViewModel));
var index = _tabs.Items.Count(t => t.TabNumber < tabViewModel.TabNumber);
_tabs.Insert(index, tabViewModel);
} }
public void RemoveTab(ITabViewModel tabViewModel) public void RemoveTab(ITabViewModel tabViewModel)
{ {
if (!Tabs.Contains(tabViewModel)) return; if (!_tabs.Items.Contains(tabViewModel)) return;
Tabs.Remove(tabViewModel); _tabs.Remove(tabViewModel);
} }
public void SetSearchText(string? searchText) => _searchText.OnNext(searchText); public void SetSearchText(string? searchText) => _searchText.OnNext(searchText);
@@ -56,7 +76,7 @@ public abstract partial class AppStateBase : IAppState
private ITabViewModel? GetSelectedTab(IEnumerable<ITabViewModel> tabs, ITabViewModel? expectedSelectedTab) private ITabViewModel? GetSelectedTab(IEnumerable<ITabViewModel> tabs, ITabViewModel? expectedSelectedTab)
{ {
var (prefered, others) = tabs.OrderBy(t => t.TabNumber).Partition(t => t.TabNumber >= (expectedSelectedTab?.TabNumber ?? 0)); var (preferred, others) = tabs.OrderBy(t => t.TabNumber).Partition(t => t.TabNumber >= (expectedSelectedTab?.TabNumber ?? 0));
return prefered.Concat(others).FirstOrDefault(); return preferred.Concat(others).FirstOrDefault();
} }
} }

View File

@@ -56,7 +56,7 @@ public class RapidTravelModeKeyInputHandler : IRapidTravelModeKeyInputHandler
} }
else else
{ {
_appState.SwitchViewMode(ViewMode.Default); await CallCommandAsync(Command.ExitRapidTravel);
} }
} }
else if (key == Key.Back) else if (key == Key.Back)