Multi instance, tab handling
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.Models;
|
||||
|
||||
public record TabToOpen(int? TabNumber, NativePath Path);
|
||||
|
||||
public record TabsToOpenOnStart(List<TabToOpen> TabsToOpen);
|
||||
@@ -0,0 +1,27 @@
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.UserCommand;
|
||||
|
||||
public class NewTabCommand : IUserCommand
|
||||
{
|
||||
public NewTabCommand(FullName? path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public FullName? Path { get; }
|
||||
public bool Open { get; init; } = true;
|
||||
}
|
||||
public class IdentifiableNewTabCommand : NewTabCommand, IIdentifiableUserCommand
|
||||
{
|
||||
public const string CommandName = "new_tab";
|
||||
|
||||
public static IdentifiableNewTabCommand Instance { get; } = new();
|
||||
|
||||
private IdentifiableNewTabCommand():base(null)
|
||||
{
|
||||
|
||||
}
|
||||
public string UserCommandID => CommandName;
|
||||
public string Title => "New tab";
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace FileTime.App.Core.UserCommand;
|
||||
|
||||
public class SelectNextTabCommand : IIdentifiableUserCommand
|
||||
{
|
||||
public const string CommandName = "next_tab";
|
||||
|
||||
public static SelectNextTabCommand Instance { get; } = new();
|
||||
|
||||
private SelectNextTabCommand()
|
||||
{
|
||||
|
||||
}
|
||||
public string UserCommandID => CommandName;
|
||||
public string Title => "Next tab";
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace FileTime.App.Core.UserCommand;
|
||||
|
||||
public class SelectPreviousTabCommand : IIdentifiableUserCommand
|
||||
{
|
||||
public const string CommandName = "previous_tab";
|
||||
|
||||
public static SelectPreviousTabCommand Instance { get; } = new();
|
||||
|
||||
private SelectPreviousTabCommand()
|
||||
{
|
||||
|
||||
}
|
||||
public string UserCommandID => CommandName;
|
||||
public string Title => "New tab";
|
||||
}
|
||||
@@ -47,19 +47,15 @@ public class MainConfiguration
|
||||
private static List<CommandBindingConfiguration> InitDefaultKeyBindings() =>
|
||||
new List<CommandBindingConfiguration>
|
||||
{
|
||||
//new CommandBindingConfiguration(ConfigCommand.AutoRefresh, new KeyConfig(Keys.R, shift: true)),
|
||||
//new CommandBindingConfiguration(ConfigCommand.ChangeTimelineMode, new[] { Keys.T, Keys.M }),
|
||||
new(CloseTabCommand.CommandName, Keys.Q),
|
||||
//new CommandBindingConfiguration(ConfigCommand.Compress, new[] { Keys.Y, Keys.C }),
|
||||
new(CopyBase64Command.CommandName, new[] {Keys.C, Keys.B}),
|
||||
new(CopyCommand.CommandName, new[] {Keys.Y, Keys.Y}),
|
||||
//new CommandBindingConfiguration(ConfigCommand.CopyHash, new[] { Keys.C, Keys.H }),
|
||||
new(CopyNativePathCommand.CommandName, new[] {Keys.C, Keys.P}),
|
||||
new(CopyFilesToClipboardCommand.CommandName, new[] {Keys.Y, Keys.C}),
|
||||
new(CreateContainer.CommandName, Keys.F7),
|
||||
new(CreateContainer.CommandName, new[] {Keys.C, Keys.C}),
|
||||
new(CreateElementCommand.CommandName, new[] {Keys.C, Keys.E}),
|
||||
//new CommandBindingConfiguration(ConfigCommand.Cut, new[] { Keys.D, Keys.D }),
|
||||
new(EditCommand.CommandName, new[] {Keys.F4}),
|
||||
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Keys.Comma, shift: true)),
|
||||
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Keys.Question, shift: true)),
|
||||
@@ -80,6 +76,7 @@ public class MainConfiguration
|
||||
new(MoveCursorDownCommand.CommandName, Keys.Down),
|
||||
new(MoveCursorUpPageCommand.CommandName, Keys.PageUp),
|
||||
new(MoveCursorDownPageCommand.CommandName, Keys.PageDown),
|
||||
new(IdentifiableNewTabCommand.CommandName, new[] {new KeyConfig(Keys.T, ctrl: true)}),
|
||||
//new CommandBindingConfiguration(ConfigCommand.NextTimelineBlock, Keys.L ),
|
||||
//new CommandBindingConfiguration(ConfigCommand.NextTimelineCommand, Keys.J ),
|
||||
new(OpenSelectedCommand.CommandName, Keys.Right),
|
||||
@@ -91,7 +88,6 @@ public class MainConfiguration
|
||||
new(PasteCommand.PasteSkipCommandName, new[] {Keys.P, Keys.S}),
|
||||
new(PasteFilesFromClipboardCommand.PasteMergeCommandName, new[] {new KeyConfig(Keys.V, ctrl: true)}),
|
||||
new(PasteFilesFromClipboardCommand.PasteOverwriteCommandName, new[] {new KeyConfig(Keys.V, ctrl: true, shift: true)}),
|
||||
//new CommandBindingConfiguration(ConfigCommand.PinFavorite, new[] { Keys.F, Keys.P }),
|
||||
//new CommandBindingConfiguration(ConfigCommand.PreviousTimelineBlock, Keys.H ),
|
||||
//new CommandBindingConfiguration(ConfigCommand.PreviousTimelineCommand, Keys.K ),
|
||||
new(RefreshCommand.CommandName, Keys.R),
|
||||
@@ -99,10 +95,10 @@ public class MainConfiguration
|
||||
new(RenameCommand.CommandName, new[] {Keys.C, Keys.W}),
|
||||
new(IdentifiableRunOrOpenCommand.CommandName, Keys.Enter),
|
||||
//new CommandBindingConfiguration(ConfigCommand.RunCommand, new KeyConfig(Keys.D4, shift: true)),
|
||||
//new CommandBindingConfiguration(ConfigCommand.ScanContainerSize, new[] { Keys.C, Keys.S }),
|
||||
//new CommandBindingConfiguration(ConfigCommand.ShowAllShortcut, Keys.F1),
|
||||
new(DeleteCommand.SoftDeleteCommandName, new[] {new KeyConfig(Keys.D), new KeyConfig(Keys.D, shift: true)}),
|
||||
new(IdentifiableSearchCommand.SearchByNameContainsCommandName, new[] {Keys.S, Keys.N}),
|
||||
new(SelectNextTabCommand.CommandName, new[] {new KeyConfig(Keys.Tab, ctrl: true)}),
|
||||
new(SelectPreviousTabCommand.CommandName, new[] {new KeyConfig(Keys.Tab, ctrl: true, shift: true)}),
|
||||
new(SwitchToTabCommand.SwitchToLastTabCommandName, new[] {new KeyConfig(Keys.Num9, alt: true)}),
|
||||
new(SwitchToTabCommand.SwitchToTab1CommandName, new[] {new KeyConfig(Keys.Num1, alt: true)}),
|
||||
new(SwitchToTabCommand.SwitchToTab2CommandName, new[] {new KeyConfig(Keys.Num2, alt: true)}),
|
||||
|
||||
@@ -36,6 +36,7 @@ public class TabPersistenceService : ITabPersistenceService
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILocalContentProvider _localContentProvider;
|
||||
private readonly TabPersistenceSettings _tabPersistenceSettings;
|
||||
private readonly TabsToOpenOnStart _tabsToOpen;
|
||||
|
||||
public TabPersistenceService(
|
||||
IApplicationSettings applicationSettings,
|
||||
@@ -44,6 +45,7 @@ public class TabPersistenceService : ITabPersistenceService
|
||||
IServiceProvider serviceProvider,
|
||||
ILocalContentProvider localContentProvider,
|
||||
TabPersistenceSettings tabPersistenceSettings,
|
||||
TabsToOpenOnStart tabsToOpen,
|
||||
ILogger<TabPersistenceService> logger)
|
||||
{
|
||||
_appState = appState;
|
||||
@@ -53,6 +55,7 @@ public class TabPersistenceService : ITabPersistenceService
|
||||
_serviceProvider = serviceProvider;
|
||||
_localContentProvider = localContentProvider;
|
||||
_tabPersistenceSettings = tabPersistenceSettings;
|
||||
_tabsToOpen = tabsToOpen;
|
||||
|
||||
_jsonOptions = new JsonSerializerOptions
|
||||
{
|
||||
@@ -62,22 +65,63 @@ public class TabPersistenceService : ITabPersistenceService
|
||||
}
|
||||
|
||||
public async Task InitAsync()
|
||||
=> await LoadStatesAsync();
|
||||
{
|
||||
var containers = new List<(int? TabNumber, IContainer Container)>();
|
||||
|
||||
foreach (var (requestedTabNumber, nativePath) in _tabsToOpen.TabsToOpen)
|
||||
{
|
||||
if (await _timelessContentProvider.GetItemByNativePathAsync(nativePath) is not IContainer container) continue;
|
||||
|
||||
containers.Add((requestedTabNumber, container));
|
||||
}
|
||||
|
||||
var loadedTabViewModels = await LoadStatesAsync(containers.Count == 0);
|
||||
|
||||
var tabViewModels = new List<ITabViewModel>();
|
||||
foreach (var (requestedTabNumber, container) in containers)
|
||||
{
|
||||
var tabNumber = requestedTabNumber ?? 1;
|
||||
|
||||
if (tabNumber < 1) tabNumber = 1;
|
||||
|
||||
var tabNumbers = _appState.Tabs.Select(t => t.TabNumber).ToHashSet();
|
||||
|
||||
while (tabNumbers.Contains(tabNumber))
|
||||
{
|
||||
tabNumber++;
|
||||
}
|
||||
|
||||
var tab = await _serviceProvider.GetAsyncInitableResolver(container)
|
||||
.GetRequiredServiceAsync<ITab>();
|
||||
var tabViewModel = _serviceProvider.GetInitableResolver(tab, tabNumber).GetRequiredService<ITabViewModel>();
|
||||
|
||||
_appState.AddTab(tabViewModel);
|
||||
tabViewModels.Add(tabViewModel);
|
||||
}
|
||||
|
||||
tabViewModels.Reverse();
|
||||
await _appState.SetSelectedTabAsync(tabViewModels.Concat(loadedTabViewModels).First());
|
||||
}
|
||||
|
||||
public Task ExitAsync(CancellationToken token = default)
|
||||
{
|
||||
if(!_tabPersistenceSettings.SaveState) return Task.CompletedTask;
|
||||
if (!_tabPersistenceSettings.SaveState) return Task.CompletedTask;
|
||||
SaveStates(token);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task LoadStatesAsync(CancellationToken token = default)
|
||||
private async Task<IEnumerable<ITabViewModel>> LoadStatesAsync(bool createEmptyIfNecessary, CancellationToken token = default)
|
||||
{
|
||||
if (!File.Exists(_settingsPath) || !_tabPersistenceSettings.LoadState)
|
||||
{
|
||||
await CreateEmptyTab();
|
||||
return;
|
||||
if (createEmptyIfNecessary)
|
||||
{
|
||||
var tabViewModel = await CreateEmptyTab();
|
||||
return new[] {tabViewModel};
|
||||
}
|
||||
|
||||
return Enumerable.Empty<ITabViewModel>();
|
||||
}
|
||||
|
||||
try
|
||||
@@ -86,7 +130,8 @@ public class TabPersistenceService : ITabPersistenceService
|
||||
var state = await JsonSerializer.DeserializeAsync<PersistenceRoot>(stateReader, cancellationToken: token);
|
||||
if (state != null)
|
||||
{
|
||||
if (await RestoreTabs(state.TabStates)) return;
|
||||
var (success, tabViewModels) = await RestoreTabs(state.TabStates);
|
||||
if (success) return tabViewModels;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -94,9 +139,15 @@ public class TabPersistenceService : ITabPersistenceService
|
||||
_logger.LogError(e, "Unknown exception while restoring app state");
|
||||
}
|
||||
|
||||
await CreateEmptyTab();
|
||||
if (createEmptyIfNecessary)
|
||||
{
|
||||
var tabViewModel = await CreateEmptyTab();
|
||||
return new[] {tabViewModel};
|
||||
}
|
||||
|
||||
async Task CreateEmptyTab()
|
||||
return Enumerable.Empty<ITabViewModel>();
|
||||
|
||||
async Task<ITabViewModel> CreateEmptyTab()
|
||||
{
|
||||
IContainer? currentDirectory = null;
|
||||
try
|
||||
@@ -116,81 +167,75 @@ public class TabPersistenceService : ITabPersistenceService
|
||||
var tabViewModel = _serviceProvider.GetInitableResolver(tab, 1).GetRequiredService<ITabViewModel>();
|
||||
|
||||
_appState.AddTab(tabViewModel);
|
||||
|
||||
return tabViewModel;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> RestoreTabs(TabStates? tabStates)
|
||||
private async Task<(bool Success, IEnumerable<ITabViewModel>)> RestoreTabs(TabStates? tabStates)
|
||||
{
|
||||
if (tabStates == null
|
||||
|| tabStates.Tabs == null)
|
||||
{
|
||||
return false;
|
||||
return (false, Enumerable.Empty<ITabViewModel>());
|
||||
}
|
||||
|
||||
try
|
||||
foreach (var tab in tabStates.Tabs)
|
||||
{
|
||||
foreach (var tab in tabStates.Tabs)
|
||||
try
|
||||
{
|
||||
try
|
||||
if (tab.Path == null) continue;
|
||||
if (_contentProvidersNotToRestore.Any(p => tab.Path.StartsWith(p))) continue;
|
||||
|
||||
IContainer? container = null;
|
||||
var path = FullName.CreateSafe(tab.Path);
|
||||
while (true)
|
||||
{
|
||||
if (tab.Path == null) continue;
|
||||
if (_contentProvidersNotToRestore.Any(p => tab.Path.StartsWith(p))) continue;
|
||||
|
||||
IContainer? container = null;
|
||||
var path = FullName.CreateSafe(tab.Path);
|
||||
while (true)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
var pathItem =
|
||||
await _timelessContentProvider.GetItemByFullNameAsync(path, PointInTime.Present);
|
||||
var pathItem =
|
||||
await _timelessContentProvider.GetItemByFullNameAsync(path, PointInTime.Present);
|
||||
|
||||
container = pathItem switch
|
||||
{
|
||||
IContainer c => c,
|
||||
IElement e =>
|
||||
e.Parent is null
|
||||
? null
|
||||
: await e.Parent.ResolveAsync() as IContainer,
|
||||
_ => null
|
||||
};
|
||||
break;
|
||||
}
|
||||
catch
|
||||
container = pathItem switch
|
||||
{
|
||||
path = path?.GetParent();
|
||||
if (path == null)
|
||||
{
|
||||
throw new Exception($"Could not find an initializable path along {tab.Path}");
|
||||
}
|
||||
IContainer c => c,
|
||||
IElement e =>
|
||||
e.Parent is null
|
||||
? null
|
||||
: await e.Parent.ResolveAsync() as IContainer,
|
||||
_ => null
|
||||
};
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
path = path?.GetParent();
|
||||
if (path == null)
|
||||
{
|
||||
throw new Exception($"Could not find an initializable path along {tab.Path}");
|
||||
}
|
||||
}
|
||||
|
||||
if (container == null) continue;
|
||||
|
||||
if (_contentProvidersNotToRestore.Contains(container.Provider.Name)) continue;
|
||||
|
||||
var tabToLoad = await _serviceProvider.GetAsyncInitableResolver(container)
|
||||
.GetRequiredServiceAsync<ITab>();
|
||||
var tabViewModel = _serviceProvider.GetInitableResolver(tabToLoad, tab.Number)
|
||||
.GetRequiredService<ITabViewModel>();
|
||||
|
||||
_appState.AddTab(tabViewModel);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Unknown exception while restoring tab. {TabState}",
|
||||
JsonSerializer.Serialize(tab, _jsonOptions));
|
||||
}
|
||||
|
||||
if (container == null) continue;
|
||||
|
||||
if (_contentProvidersNotToRestore.Contains(container.Provider.Name)) continue;
|
||||
|
||||
var tabToLoad = await _serviceProvider.GetAsyncInitableResolver(container)
|
||||
.GetRequiredServiceAsync<ITab>();
|
||||
var tabViewModel = _serviceProvider.GetInitableResolver(tabToLoad, tab.Number)
|
||||
.GetRequiredService<ITabViewModel>();
|
||||
|
||||
_appState.AddTab(tabViewModel);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Unknown exception while restoring tab. {TabState}",
|
||||
JsonSerializer.Serialize(tab, _jsonOptions));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, "Unknown exception while restoring tabs");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_appState.Tabs.Count == 0) return false;
|
||||
if (_appState.Tabs.Count == 0) return (false, Enumerable.Empty<ITabViewModel>());
|
||||
|
||||
var optimalTabs = _appState
|
||||
.Tabs
|
||||
@@ -200,10 +245,7 @@ public class TabPersistenceService : ITabPersistenceService
|
||||
.Tabs
|
||||
.SkipWhile(t => t.TabNumber <= tabStates.ActiveTabNumber);
|
||||
|
||||
var tabToActivate = optimalTabs.Concat(suboptimalTabs).FirstOrDefault();
|
||||
if (tabToActivate is not null) await _appState.SetSelectedTabAsync(tabToActivate);
|
||||
|
||||
return true;
|
||||
return (true, optimalTabs.Concat(suboptimalTabs));
|
||||
}
|
||||
|
||||
public void SaveStates(CancellationToken token = default)
|
||||
|
||||
@@ -86,11 +86,14 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
new TypeUserCommandHandler<MoveCursorToLastCommand>(MoveCursorToLast),
|
||||
new TypeUserCommandHandler<MoveCursorUpCommand>(MoveCursorUp),
|
||||
new TypeUserCommandHandler<MoveCursorUpPageCommand>(MoveCursorUpPage),
|
||||
new TypeUserCommandHandler<NewTabCommand>(NewTabAsync),
|
||||
new TypeUserCommandHandler<OpenCommandPaletteCommand>(OpenCommandPalette),
|
||||
new TypeUserCommandHandler<OpenContainerCommand>(OpenContainer),
|
||||
new TypeUserCommandHandler<OpenSelectedCommand>(OpenSelected),
|
||||
new TypeUserCommandHandler<RunOrOpenCommand>(RunOrOpen),
|
||||
new TypeUserCommandHandler<RefreshCommand>(Refresh),
|
||||
new TypeUserCommandHandler<SelectNextTabCommand>(SelectNextTab),
|
||||
new TypeUserCommandHandler<SelectPreviousTabCommand>(SelectPreviousTab),
|
||||
new TypeUserCommandHandler<SwitchToTabCommand>(SwitchToTab),
|
||||
});
|
||||
}
|
||||
@@ -346,38 +349,19 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
|
||||
private async Task SwitchToTab(SwitchToTabCommand command)
|
||||
{
|
||||
var number = command.TabNumber;
|
||||
var tabViewModel = _appState.Tabs.FirstOrDefault(t => t.TabNumber == number);
|
||||
var tabNumber = command.TabNumber;
|
||||
var tabViewModel = _appState.Tabs.FirstOrDefault(t => t.TabNumber == tabNumber);
|
||||
|
||||
if (number == -1)
|
||||
if (tabNumber == -1)
|
||||
{
|
||||
var greatestNumber = _appState.Tabs.Max(t => t.TabNumber);
|
||||
tabViewModel = _appState.Tabs.FirstOrDefault(t => t.TabNumber == greatestNumber);
|
||||
}
|
||||
else if (tabViewModel == null)
|
||||
|
||||
if (tabViewModel == null)
|
||||
{
|
||||
IContainer? newLocation = null;
|
||||
|
||||
try
|
||||
{
|
||||
newLocation = _currentLocation?.Value?.FullName is { } fullName
|
||||
? (IContainer) await _timelessContentProvider.GetItemByFullNameAsync(fullName, PointInTime.Present)
|
||||
: _localContentProvider;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var fullName = _currentLocation?.Value?.FullName?.Path ?? "unknown";
|
||||
_logger.LogError(ex, "Could not resolve container while switching to tab {TabNumber} to path {FullName}", number, fullName);
|
||||
}
|
||||
|
||||
newLocation ??= _localContentProvider;
|
||||
|
||||
var tab = await _serviceProvider.GetAsyncInitableResolver(newLocation)
|
||||
.GetRequiredServiceAsync<ITab>();
|
||||
var newTabViewModel = _serviceProvider.GetInitableResolver(tab, number).GetRequiredService<ITabViewModel>();
|
||||
|
||||
_appState.AddTab(newTabViewModel);
|
||||
tabViewModel = newTabViewModel;
|
||||
var newLocation = await GetLocationForNewTabAsync(tabNumber);
|
||||
tabViewModel = await CreateTabAsync(newLocation, tabNumber);
|
||||
}
|
||||
|
||||
if (_viewMode == ViewMode.RapidTravel)
|
||||
@@ -385,9 +369,96 @@ public class NavigationUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
await _userCommandHandlerService.HandleCommandAsync(ExitRapidTravelCommand.Instance);
|
||||
}
|
||||
|
||||
await _appState.SetSelectedTabAsync(tabViewModel);
|
||||
}
|
||||
|
||||
private async Task NewTabAsync(NewTabCommand command)
|
||||
{
|
||||
var numbers = _appState.Tabs.Select(t => t.TabNumber).ToHashSet();
|
||||
|
||||
var tabNumber = 1;
|
||||
while (numbers.Contains(tabNumber))
|
||||
{
|
||||
tabNumber++;
|
||||
}
|
||||
|
||||
IContainer? newLocation = null;
|
||||
|
||||
if (command.Path is { } path)
|
||||
{
|
||||
newLocation = await _timelessContentProvider.GetItemByFullNameAsync(path, PointInTime.Present) as IContainer;
|
||||
}
|
||||
|
||||
newLocation ??= await GetLocationForNewTabAsync(tabNumber);
|
||||
var tabViewModel = await CreateTabAsync(newLocation, tabNumber);
|
||||
|
||||
if (_viewMode == ViewMode.RapidTravel)
|
||||
{
|
||||
await _userCommandHandlerService.HandleCommandAsync(ExitRapidTravelCommand.Instance);
|
||||
}
|
||||
|
||||
if (command.Open)
|
||||
{
|
||||
await _appState.SetSelectedTabAsync(tabViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task SelectNextTab()
|
||||
{
|
||||
var currentTabNumber = _appState.SelectedTab.Value?.TabNumber;
|
||||
|
||||
var nextTabNumbers = _appState.Tabs.Select(t => t.TabNumber).Order().SkipWhile(n => n <= currentTabNumber).ToArray();
|
||||
|
||||
if (nextTabNumbers.Length == 0) return;
|
||||
|
||||
var nextTabNumber = nextTabNumbers[0];
|
||||
var tabViewModel = _appState.Tabs.FirstOrDefault(t => t.TabNumber == nextTabNumber);
|
||||
await _appState.SetSelectedTabAsync(tabViewModel!);
|
||||
}
|
||||
|
||||
private async Task SelectPreviousTab()
|
||||
{
|
||||
var currentTabNumber = _appState.SelectedTab.Value?.TabNumber;
|
||||
|
||||
var nextTabNumbers = _appState.Tabs.Select(t => t.TabNumber).Order().TakeWhile(n => n < currentTabNumber).ToArray();
|
||||
|
||||
if (nextTabNumbers.Length == 0) return;
|
||||
|
||||
var nextTabNumber = nextTabNumbers[^1];
|
||||
var tabViewModel = _appState.Tabs.FirstOrDefault(t => t.TabNumber == nextTabNumber);
|
||||
await _appState.SetSelectedTabAsync(tabViewModel!);
|
||||
}
|
||||
|
||||
private async Task<IContainer> GetLocationForNewTabAsync(int tabNumber)
|
||||
{
|
||||
try
|
||||
{
|
||||
var newLocation = _currentLocation?.Value?.FullName is { } fullName
|
||||
? (IContainer) await _timelessContentProvider.GetItemByFullNameAsync(fullName, PointInTime.Present)
|
||||
: _localContentProvider;
|
||||
|
||||
return newLocation;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var fullName = _currentLocation?.Value?.FullName?.Path ?? "unknown";
|
||||
_logger.LogError(ex, "Could not resolve container while switching to tab {TabNumber} to path {FullName}", tabNumber, fullName);
|
||||
}
|
||||
|
||||
return _localContentProvider;
|
||||
}
|
||||
|
||||
private async Task<ITabViewModel> CreateTabAsync(IContainer newLocation, int tabNumber)
|
||||
{
|
||||
var tab = await _serviceProvider.GetAsyncInitableResolver(newLocation)
|
||||
.GetRequiredServiceAsync<ITab>();
|
||||
var newTabViewModel = _serviceProvider.GetInitableResolver(tab, tabNumber).GetRequiredService<ITabViewModel>();
|
||||
|
||||
_appState.AddTab(newTabViewModel);
|
||||
|
||||
return newTabViewModel;
|
||||
}
|
||||
|
||||
private Task CloseTab()
|
||||
{
|
||||
if ((!_applicationConfiguration.AllowCloseLastTab && _appState.Tabs.Count < 2) || _selectedTab == null) return Task.CompletedTask;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using FileTime.App.Core.Configuration;
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.App.Core.Services.UserCommandHandler;
|
||||
using FileTime.App.Core.StartupServices;
|
||||
@@ -36,6 +37,7 @@ public static class Startup
|
||||
serviceCollection.TryAddSingleton<IPossibleCommandsService, PossibleCommandsService>();
|
||||
serviceCollection.TryAddSingleton<IPossibleCommandsViewModel, PossibleCommandsViewModel>();
|
||||
serviceCollection.TryAddSingleton<IProgramsService, ProgramsService>();
|
||||
serviceCollection.TryAddSingleton(new TabsToOpenOnStart(new List<TabToOpen>()));
|
||||
|
||||
return serviceCollection
|
||||
.AddCommandHandlers()
|
||||
|
||||
@@ -13,8 +13,8 @@ public class DefaultIdentifiableCommandHandlerRegister : IStartupHandler
|
||||
|
||||
AddUserCommand(AddRemoteContentProviderCommand.Instance);
|
||||
AddUserCommand(CloseTabCommand.Instance);
|
||||
AddUserCommand(CopyCommand.Instance);
|
||||
AddUserCommand(CopyBase64Command.Instance);
|
||||
AddUserCommand(CopyCommand.Instance);
|
||||
AddUserCommand(CopyFilesToClipboardCommand.Instance);
|
||||
AddUserCommand(CopyNativePathCommand.Instance);
|
||||
AddUserCommand(CreateContainer.Instance);
|
||||
@@ -32,6 +32,9 @@ public class DefaultIdentifiableCommandHandlerRegister : IStartupHandler
|
||||
AddUserCommand(GoToProviderCommand.Instance);
|
||||
AddUserCommand(GoToRootCommand.Instance);
|
||||
AddUserCommand(GoUpCommand.Instance);
|
||||
AddUserCommand(IdentifiableRunOrOpenCommand.Instance);
|
||||
AddUserCommand(IdentifiableSearchCommand.SearchByNameContains);
|
||||
AddUserCommand(IdentifiableSearchCommand.SearchByRegex);
|
||||
AddUserCommand(MarkCommand.Instance);
|
||||
AddUserCommand(MoveCursorDownCommand.Instance);
|
||||
AddUserCommand(MoveCursorDownPageCommand.Instance);
|
||||
@@ -39,6 +42,7 @@ public class DefaultIdentifiableCommandHandlerRegister : IStartupHandler
|
||||
AddUserCommand(MoveCursorToLastCommand.Instance);
|
||||
AddUserCommand(MoveCursorUpCommand.Instance);
|
||||
AddUserCommand(MoveCursorUpPageCommand.Instance);
|
||||
AddUserCommand(IdentifiableNewTabCommand.Instance);
|
||||
AddUserCommand(OpenCommandPaletteCommand.Instance);
|
||||
AddUserCommand(OpenInDefaultFileExplorerCommand.Instance);
|
||||
AddUserCommand(OpenSelectedCommand.Instance);
|
||||
@@ -51,19 +55,18 @@ public class DefaultIdentifiableCommandHandlerRegister : IStartupHandler
|
||||
AddUserCommand(PauseCommandSchedulerCommand.Instance);
|
||||
AddUserCommand(RefreshCommand.Instance);
|
||||
AddUserCommand(RenameCommand.Instance);
|
||||
AddUserCommand(IdentifiableRunOrOpenCommand.Instance);
|
||||
AddUserCommand(ScanSizeCommand.Instance);
|
||||
AddUserCommand(StartCommandSchedulerCommand.Instance);
|
||||
AddUserCommand(SortItemsCommand.OrderByNameCommand);
|
||||
AddUserCommand(SortItemsCommand.OrderByNameDescCommand);
|
||||
AddUserCommand(SelectNextTabCommand.Instance);
|
||||
AddUserCommand(SelectPreviousTabCommand.Instance);
|
||||
AddUserCommand(SortItemsCommand.OrderByCreatedAtCommand);
|
||||
AddUserCommand(SortItemsCommand.OrderByCreatedAtDescCommand);
|
||||
AddUserCommand(SortItemsCommand.OrderByLastModifiedCommand);
|
||||
AddUserCommand(SortItemsCommand.OrderByLastModifiedDescCommand);
|
||||
AddUserCommand(SortItemsCommand.OrderByNameCommand);
|
||||
AddUserCommand(SortItemsCommand.OrderByNameDescCommand);
|
||||
AddUserCommand(SortItemsCommand.OrderBySizeCommand);
|
||||
AddUserCommand(SortItemsCommand.OrderBySizeDescCommand);
|
||||
AddUserCommand(IdentifiableSearchCommand.SearchByNameContains);
|
||||
AddUserCommand(IdentifiableSearchCommand.SearchByRegex);
|
||||
AddUserCommand(StartCommandSchedulerCommand.Instance);
|
||||
AddUserCommand(SwitchToTabCommand.SwitchToLastTab);
|
||||
AddUserCommand(SwitchToTabCommand.SwitchToTab1);
|
||||
AddUserCommand(SwitchToTabCommand.SwitchToTab2);
|
||||
|
||||
Reference in New Issue
Block a user