Tab restore
This commit is contained in:
@@ -0,0 +1,7 @@
|
|||||||
|
namespace FileTime.App.Core.Models;
|
||||||
|
|
||||||
|
public interface IApplicationSettings
|
||||||
|
{
|
||||||
|
string AppDataRoot { get; }
|
||||||
|
string EnvironmentName { get; }
|
||||||
|
}
|
||||||
@@ -2,4 +2,5 @@ namespace FileTime.App.Core.Services;
|
|||||||
|
|
||||||
public interface IStartupHandler
|
public interface IStartupHandler
|
||||||
{
|
{
|
||||||
|
Task InitAsync();
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace FileTime.App.Core.Services.Persistence;
|
||||||
|
|
||||||
|
public interface ITabPersistenceService : IStartupHandler, IExitHandler
|
||||||
|
{
|
||||||
|
void SaveStates();
|
||||||
|
}
|
||||||
@@ -24,6 +24,8 @@ public interface ITabViewModel : IInitable<ITab, int>, IDisposable
|
|||||||
IObservable<IReadOnlyCollection<IItemViewModel>?> CurrentItemsCollectionObservable { get; }
|
IObservable<IReadOnlyCollection<IItemViewModel>?> CurrentItemsCollectionObservable { get; }
|
||||||
IObservable<IReadOnlyCollection<IItemViewModel>?> ParentsChildrenCollectionObservable { get; }
|
IObservable<IReadOnlyCollection<IItemViewModel>?> ParentsChildrenCollectionObservable { get; }
|
||||||
IObservable<IReadOnlyCollection<IItemViewModel>?> SelectedsChildrenCollectionObservable { get; }
|
IObservable<IReadOnlyCollection<IItemViewModel>?> SelectedsChildrenCollectionObservable { get; }
|
||||||
|
IContainer? CachedCurrentLocation { get; }
|
||||||
|
|
||||||
void ClearMarkedItems();
|
void ClearMarkedItems();
|
||||||
void RemoveMarkedItem(FullName fullName);
|
void RemoveMarkedItem(FullName fullName);
|
||||||
void AddMarkedItem(FullName fullName);
|
void AddMarkedItem(FullName fullName);
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace FileTime.App.Core.Models;
|
||||||
|
|
||||||
|
public class ApplicationSettings : IApplicationSettings
|
||||||
|
{
|
||||||
|
public string AppDataRoot { get; private set; } = null!;
|
||||||
|
public string EnvironmentName { get; private set; } = null!;
|
||||||
|
|
||||||
|
public ApplicationSettings()
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
InitDebugSettings();
|
||||||
|
#else
|
||||||
|
InitReleaseSettings();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitDebugSettings()
|
||||||
|
{
|
||||||
|
EnvironmentName = "Development";
|
||||||
|
|
||||||
|
AppDataRoot = Path.Combine(Environment.CurrentDirectory, "appdata");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitReleaseSettings()
|
||||||
|
{
|
||||||
|
EnvironmentName = "Release";
|
||||||
|
|
||||||
|
var possibleDataRootsPaths = new List<string>()
|
||||||
|
{
|
||||||
|
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "FileTime"),
|
||||||
|
Path.Combine(Assembly.GetEntryAssembly()?.Location ?? ".", "fallbackDataRoot")
|
||||||
|
};
|
||||||
|
|
||||||
|
string? appDataRoot = null;
|
||||||
|
foreach (var possibleAppDataRoot in possibleDataRootsPaths)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var appDataRootDirectory = new DirectoryInfo(possibleAppDataRoot);
|
||||||
|
if (!appDataRootDirectory.Exists) appDataRootDirectory.Create();
|
||||||
|
|
||||||
|
appDataRoot = possibleAppDataRoot;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AppDataRoot = appDataRoot ?? throw new UnauthorizedAccessException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Text.Json;
|
||||||
|
using FileTime.App.Core.Models;
|
||||||
|
using FileTime.App.Core.ViewModels;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Services;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
using FileTime.Providers.Local;
|
||||||
|
using InitableService;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
|
namespace FileTime.App.Core.Services.Persistence;
|
||||||
|
|
||||||
|
public class TabPersistenceService : ITabPersistenceService
|
||||||
|
{
|
||||||
|
private readonly IAppState _appState;
|
||||||
|
private readonly ILogger<TabPersistenceService> _logger;
|
||||||
|
|
||||||
|
private class PersistenceRoot
|
||||||
|
{
|
||||||
|
public TabStates? TabStates { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TabStates
|
||||||
|
{
|
||||||
|
public List<TabState>? Tabs { get; set; }
|
||||||
|
public int? ActiveTabNumber { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TabState
|
||||||
|
{
|
||||||
|
public string? Path { get; set; }
|
||||||
|
public int Number { get; set; }
|
||||||
|
|
||||||
|
public TabState()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public TabState(FullName path, int number)
|
||||||
|
{
|
||||||
|
Path = path.Path;
|
||||||
|
Number = number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly string _settingsPath;
|
||||||
|
private readonly JsonSerializerOptions _jsonOptions;
|
||||||
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
private readonly ILocalContentProvider _localContentProvider;
|
||||||
|
|
||||||
|
public TabPersistenceService(
|
||||||
|
IApplicationSettings applicationSettings,
|
||||||
|
IAppState appState,
|
||||||
|
ITimelessContentProvider timelessContentProvider,
|
||||||
|
IServiceProvider serviceProvider,
|
||||||
|
ILocalContentProvider localContentProvider,
|
||||||
|
ILogger<TabPersistenceService> logger)
|
||||||
|
{
|
||||||
|
_appState = appState;
|
||||||
|
_logger = logger;
|
||||||
|
_settingsPath = Path.Combine(applicationSettings.AppDataRoot, "savedState.json");
|
||||||
|
_timelessContentProvider = timelessContentProvider;
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
_localContentProvider = localContentProvider;
|
||||||
|
|
||||||
|
_jsonOptions = new JsonSerializerOptions()
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true,
|
||||||
|
WriteIndented = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task ExitAsync()
|
||||||
|
{
|
||||||
|
SaveStates();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadStatesAsync()
|
||||||
|
{
|
||||||
|
if (!File.Exists(_settingsPath)) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await using var stateReader = File.OpenRead(_settingsPath);
|
||||||
|
var state = await JsonSerializer.DeserializeAsync<PersistenceRoot>(stateReader);
|
||||||
|
if (state != null)
|
||||||
|
{
|
||||||
|
await RestoreTabs(state.TabStates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Unknown exception while restoring app state");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async Task RestoreTabs(TabStates? tabStates)
|
||||||
|
{
|
||||||
|
if (tabStates == null
|
||||||
|
|| tabStates.Tabs == null)
|
||||||
|
{
|
||||||
|
CreateEmptyTab();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (var tab in tabStates.Tabs)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (tab.Path == null) continue;
|
||||||
|
|
||||||
|
IContainer? container = null;
|
||||||
|
var path = new FullName(tab.Path);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pathItem = await _timelessContentProvider.GetItemByFullNameAsync(path, PointInTime.Present);
|
||||||
|
|
||||||
|
container = pathItem switch
|
||||||
|
{
|
||||||
|
IContainer c => c,
|
||||||
|
IElement e => 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;
|
||||||
|
|
||||||
|
var tabToLoad = _serviceProvider.GetInitableResolver(container)
|
||||||
|
.GetRequiredService<ITab>();
|
||||||
|
var tabViewModel = _serviceProvider.GetInitableResolver(tabToLoad, tab.Number).GetRequiredService<ITabViewModel>();
|
||||||
|
|
||||||
|
_appState.AddTab(tabViewModel);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Unkown exception while restoring tab. {TabState}", JsonSerializer.Serialize(tab, _jsonOptions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Unkown exception while restoring tabs.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_appState.Tabs.Count == 0)
|
||||||
|
{
|
||||||
|
CreateEmptyTab();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var tabToActivate = _appState.Tabs.FirstOrDefault(t => t.TabNumber == tabStates.ActiveTabNumber);
|
||||||
|
if (tabToActivate is not null) _appState.SetSelectedTab(tabToActivate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateEmptyTab()
|
||||||
|
{
|
||||||
|
var tab = _serviceProvider.GetInitableResolver<IContainer>(_localContentProvider)
|
||||||
|
.GetRequiredService<ITab>();
|
||||||
|
var tabViewModel = _serviceProvider.GetInitableResolver(tab, 1).GetRequiredService<ITabViewModel>();
|
||||||
|
|
||||||
|
_appState.AddTab(tabViewModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveStates()
|
||||||
|
{
|
||||||
|
var state = new PersistenceRoot
|
||||||
|
{
|
||||||
|
TabStates = SerializeTabStates()
|
||||||
|
};
|
||||||
|
var settingsDirectory = new DirectoryInfo(string.Join(Path.DirectorySeparatorChar, _settingsPath.Split(Path.DirectorySeparatorChar)[0..^1]));
|
||||||
|
if (!settingsDirectory.Exists) settingsDirectory.Create();
|
||||||
|
var serializedData = JsonSerializer.Serialize(state, _jsonOptions);
|
||||||
|
File.WriteAllText(_settingsPath, serializedData);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TabStates SerializeTabStates()
|
||||||
|
{
|
||||||
|
var tabStates = new List<TabState>();
|
||||||
|
foreach (var tab in _appState.Tabs)
|
||||||
|
{
|
||||||
|
var currentLocation = tab.CachedCurrentLocation;
|
||||||
|
if (currentLocation is null) continue;
|
||||||
|
tabStates.Add(new TabState(currentLocation.FullName!, tab.TabNumber));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TabStates()
|
||||||
|
{
|
||||||
|
Tabs = tabStates,
|
||||||
|
ActiveTabNumber = _appState.CurrentSelectedTab?.TabNumber
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InitAsync()
|
||||||
|
{
|
||||||
|
await LoadStatesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,9 +22,11 @@ public static class Startup
|
|||||||
serviceCollection.TryAddSingleton<IUserCommandHandlerService, UserCommandHandlerService>();
|
serviceCollection.TryAddSingleton<IUserCommandHandlerService, UserCommandHandlerService>();
|
||||||
serviceCollection.TryAddSingleton<IClipboardService, ClipboardService>();
|
serviceCollection.TryAddSingleton<IClipboardService, ClipboardService>();
|
||||||
serviceCollection.TryAddSingleton<IIdentifiableUserCommandService, IdentifiableUserCommandService>();
|
serviceCollection.TryAddSingleton<IIdentifiableUserCommandService, IdentifiableUserCommandService>();
|
||||||
serviceCollection.TryAddSingleton<IStartupHandler, DefaultIdentifiableCommandHandlerRegister>();
|
|
||||||
serviceCollection.TryAddSingleton<IItemPreviewService, ItemPreviewService>();
|
serviceCollection.TryAddSingleton<IItemPreviewService, ItemPreviewService>();
|
||||||
return serviceCollection.AddCommandHandlers();
|
|
||||||
|
return serviceCollection
|
||||||
|
.AddCommandHandlers()
|
||||||
|
.AddSingleton<IStartupHandler, DefaultIdentifiableCommandHandlerRegister>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddCommandHandlers(this IServiceCollection serviceCollection)
|
private static IServiceCollection AddCommandHandlers(this IServiceCollection serviceCollection)
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ public class DefaultIdentifiableCommandHandlerRegister : IStartupHandler
|
|||||||
AddUserCommand(SwitchToTabCommand.SwitchToTab8);
|
AddUserCommand(SwitchToTabCommand.SwitchToTab8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task InitAsync() => Task.CompletedTask;
|
||||||
|
|
||||||
private void AddUserCommand(IIdentifiableUserCommand command)
|
private void AddUserCommand(IIdentifiableUserCommand command)
|
||||||
=> _service.AddIdentifiableUserCommandFactory(command.UserCommandID, () => command);
|
=> _service.AddIdentifiableUserCommandFactory(command.UserCommandID, () => command);
|
||||||
}
|
}
|
||||||
@@ -43,7 +43,8 @@ public partial class TabViewModel : ITabViewModel
|
|||||||
null!;
|
null!;
|
||||||
|
|
||||||
public IObservable<IReadOnlyCollection<IItemViewModel>?>
|
public IObservable<IReadOnlyCollection<IItemViewModel>?>
|
||||||
SelectedsChildrenCollectionObservable { get; private set; } = null!;
|
SelectedsChildrenCollectionObservable
|
||||||
|
{ get; private set; } = null!;
|
||||||
|
|
||||||
[Property] private BindedCollection<IItemViewModel>? _currentItemsCollection;
|
[Property] private BindedCollection<IItemViewModel>? _currentItemsCollection;
|
||||||
|
|
||||||
@@ -51,6 +52,8 @@ public partial class TabViewModel : ITabViewModel
|
|||||||
|
|
||||||
[Property] private BindedCollection<IItemViewModel>? _selectedsChildrenCollection;
|
[Property] private BindedCollection<IItemViewModel>? _selectedsChildrenCollection;
|
||||||
|
|
||||||
|
public IContainer? CachedCurrentLocation { get; private set; }
|
||||||
|
|
||||||
public TabViewModel(
|
public TabViewModel(
|
||||||
IServiceProvider serviceProvider,
|
IServiceProvider serviceProvider,
|
||||||
IItemNameConverterService itemNameConverterService,
|
IItemNameConverterService itemNameConverterService,
|
||||||
@@ -74,6 +77,8 @@ public partial class TabViewModel : ITabViewModel
|
|||||||
tab.AddToDisposables(_disposables);
|
tab.AddToDisposables(_disposables);
|
||||||
|
|
||||||
CurrentLocation = tab.CurrentLocation.AsObservable();
|
CurrentLocation = tab.CurrentLocation.AsObservable();
|
||||||
|
CurrentLocation.Subscribe(l => CachedCurrentLocation = l).AddToDisposables(_disposables);
|
||||||
|
|
||||||
CurrentItems = tab.CurrentItems
|
CurrentItems = tab.CurrentItems
|
||||||
.Select(items => items?.Transform(i => MapItemToViewModel(i, ItemViewModelType.Main)))
|
.Select(items => items?.Transform(i => MapItemToViewModel(i, ItemViewModelType.Main)))
|
||||||
/*.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
/*.ObserveOn(_rxSchedulerService.GetWorkerScheduler())
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
using FileTime.App.Core;
|
using FileTime.App.Core;
|
||||||
|
using FileTime.App.Core.Models;
|
||||||
|
using FileTime.App.Core.Services;
|
||||||
|
using FileTime.App.Core.Services.Persistence;
|
||||||
using FileTime.Core.Command;
|
using FileTime.Core.Command;
|
||||||
using FileTime.Core.Command.CreateContainer;
|
using FileTime.Core.Command.CreateContainer;
|
||||||
using FileTime.Core.Command.CreateElement;
|
using FileTime.Core.Command.CreateElement;
|
||||||
@@ -21,8 +24,12 @@ public static class DependencyInjection
|
|||||||
serviceCollection.TryAddSingleton<ITimelessContentProvider, TimelessContentProvider>();
|
serviceCollection.TryAddSingleton<ITimelessContentProvider, TimelessContentProvider>();
|
||||||
serviceCollection.TryAddSingleton<ICommandRunner, CommandRunner>();
|
serviceCollection.TryAddSingleton<ICommandRunner, CommandRunner>();
|
||||||
serviceCollection.TryAddSingleton<IContentAccessorFactory, ContentAccessorFactory>();
|
serviceCollection.TryAddSingleton<IContentAccessorFactory, ContentAccessorFactory>();
|
||||||
serviceCollection.TryAddSingleton<ITab, Tab>();
|
|
||||||
serviceCollection.TryAddSingleton<ILocalCommandExecutor, LocalCommandExecutor>();
|
serviceCollection.TryAddSingleton<ILocalCommandExecutor, LocalCommandExecutor>();
|
||||||
|
serviceCollection.TryAddSingleton<IApplicationSettings, ApplicationSettings>();
|
||||||
|
serviceCollection.TryAddSingleton<ITabPersistenceService, TabPersistenceService>();
|
||||||
|
serviceCollection.TryAddTransient<ITab, Tab>();
|
||||||
|
serviceCollection.AddSingleton<IExitHandler, ITabPersistenceService>(sp => sp.GetRequiredService<ITabPersistenceService>());
|
||||||
|
serviceCollection.AddSingleton<IStartupHandler, ITabPersistenceService>(sp => sp.GetRequiredService<ITabPersistenceService>());
|
||||||
|
|
||||||
return serviceCollection
|
return serviceCollection
|
||||||
.AddCoreAppServices()
|
.AddCoreAppServices()
|
||||||
|
|||||||
@@ -35,13 +35,14 @@ public static class Startup
|
|||||||
serviceCollection.TryAddSingleton<IDefaultModeKeyInputHandler, DefaultModeKeyInputHandler>();
|
serviceCollection.TryAddSingleton<IDefaultModeKeyInputHandler, DefaultModeKeyInputHandler>();
|
||||||
serviceCollection.TryAddSingleton<IKeyboardConfigurationService, KeyboardConfigurationService>();
|
serviceCollection.TryAddSingleton<IKeyboardConfigurationService, KeyboardConfigurationService>();
|
||||||
serviceCollection.TryAddSingleton<IRapidTravelModeKeyInputHandler, RapidTravelModeKeyInputHandler>();
|
serviceCollection.TryAddSingleton<IRapidTravelModeKeyInputHandler, RapidTravelModeKeyInputHandler>();
|
||||||
serviceCollection.TryAddSingleton<IStartupHandler, RootDriveInfoService>();
|
|
||||||
serviceCollection.TryAddSingleton<LifecycleService>();
|
serviceCollection.TryAddSingleton<LifecycleService>();
|
||||||
serviceCollection.TryAddSingleton<IIconProvider, MaterialIconProvider>();
|
serviceCollection.TryAddSingleton<IIconProvider, MaterialIconProvider>();
|
||||||
serviceCollection.TryAddSingleton<IModalService, ModalService>();
|
serviceCollection.TryAddSingleton<IModalService, ModalService>();
|
||||||
serviceCollection.TryAddSingleton<IDialogService, DialogService>();
|
serviceCollection.TryAddSingleton<IDialogService, DialogService>();
|
||||||
serviceCollection.TryAddSingleton<IInputInterface>(s => s.GetRequiredService<IDialogService>());
|
serviceCollection.TryAddSingleton<IInputInterface>(s => s.GetRequiredService<IDialogService>());
|
||||||
return serviceCollection;
|
|
||||||
|
return serviceCollection
|
||||||
|
.AddSingleton<IStartupHandler, RootDriveInfoService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IServiceCollection RegisterLogging(this IServiceCollection serviceCollection)
|
internal static IServiceCollection RegisterLogging(this IServiceCollection serviceCollection)
|
||||||
|
|||||||
@@ -5,13 +5,23 @@ namespace FileTime.GuiApp.Services;
|
|||||||
public class LifecycleService
|
public class LifecycleService
|
||||||
{
|
{
|
||||||
private readonly IEnumerable<IExitHandler> _exitHandlers;
|
private readonly IEnumerable<IExitHandler> _exitHandlers;
|
||||||
|
private readonly IEnumerable<IStartupHandler> _startupHandlers;
|
||||||
|
|
||||||
public LifecycleService(IEnumerable<IStartupHandler> startupHandlers, IEnumerable<IExitHandler> exitHandlers)
|
public LifecycleService(IEnumerable<IStartupHandler> startupHandlers, IEnumerable<IExitHandler> exitHandlers)
|
||||||
{
|
{
|
||||||
_exitHandlers = exitHandlers;
|
_exitHandlers = exitHandlers;
|
||||||
|
_startupHandlers = startupHandlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Exit()
|
public async Task InitStartupHandlersAsync()
|
||||||
|
{
|
||||||
|
foreach (var startupHandler in _startupHandlers)
|
||||||
|
{
|
||||||
|
await startupHandler.InitAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ExitAsync()
|
||||||
{
|
{
|
||||||
foreach (var exitHandler in _exitHandlers)
|
foreach (var exitHandler in _exitHandlers)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class RootDriveInfoService : IStartupHandler
|
|||||||
{
|
{
|
||||||
var containerPath = localContentProvider.GetNativePath(i.Path).Path;
|
var containerPath = localContentProvider.GetNativePath(i.Path).Path;
|
||||||
var drivePath = d.Name.TrimEnd(Path.DirectorySeparatorChar);
|
var drivePath = d.Name.TrimEnd(Path.DirectorySeparatorChar);
|
||||||
return containerPath == drivePath
|
return containerPath == drivePath
|
||||||
|| (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && containerPath == "/" && d.Name == "/");
|
|| (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && containerPath == "/" && d.Name == "/");
|
||||||
})))
|
})))
|
||||||
.Filter(t => t.Drive is not null);
|
.Filter(t => t.Drive is not null);
|
||||||
@@ -68,4 +68,6 @@ public class RootDriveInfoService : IStartupHandler
|
|||||||
_rootDrives.AddRange(drives);
|
_rootDrives.AddRange(drives);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task InitAsync() => Task.CompletedTask;
|
||||||
}
|
}
|
||||||
@@ -50,14 +50,16 @@ public partial class MainWindowViewModel : IMainWindowViewModelBase
|
|||||||
Title = "FileTime " + versionString;
|
Title = "FileTime " + versionString;
|
||||||
|
|
||||||
//TODO: refactor
|
//TODO: refactor
|
||||||
if (AppState.Tabs.Count == 0)
|
/*if (AppState.Tabs.Count == 0)
|
||||||
{
|
{
|
||||||
var tab = _serviceProvider.GetInitableResolver<IContainer>(_localContentProvider)
|
var tab = _serviceProvider.GetInitableResolver<IContainer>(_localContentProvider)
|
||||||
.GetRequiredService<ITab>();
|
.GetRequiredService<ITab>();
|
||||||
var tabViewModel = _serviceProvider.GetInitableResolver(tab, 1).GetRequiredService<ITabViewModel>();
|
var tabViewModel = _serviceProvider.GetInitableResolver(tab, 1).GetRequiredService<ITabViewModel>();
|
||||||
|
|
||||||
_appState.AddTab(tabViewModel);
|
_appState.AddTab(tabViewModel);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
_lifecycleService.InitStartupHandlersAsync().Wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action<bool> setHandled)
|
public void ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action<bool> setHandled)
|
||||||
@@ -72,4 +74,9 @@ public partial class MainWindowViewModel : IMainWindowViewModelBase
|
|||||||
await UserCommandHandlerService.HandleCommandAsync(
|
await UserCommandHandlerService.HandleCommandAsync(
|
||||||
new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, resolvedContainer)));
|
new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, resolvedContainer)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task OnExit()
|
||||||
|
{
|
||||||
|
await _lifecycleService.ExitAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
Icon="/Assets/filetime.ico"
|
Icon="/Assets/filetime.ico"
|
||||||
InputElement.KeyDown="OnKeyDown"
|
InputElement.KeyDown="OnKeyDown"
|
||||||
Opened="OnWindowOpened"
|
Opened="OnWindowOpened"
|
||||||
|
Closed="OnWindowClosed"
|
||||||
TransparencyLevelHint="Blur"
|
TransparencyLevelHint="Blur"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ public partial class MainWindow : Window
|
|||||||
&& sender is StyledElement control)
|
&& sender is StyledElement control)
|
||||||
{
|
{
|
||||||
FullName? path = null;
|
FullName? path = null;
|
||||||
if (control.DataContext is IHaveFullPath { Path: { } } hasFullPath)
|
if (control.DataContext is IHaveFullPath {Path: { }} hasFullPath)
|
||||||
{
|
{
|
||||||
path = hasFullPath.Path;
|
path = hasFullPath.Path;
|
||||||
}
|
}
|
||||||
@@ -108,4 +108,10 @@ public partial class MainWindow : Window
|
|||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnWindowClosed(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
var vm = ViewModel;
|
||||||
|
Task.Run(() => vm?.OnExit()).Wait();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user