Top navigation, search delete
This commit is contained in:
@@ -15,32 +15,17 @@ public class TabPersistenceService : ITabPersistenceService
|
|||||||
private readonly IAppState _appState;
|
private readonly IAppState _appState;
|
||||||
private readonly ILogger<TabPersistenceService> _logger;
|
private readonly ILogger<TabPersistenceService> _logger;
|
||||||
|
|
||||||
private class PersistenceRoot
|
//TODO: make this a configuration maybe?
|
||||||
|
private readonly List<string> _contentProvidersNotToRestore = new()
|
||||||
{
|
{
|
||||||
public TabStates? TabStates { get; set; }
|
"search"
|
||||||
}
|
};
|
||||||
|
|
||||||
private class TabStates
|
private record PersistenceRoot(TabStates? TabStates);
|
||||||
{
|
|
||||||
public List<TabState>? Tabs { get; set; }
|
|
||||||
public int? ActiveTabNumber { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TabState
|
private record TabStates(List<TabState>? Tabs, int? ActiveTabNumber);
|
||||||
{
|
|
||||||
public string? Path { get; set; }
|
|
||||||
public int Number { get; set; }
|
|
||||||
|
|
||||||
public TabState()
|
private record TabState(string? Path, int Number);
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public TabState(FullName path, int number)
|
|
||||||
{
|
|
||||||
Path = path.Path;
|
|
||||||
Number = number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly string _settingsPath;
|
private readonly string _settingsPath;
|
||||||
private readonly JsonSerializerOptions _jsonOptions;
|
private readonly JsonSerializerOptions _jsonOptions;
|
||||||
@@ -149,7 +134,7 @@ public class TabPersistenceService : ITabPersistenceService
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
path = path.GetParent();
|
path = path?.GetParent();
|
||||||
if (path == null)
|
if (path == null)
|
||||||
{
|
{
|
||||||
throw new Exception($"Could not find an initializable path along {tab.Path}");
|
throw new Exception($"Could not find an initializable path along {tab.Path}");
|
||||||
@@ -159,6 +144,8 @@ public class TabPersistenceService : ITabPersistenceService
|
|||||||
|
|
||||||
if (container == null) continue;
|
if (container == null) continue;
|
||||||
|
|
||||||
|
if (_contentProvidersNotToRestore.Contains(container.Provider.Name)) continue;
|
||||||
|
|
||||||
var tabToLoad = await _serviceProvider.GetAsyncInitableResolver(container)
|
var tabToLoad = await _serviceProvider.GetAsyncInitableResolver(container)
|
||||||
.GetRequiredServiceAsync<ITab>();
|
.GetRequiredServiceAsync<ITab>();
|
||||||
var tabViewModel = _serviceProvider.GetInitableResolver(tabToLoad, tab.Number)
|
var tabViewModel = _serviceProvider.GetInitableResolver(tabToLoad, tab.Number)
|
||||||
@@ -181,7 +168,15 @@ public class TabPersistenceService : ITabPersistenceService
|
|||||||
|
|
||||||
if (_appState.Tabs.Count == 0) return false;
|
if (_appState.Tabs.Count == 0) return false;
|
||||||
|
|
||||||
var tabToActivate = _appState.Tabs.FirstOrDefault(t => t.TabNumber == tabStates.ActiveTabNumber);
|
var optimalTabs = _appState
|
||||||
|
.Tabs
|
||||||
|
.TakeWhile(t => t.TabNumber <= tabStates.ActiveTabNumber)
|
||||||
|
.Reverse();
|
||||||
|
var suboptimalTabs = _appState
|
||||||
|
.Tabs
|
||||||
|
.SkipWhile(t => t.TabNumber <= tabStates.ActiveTabNumber);
|
||||||
|
|
||||||
|
var tabToActivate = optimalTabs.Concat(suboptimalTabs).FirstOrDefault();
|
||||||
if (tabToActivate is not null) _appState.SetSelectedTab(tabToActivate);
|
if (tabToActivate is not null) _appState.SetSelectedTab(tabToActivate);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -189,10 +184,8 @@ public class TabPersistenceService : ITabPersistenceService
|
|||||||
|
|
||||||
public void SaveStates(CancellationToken token = default)
|
public void SaveStates(CancellationToken token = default)
|
||||||
{
|
{
|
||||||
var state = new PersistenceRoot
|
var state = new PersistenceRoot(SerializeTabStates());
|
||||||
{
|
|
||||||
TabStates = SerializeTabStates()
|
|
||||||
};
|
|
||||||
var settingsDirectory = new DirectoryInfo(string.Join(Path.DirectorySeparatorChar,
|
var settingsDirectory = new DirectoryInfo(string.Join(Path.DirectorySeparatorChar,
|
||||||
_settingsPath.Split(Path.DirectorySeparatorChar)[0..^1]));
|
_settingsPath.Split(Path.DirectorySeparatorChar)[0..^1]));
|
||||||
if (!settingsDirectory.Exists) settingsDirectory.Create();
|
if (!settingsDirectory.Exists) settingsDirectory.Create();
|
||||||
@@ -207,14 +200,13 @@ public class TabPersistenceService : ITabPersistenceService
|
|||||||
{
|
{
|
||||||
var currentLocation = tab.CurrentLocation.Value;
|
var currentLocation = tab.CurrentLocation.Value;
|
||||||
if (currentLocation is null) continue;
|
if (currentLocation is null) continue;
|
||||||
tabStates.Add(new TabState(currentLocation.FullName!, tab.TabNumber));
|
tabStates.Add(new TabState(currentLocation.FullName!.Path, tab.TabNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TabStates
|
return new TabStates(
|
||||||
{
|
tabStates,
|
||||||
Tabs = tabStates,
|
_appState.CurrentSelectedTab?.TabNumber
|
||||||
ActiveTabNumber = _appState.CurrentSelectedTab?.TabNumber
|
);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task InitAsync()
|
public async Task InitAsync()
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ using FileTime.App.Core.UserCommand;
|
|||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
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.Move;
|
using FileTime.Core.Command.Move;
|
||||||
using FileTime.Core.Extensions;
|
using FileTime.Core.Extensions;
|
||||||
using FileTime.Core.Interactions;
|
using FileTime.Core.Interactions;
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
{
|
{
|
||||||
private readonly ISystemClipboardService _systemClipboardService;
|
private readonly ISystemClipboardService _systemClipboardService;
|
||||||
private readonly IUserCommunicationService _userCommunicationService;
|
private readonly IUserCommunicationService _userCommunicationService;
|
||||||
private readonly ISearchManager _searchManager;
|
private readonly ISearchContentProvider _searchContentProvider;
|
||||||
private readonly IItemNameConverterService _itemNameConverterService;
|
private readonly IItemNameConverterService _itemNameConverterService;
|
||||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
private readonly IUserCommandHandlerService _userCommandHandlerService;
|
private readonly IUserCommandHandlerService _userCommandHandlerService;
|
||||||
@@ -28,7 +28,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
IAppState appState,
|
IAppState appState,
|
||||||
ISystemClipboardService systemClipboardService,
|
ISystemClipboardService systemClipboardService,
|
||||||
IUserCommunicationService userCommunicationService,
|
IUserCommunicationService userCommunicationService,
|
||||||
ISearchManager searchManager,
|
ISearchContentProvider searchContentProvider,
|
||||||
IItemNameConverterService itemNameConverterService,
|
IItemNameConverterService itemNameConverterService,
|
||||||
ITimelessContentProvider timelessContentProvider,
|
ITimelessContentProvider timelessContentProvider,
|
||||||
IUserCommandHandlerService userCommandHandlerService,
|
IUserCommandHandlerService userCommandHandlerService,
|
||||||
@@ -36,7 +36,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
{
|
{
|
||||||
_systemClipboardService = systemClipboardService;
|
_systemClipboardService = systemClipboardService;
|
||||||
_userCommunicationService = userCommunicationService;
|
_userCommunicationService = userCommunicationService;
|
||||||
_searchManager = searchManager;
|
_searchContentProvider = searchContentProvider;
|
||||||
_itemNameConverterService = itemNameConverterService;
|
_itemNameConverterService = itemNameConverterService;
|
||||||
_timelessContentProvider = timelessContentProvider;
|
_timelessContentProvider = timelessContentProvider;
|
||||||
_userCommandHandlerService = userCommandHandlerService;
|
_userCommandHandlerService = userCommandHandlerService;
|
||||||
@@ -113,7 +113,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
|||||||
_ => throw new ArgumentOutOfRangeException()
|
_ => throw new ArgumentOutOfRangeException()
|
||||||
};
|
};
|
||||||
|
|
||||||
var searchTask = await _searchManager.StartSearchAsync(searchMatcher, _currentLocation.Value);
|
var searchTask = await _searchContentProvider.StartSearchAsync(searchMatcher, _currentLocation.Value);
|
||||||
var openContainerCommand = new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, searchTask.SearchContainer));
|
var openContainerCommand = new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, searchTask.SearchContainer));
|
||||||
await _userCommandHandlerService.HandleCommandAsync(openContainerCommand);
|
await _userCommandHandlerService.HandleCommandAsync(openContainerCommand);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ public abstract partial class ItemViewModel : IItemViewModel
|
|||||||
var displayName = itemViewModelType switch
|
var displayName = itemViewModelType switch
|
||||||
{
|
{
|
||||||
ItemViewModelType.Main => _appState.RapidTravelText.Map(s => (IReadOnlyList<ItemNamePart>) _itemNameConverterService.GetDisplayName(item.DisplayName, s)),
|
ItemViewModelType.Main => _appState.RapidTravelText.Map(s => (IReadOnlyList<ItemNamePart>) _itemNameConverterService.GetDisplayName(item.DisplayName, s)),
|
||||||
_ => new DeclarativeProperty<IReadOnlyList<ItemNamePart>>(new List<ItemNamePart> {new (item.DisplayName)}),
|
_ => new DeclarativeProperty<IReadOnlyList<ItemNamePart>>(new List<ItemNamePart> {new(item.DisplayName)}),
|
||||||
};
|
};
|
||||||
|
|
||||||
BaseItem = item;
|
BaseItem = item;
|
||||||
@@ -103,6 +103,6 @@ public abstract partial class ItemViewModel : IItemViewModel
|
|||||||
var deepestPath = _parentTab.Tab.LastDeepestSelectedPath;
|
var deepestPath = _parentTab.Tab.LastDeepestSelectedPath;
|
||||||
var commonPath = FullName.CreateSafe(PathHelper.GetCommonPath(ownFullName.Path, deepestPath.Path));
|
var commonPath = FullName.CreateSafe(PathHelper.GetCommonPath(ownFullName.Path, deepestPath.Path));
|
||||||
|
|
||||||
return commonPath.Path == ownFullName.Path;
|
return commonPath is not null && commonPath.Path == ownFullName.Path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,7 +198,7 @@ public partial class TabViewModel : ITabViewModel
|
|||||||
|
|
||||||
private static async Task<IItem> MapItemAsync(AbsolutePath item)
|
private static async Task<IItem> MapItemAsync(AbsolutePath item)
|
||||||
=> await item.ResolveAsync(forceResolve: true,
|
=> await item.ResolveAsync(forceResolve: true,
|
||||||
itemInitializationSettings: new ItemInitializationSettings(true));
|
itemInitializationSettings: new ItemInitializationSettings {SkipChildInitialization = true});
|
||||||
|
|
||||||
private IItemViewModel MapItemToViewModel(IItem item, ItemViewModelType type)
|
private IItemViewModel MapItemToViewModel(IItem item, ItemViewModelType type)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public static class DependencyInjection
|
|||||||
serviceCollection.TryAddSingleton<ICommandRunner, CommandRunner>();
|
serviceCollection.TryAddSingleton<ICommandRunner, CommandRunner>();
|
||||||
serviceCollection.TryAddSingleton<IContentAccessorFactory, ContentAccessorFactory>();
|
serviceCollection.TryAddSingleton<IContentAccessorFactory, ContentAccessorFactory>();
|
||||||
serviceCollection.TryAddSingleton<IContentProviderRegistry, ContentProviderRegistry>();
|
serviceCollection.TryAddSingleton<IContentProviderRegistry, ContentProviderRegistry>();
|
||||||
|
serviceCollection.TryAddSingleton<IRootContentProvider, RootContentProvider>();
|
||||||
//TODO: check local/remote context
|
//TODO: check local/remote context
|
||||||
serviceCollection.TryAddSingleton<ILocalCommandExecutor, LocalCommandExecutor>();
|
serviceCollection.TryAddSingleton<ILocalCommandExecutor, LocalCommandExecutor>();
|
||||||
serviceCollection.TryAddSingleton<ICommandSchedulerNotifier, LocalCommandSchedulerNotifier>();
|
serviceCollection.TryAddSingleton<ICommandSchedulerNotifier, LocalCommandSchedulerNotifier>();
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
using FileTime.Core.ContentAccess;
|
using FileTime.Core.ContentAccess;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.App.Search;
|
namespace FileTime.App.Search;
|
||||||
|
|
||||||
public interface ISearchContentProvider : IContentProvider
|
public interface ISearchContentProvider : IContentProvider
|
||||||
{
|
{
|
||||||
|
Task<ISearchTask> StartSearchAsync(ISearchMatcher matcher, IContainer searchIn);
|
||||||
|
void RemoveSearch(FullName searchFullName);
|
||||||
}
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
using FileTime.Core.Models;
|
|
||||||
|
|
||||||
namespace FileTime.App.Search;
|
|
||||||
|
|
||||||
public interface ISearchManager
|
|
||||||
{
|
|
||||||
Task<ISearchTask> StartSearchAsync(ISearchMatcher matcher, IContainer searchIn);
|
|
||||||
IReadOnlyList<ISearchTask> SearchTasks { get; }
|
|
||||||
}
|
|
||||||
@@ -7,12 +7,14 @@ namespace FileTime.App.Search;
|
|||||||
|
|
||||||
public class SearchContentProvider : ContentProviderBase, ISearchContentProvider
|
public class SearchContentProvider : ContentProviderBase, ISearchContentProvider
|
||||||
{
|
{
|
||||||
private readonly ISearchManager _searchManager;
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
|
private readonly List<SearchTask> _searchTasks = new();
|
||||||
public const string ContentProviderName = "search";
|
public const string ContentProviderName = "search";
|
||||||
|
|
||||||
public SearchContentProvider(ISearchManager searchManager) : base(ContentProviderName)
|
public SearchContentProvider(ITimelessContentProvider timelessContentProvider)
|
||||||
|
: base(ContentProviderName, timelessContentProvider)
|
||||||
{
|
{
|
||||||
_searchManager = searchManager;
|
_timelessContentProvider = timelessContentProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<IItem> GetItemByNativePathAsync(
|
public override Task<IItem> GetItemByNativePathAsync(
|
||||||
@@ -21,9 +23,12 @@ public class SearchContentProvider : ContentProviderBase, ISearchContentProvider
|
|||||||
bool forceResolve = false,
|
bool forceResolve = false,
|
||||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
ItemInitializationSettings itemInitializationSettings = default
|
ItemInitializationSettings itemInitializationSettings = default
|
||||||
) =>
|
)
|
||||||
Task.FromResult((IItem) _searchManager.SearchTasks
|
{
|
||||||
|
if (nativePath.Path == ContentProviderName) return Task.FromResult((IItem) this);
|
||||||
|
return Task.FromResult((IItem) _searchTasks
|
||||||
.First(searchTask => searchTask.SearchContainer.NativePath == nativePath).SearchContainer);
|
.First(searchTask => searchTask.SearchContainer.NativePath == nativePath).SearchContainer);
|
||||||
|
}
|
||||||
|
|
||||||
public override NativePath GetNativePath(FullName fullName) => new(fullName.Path);
|
public override NativePath GetNativePath(FullName fullName) => new(fullName.Path);
|
||||||
public override FullName GetFullName(NativePath nativePath) => new(nativePath.Path);
|
public override FullName GetFullName(NativePath nativePath) => new(nativePath.Path);
|
||||||
@@ -36,4 +41,34 @@ public class SearchContentProvider : ContentProviderBase, ISearchContentProvider
|
|||||||
=> Task.FromResult(null as byte[]);
|
=> Task.FromResult(null as byte[]);
|
||||||
|
|
||||||
public override bool CanHandlePath(NativePath path) => path.Path.StartsWith(ContentProviderName);
|
public override bool CanHandlePath(NativePath path) => path.Path.StartsWith(ContentProviderName);
|
||||||
|
|
||||||
|
public async Task<ISearchTask> StartSearchAsync(ISearchMatcher matcher, IContainer searchIn)
|
||||||
|
{
|
||||||
|
var searchTask = new SearchTask(
|
||||||
|
searchIn,
|
||||||
|
this,
|
||||||
|
_timelessContentProvider,
|
||||||
|
matcher,
|
||||||
|
new AbsolutePath(_timelessContentProvider, this)
|
||||||
|
);
|
||||||
|
|
||||||
|
_searchTasks.Add(searchTask);
|
||||||
|
await searchTask.StartAsync();
|
||||||
|
Items.Add(new AbsolutePath(_timelessContentProvider, searchTask.SearchContainer));
|
||||||
|
|
||||||
|
return searchTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveSearch(FullName searchFullName)
|
||||||
|
{
|
||||||
|
var searchTask = _searchTasks.FirstOrDefault(t => t.SearchContainer.FullName == searchFullName);
|
||||||
|
if (searchTask is null) return;
|
||||||
|
|
||||||
|
_searchTasks.Remove(searchTask);
|
||||||
|
var searchItem = Items.FirstOrDefault(c => c.Path == searchTask.SearchContainer.FullName);
|
||||||
|
if (searchItem is not null)
|
||||||
|
{
|
||||||
|
Items.Remove(searchItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
13
src/AppCommon/FileTime.App.Search/SearchItemDeleter.cs
Normal file
13
src/AppCommon/FileTime.App.Search/SearchItemDeleter.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using FileTime.Core.ContentAccess;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.App.Search;
|
||||||
|
|
||||||
|
public class SearchItemDeleter : IItemDeleter<ISearchContentProvider>
|
||||||
|
{
|
||||||
|
public Task DeleteAsync(ISearchContentProvider contentProvider, FullName fullName)
|
||||||
|
{
|
||||||
|
contentProvider.RemoveSearch(fullName);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
using FileTime.Core.Models;
|
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
|
||||||
|
|
||||||
namespace FileTime.App.Search;
|
|
||||||
|
|
||||||
public class SearchManager : ISearchManager
|
|
||||||
{
|
|
||||||
private readonly IServiceProvider _serviceProvider;
|
|
||||||
private ISearchContentProvider? _searchContainerProvider;
|
|
||||||
private readonly List<SearchTask> _searchTasks = new();
|
|
||||||
|
|
||||||
public IReadOnlyList<ISearchTask> SearchTasks { get; }
|
|
||||||
|
|
||||||
public SearchManager(IServiceProvider serviceProvider)
|
|
||||||
{
|
|
||||||
_serviceProvider = serviceProvider;
|
|
||||||
SearchTasks = _searchTasks.AsReadOnly();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<ISearchTask> StartSearchAsync(ISearchMatcher matcher, IContainer searchIn)
|
|
||||||
{
|
|
||||||
_searchContainerProvider ??= _serviceProvider.GetRequiredService<ISearchContentProvider>();
|
|
||||||
var searchTask = new SearchTask(
|
|
||||||
searchIn,
|
|
||||||
_searchContainerProvider,
|
|
||||||
matcher
|
|
||||||
);
|
|
||||||
|
|
||||||
_searchTasks.Add(searchTask);
|
|
||||||
|
|
||||||
await searchTask.StartAsync();
|
|
||||||
|
|
||||||
return searchTask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -10,6 +10,7 @@ namespace FileTime.App.Search;
|
|||||||
public class SearchTask : ISearchTask
|
public class SearchTask : ISearchTask
|
||||||
{
|
{
|
||||||
private readonly IContainer _baseContainer;
|
private readonly IContainer _baseContainer;
|
||||||
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
private readonly ISearchMatcher _matcher;
|
private readonly ISearchMatcher _matcher;
|
||||||
private readonly Container _container;
|
private readonly Container _container;
|
||||||
private readonly ObservableCollection<Exception> _exceptions = new();
|
private readonly ObservableCollection<Exception> _exceptions = new();
|
||||||
@@ -22,19 +23,22 @@ public class SearchTask : ISearchTask
|
|||||||
|
|
||||||
public SearchTask(
|
public SearchTask(
|
||||||
IContainer baseContainer,
|
IContainer baseContainer,
|
||||||
IContentProvider contentProvider,
|
ISearchContentProvider contentProvider,
|
||||||
ISearchMatcher matcher
|
ITimelessContentProvider timelessContentProvider,
|
||||||
|
ISearchMatcher matcher,
|
||||||
|
AbsolutePath parent
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var randomId = $"{SearchContentProvider.ContentProviderName}/{_searchId++}_{baseContainer.Name}";
|
var randomId = $"{SearchContentProvider.ContentProviderName}/{_searchId++}_{baseContainer.Name}";
|
||||||
_baseContainer = baseContainer;
|
_baseContainer = baseContainer;
|
||||||
|
_timelessContentProvider = timelessContentProvider;
|
||||||
_matcher = matcher;
|
_matcher = matcher;
|
||||||
_container = new Container(
|
_container = new Container(
|
||||||
baseContainer.Name,
|
baseContainer.Name,
|
||||||
baseContainer.DisplayName,
|
baseContainer.DisplayName,
|
||||||
new FullName(randomId),
|
new FullName(randomId),
|
||||||
new NativePath(randomId),
|
new NativePath(randomId),
|
||||||
null,
|
parent,
|
||||||
false,
|
false,
|
||||||
true,
|
true,
|
||||||
null,
|
null,
|
||||||
@@ -85,7 +89,11 @@ public class SearchTask : ISearchTask
|
|||||||
|
|
||||||
foreach (var itemPath in items)
|
foreach (var itemPath in items)
|
||||||
{
|
{
|
||||||
var item = await itemPath.ResolveAsync();
|
var item = await itemPath.ResolveAsync(
|
||||||
|
itemInitializationSettings: new ItemInitializationSettings
|
||||||
|
{
|
||||||
|
Parent = new AbsolutePath(_timelessContentProvider, _container)
|
||||||
|
});
|
||||||
if (await _matcher.IsItemMatchAsync(item))
|
if (await _matcher.IsItemMatchAsync(item))
|
||||||
{
|
{
|
||||||
_items.Add(itemPath);
|
_items.Add(itemPath);
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ public static class Startup
|
|||||||
{
|
{
|
||||||
services.TryAddSingleton<ISearchContentProvider, SearchContentProvider>();
|
services.TryAddSingleton<ISearchContentProvider, SearchContentProvider>();
|
||||||
services.AddSingleton<IContentProvider>(sp => sp.GetRequiredService<ISearchContentProvider>());
|
services.AddSingleton<IContentProvider>(sp => sp.GetRequiredService<ISearchContentProvider>());
|
||||||
services.TryAddSingleton<ISearchManager, SearchManager>();
|
services.TryAddSingleton<IItemDeleter<ISearchContentProvider>, SearchItemDeleter>();
|
||||||
|
services.TryAddSingleton<IItemDeleter<SearchContentProvider>>(sp => sp.GetRequiredService<IItemDeleter<ISearchContentProvider>>());
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
namespace FileTime.Core.ContentAccess;
|
namespace FileTime.Core.ContentAccess;
|
||||||
|
|
||||||
public interface IContentProviderRegistry
|
public interface IContentProviderRegistry
|
||||||
{
|
{
|
||||||
IEnumerable<IContentProvider> ContentProviders { get; }
|
ReadOnlyObservableCollection<IContentProvider> ContentProviders { get; }
|
||||||
void AddContentProvider(IContentProvider contentProvider);
|
void AddContentProvider(IContentProvider contentProvider);
|
||||||
void RemoveContentProvider(IContentProvider contentProvider);
|
void RemoveContentProvider(IContentProvider contentProvider);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
namespace FileTime.Core.ContentAccess;
|
||||||
|
|
||||||
|
public interface IRootContentProvider : IContentProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,18 +4,22 @@ public record FullName(string Path)
|
|||||||
{
|
{
|
||||||
public FullName? GetParent()
|
public FullName? GetParent()
|
||||||
{
|
{
|
||||||
|
if (Path.Length == 0) return null;
|
||||||
var pathParts = Path.TrimEnd(Constants.SeparatorChar).Split(Constants.SeparatorChar);
|
var pathParts = Path.TrimEnd(Constants.SeparatorChar).Split(Constants.SeparatorChar);
|
||||||
return pathParts.Length switch
|
return pathParts.Length switch
|
||||||
{
|
{
|
||||||
> 1 => CreateSafe(string.Join(Constants.SeparatorChar, pathParts.SkipLast(1))),
|
> 1 => CreateSafe(string.Join(Constants.SeparatorChar, pathParts.SkipLast(1))),
|
||||||
_ => null
|
_ => CreateSafe("")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FullName? CreateSafe(string? path)
|
public static FullName? CreateSafe(string? path)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(path))
|
if (path is null)
|
||||||
return null;
|
return null;
|
||||||
|
if (string.IsNullOrWhiteSpace(path))
|
||||||
|
return new FullName("");
|
||||||
|
|
||||||
return new(path);
|
return new(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
namespace FileTime.Core.Models;
|
namespace FileTime.Core.Models;
|
||||||
|
|
||||||
public readonly struct ItemInitializationSettings
|
public sealed class ItemInitializationSettings
|
||||||
{
|
{
|
||||||
public readonly bool SkipChildInitialization;
|
public bool SkipChildInitialization { get; init; }
|
||||||
|
public AbsolutePath? Parent { get; init; }
|
||||||
public ItemInitializationSettings(bool skipChildInitialization)
|
|
||||||
{
|
|
||||||
SkipChildInitialization = skipChildInitialization;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,10 @@ public class DeleteCommand : CommandBase, IExecutableCommand
|
|||||||
new DeleteStrategy()
|
new DeleteStrategy()
|
||||||
);
|
);
|
||||||
|
|
||||||
var parents = ItemsToDelete.Select(i => i.GetParent()).OfType<FullName>().Distinct();
|
var parents = ItemsToDelete
|
||||||
|
.Select(i => i.GetParent())
|
||||||
|
.OfType<FullName>()
|
||||||
|
.Distinct();
|
||||||
foreach (var parent in parents)
|
foreach (var parent in parents)
|
||||||
{
|
{
|
||||||
await _commandSchedulerNotifier.RefreshContainer(parent);
|
await _commandSchedulerNotifier.RefreshContainer(parent);
|
||||||
@@ -68,18 +71,26 @@ public class DeleteCommand : CommandBase, IExecutableCommand
|
|||||||
foreach (var itemToDeleteName in itemsToDelete)
|
foreach (var itemToDeleteName in itemsToDelete)
|
||||||
{
|
{
|
||||||
var itemToDelete = await _timelessContentProvider.GetItemByFullNameAsync(itemToDeleteName, currentTime);
|
var itemToDelete = await _timelessContentProvider.GetItemByFullNameAsync(itemToDeleteName, currentTime);
|
||||||
IItemDeleter itemDeleter;
|
IItemDeleter? itemDeleter = null;
|
||||||
|
|
||||||
if (itemDeleters.ContainsKey(itemToDelete.Provider.Name))
|
if (itemDeleters.TryGetValue(itemToDelete.Provider.Name, out var deleter))
|
||||||
{
|
{
|
||||||
itemDeleter = itemDeleters[itemToDelete.Provider.Name];
|
itemDeleter = deleter;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
itemDeleter = _contentAccessorFactory.GetItemDeleter(itemToDelete.Provider);
|
try
|
||||||
itemDeleters.Add(itemToDelete.Provider.Name, itemDeleter);
|
{
|
||||||
|
itemDeleter = _contentAccessorFactory.GetItemDeleter(itemToDelete.Provider);
|
||||||
|
itemDeleters.Add(itemToDelete.Provider.Name, itemDeleter);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (itemDeleter is null) continue;
|
||||||
|
|
||||||
if (itemToDelete is IContainer container)
|
if (itemToDelete is IContainer container)
|
||||||
{
|
{
|
||||||
await TraverseTree(
|
await TraverseTree(
|
||||||
@@ -95,7 +106,7 @@ public class DeleteCommand : CommandBase, IExecutableCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await itemDeleter.DeleteAsync(itemToDelete.Provider, itemToDelete.FullName!);
|
await deleteStrategy.DeleteItem(itemToDelete, itemDeleter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,7 +6,5 @@ namespace FileTime.Core.Command.Delete;
|
|||||||
public class DeleteStrategy : IDeleteStrategy
|
public class DeleteStrategy : IDeleteStrategy
|
||||||
{
|
{
|
||||||
public async Task DeleteItem(IItem item, IItemDeleter deleter)
|
public async Task DeleteItem(IItem item, IItemDeleter deleter)
|
||||||
{
|
=> await deleter.DeleteAsync(item.Provider, item.FullName!);
|
||||||
await deleter.DeleteAsync(item.Provider, item.FullName!);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ public abstract class ContentProviderBase : IContentProvider
|
|||||||
|
|
||||||
public IContentProvider Provider => this;
|
public IContentProvider Provider => this;
|
||||||
|
|
||||||
public AbsolutePath? Parent => null;
|
public AbsolutePath? Parent { get; }
|
||||||
|
|
||||||
public DateTime? CreatedAt => null;
|
public DateTime? CreatedAt => null;
|
||||||
|
|
||||||
@@ -46,14 +46,15 @@ public abstract class ContentProviderBase : IContentProvider
|
|||||||
public bool AllowRecursiveDeletion => false;
|
public bool AllowRecursiveDeletion => false;
|
||||||
|
|
||||||
public AbsolutePathType Type => AbsolutePathType.Container;
|
public AbsolutePathType Type => AbsolutePathType.Container;
|
||||||
public PointInTime PointInTime { get; } = PointInTime.Eternal;
|
public PointInTime PointInTime => PointInTime.Eternal;
|
||||||
|
|
||||||
public ObservableCollection<Exception> Exceptions { get; } = new();
|
public ObservableCollection<Exception> Exceptions { get; } = new();
|
||||||
|
|
||||||
ReadOnlyExtensionCollection IItem.Extensions => _extensions;
|
ReadOnlyExtensionCollection IItem.Extensions => _extensions;
|
||||||
|
|
||||||
protected ContentProviderBase(string name)
|
protected ContentProviderBase(string name, ITimelessContentProvider timelessContentProvider)
|
||||||
{
|
{
|
||||||
|
Parent = new AbsolutePath(timelessContentProvider, PointInTime.Eternal, new FullName(""), AbsolutePathType.Container);
|
||||||
DisplayName = Name = name;
|
DisplayName = Name = name;
|
||||||
FullName = FullName.CreateSafe(name);
|
FullName = FullName.CreateSafe(name);
|
||||||
Extensions = new ExtensionCollection();
|
Extensions = new ExtensionCollection();
|
||||||
|
|||||||
@@ -1,21 +1,64 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace FileTime.Core.ContentAccess;
|
namespace FileTime.Core.ContentAccess;
|
||||||
|
|
||||||
public class ContentProviderRegistry : IContentProviderRegistry
|
public class ContentProviderRegistry : IContentProviderRegistry
|
||||||
{
|
{
|
||||||
|
private readonly object _lock = new();
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly Lazy<IList<IContentProvider>> _defaultContentProviders;
|
private readonly ObservableCollection<IContentProvider> _contentProviders = new();
|
||||||
private readonly List<IContentProvider> _additionalContentProviders = new();
|
private readonly ReadOnlyObservableCollection<IContentProvider> _contentProvidersReadOnly;
|
||||||
|
private bool _initialized;
|
||||||
|
|
||||||
public ContentProviderRegistry(IServiceProvider serviceProvider)
|
public ContentProviderRegistry(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_defaultContentProviders = new Lazy<IList<IContentProvider>>(() => serviceProvider.GetServices<IContentProvider>().ToList());
|
_contentProvidersReadOnly = new ReadOnlyObservableCollection<IContentProvider>(_contentProviders);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<IContentProvider> ContentProviders => _defaultContentProviders.Value.Concat(_additionalContentProviders);
|
public ReadOnlyObservableCollection<IContentProvider> ContentProviders
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
InitializeContentProviderListIfNeeded();
|
||||||
|
return _contentProvidersReadOnly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void AddContentProvider(IContentProvider contentProvider) => _additionalContentProviders.Add(contentProvider);
|
private void InitializeContentProviderListIfNeeded()
|
||||||
public void RemoveContentProvider(IContentProvider contentProvider) => _additionalContentProviders.Remove(contentProvider);
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (!_initialized)
|
||||||
|
{
|
||||||
|
foreach (var contentProvider in _serviceProvider.GetServices<IContentProvider>())
|
||||||
|
{
|
||||||
|
_contentProviders.Add(contentProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddContentProvider(IContentProvider contentProvider)
|
||||||
|
{
|
||||||
|
InitializeContentProviderListIfNeeded();
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_contentProviders.Add(contentProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveContentProvider(IContentProvider contentProvider)
|
||||||
|
{
|
||||||
|
InitializeContentProviderListIfNeeded();
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
_contentProviders.Remove(contentProvider);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
87
src/Core/FileTime.Core.ContentAccess/RootContentProvider.cs
Normal file
87
src/Core/FileTime.Core.ContentAccess/RootContentProvider.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using FileTime.Core.Enums;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
using ObservableComputations;
|
||||||
|
|
||||||
|
namespace FileTime.Core.ContentAccess;
|
||||||
|
|
||||||
|
public class RootContentProvider : IRootContentProvider
|
||||||
|
{
|
||||||
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
|
public string Name => "root";
|
||||||
|
public string DisplayName => "Root";
|
||||||
|
public FullName? FullName => null;
|
||||||
|
public NativePath? NativePath => null;
|
||||||
|
public AbsolutePath? Parent => null;
|
||||||
|
public bool IsHidden => false;
|
||||||
|
public bool IsExists => true;
|
||||||
|
public DateTime? CreatedAt => null;
|
||||||
|
public SupportsDelete CanDelete => SupportsDelete.False;
|
||||||
|
public bool CanRename => false;
|
||||||
|
public IContentProvider Provider => this;
|
||||||
|
public string? Attributes => null;
|
||||||
|
public AbsolutePathType Type => AbsolutePathType.Container;
|
||||||
|
public PointInTime PointInTime => PointInTime.Eternal;
|
||||||
|
public ObservableCollection<Exception> Exceptions { get; } = new();
|
||||||
|
public ReadOnlyExtensionCollection Extensions { get; } = new(new ExtensionCollection());
|
||||||
|
public ObservableCollection<AbsolutePath> Items { get; }
|
||||||
|
public IObservable<bool> IsLoading => Observable.Return(false);
|
||||||
|
public bool? IsLoaded => true;
|
||||||
|
public Task WaitForLoaded(CancellationToken token = default) => Task.CompletedTask;
|
||||||
|
|
||||||
|
public bool AllowRecursiveDeletion => false;
|
||||||
|
public Task OnEnter() => Task.CompletedTask;
|
||||||
|
|
||||||
|
public bool SupportsContentStreams => false;
|
||||||
|
|
||||||
|
public RootContentProvider(
|
||||||
|
IContentProviderRegistry contentProviderRegistry,
|
||||||
|
ITimelessContentProvider timelessContentProvider)
|
||||||
|
{
|
||||||
|
_timelessContentProvider = timelessContentProvider;
|
||||||
|
Items = contentProviderRegistry
|
||||||
|
.ContentProviders
|
||||||
|
.Selecting<IContentProvider, AbsolutePath>(c =>
|
||||||
|
new AbsolutePath(timelessContentProvider, c)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IItem> GetItemByFullNameAsync(
|
||||||
|
FullName fullName,
|
||||||
|
PointInTime pointInTime,
|
||||||
|
bool forceResolve = false,
|
||||||
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
|
ItemInitializationSettings itemInitializationSettings = default)
|
||||||
|
=> await _timelessContentProvider.GetItemByFullNameAsync(
|
||||||
|
fullName,
|
||||||
|
pointInTime,
|
||||||
|
forceResolve,
|
||||||
|
forceResolvePathType,
|
||||||
|
itemInitializationSettings);
|
||||||
|
|
||||||
|
public async Task<IItem> GetItemByNativePathAsync(
|
||||||
|
NativePath nativePath,
|
||||||
|
PointInTime pointInTime,
|
||||||
|
bool forceResolve = false,
|
||||||
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
|
ItemInitializationSettings itemInitializationSettings = default)
|
||||||
|
=> await _timelessContentProvider.GetItemByNativePathAsync(
|
||||||
|
nativePath,
|
||||||
|
pointInTime
|
||||||
|
) ?? throw new FileNotFoundException();
|
||||||
|
|
||||||
|
public NativePath GetNativePath(FullName fullName) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public FullName GetFullName(NativePath nativePath) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Task<byte[]?> GetContentAsync(
|
||||||
|
IElement element,
|
||||||
|
int? maxLength = null,
|
||||||
|
CancellationToken cancellationToken = default) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public bool CanHandlePath(NativePath path) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public bool CanHandlePath(FullName path) => throw new NotImplementedException();
|
||||||
|
}
|
||||||
@@ -140,7 +140,7 @@ public class Tab : ITab
|
|||||||
{
|
{
|
||||||
var itemNameToSelect = LastDeepestSelectedPath.Path
|
var itemNameToSelect = LastDeepestSelectedPath.Path
|
||||||
.Split(Constants.SeparatorChar)
|
.Split(Constants.SeparatorChar)
|
||||||
.Skip(parentPath.Split(Constants.SeparatorChar).Length)
|
.Skip(parentPath == "" ? 0 : parentPath.Split(Constants.SeparatorChar).Length)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
var itemToSelect = items.FirstOrDefault(i => i.FullName?.GetName() == itemNameToSelect);
|
var itemToSelect = items.FirstOrDefault(i => i.FullName?.GetName() == itemNameToSelect);
|
||||||
|
|||||||
@@ -2,18 +2,24 @@ using System.Reactive.Subjects;
|
|||||||
using FileTime.Core.ContentAccess;
|
using FileTime.Core.ContentAccess;
|
||||||
using FileTime.Core.Enums;
|
using FileTime.Core.Enums;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace FileTime.Core.Timeline;
|
namespace FileTime.Core.Timeline;
|
||||||
|
|
||||||
public class TimelessContentProvider : ITimelessContentProvider
|
public class TimelessContentProvider : ITimelessContentProvider
|
||||||
{
|
{
|
||||||
private readonly IContentProviderRegistry _contentProviderRegistry;
|
private readonly IContentProviderRegistry _contentProviderRegistry;
|
||||||
|
private readonly Lazy<IRootContentProvider> _rootContentProvider;
|
||||||
|
|
||||||
public BehaviorSubject<PointInTime> CurrentPointInTime { get; } = new(PointInTime.Present);
|
public BehaviorSubject<PointInTime> CurrentPointInTime { get; } = new(PointInTime.Present);
|
||||||
|
|
||||||
public TimelessContentProvider(IContentProviderRegistry contentProviderRegistry)
|
public TimelessContentProvider(
|
||||||
|
IContentProviderRegistry contentProviderRegistry,
|
||||||
|
IServiceProvider serviceProvider
|
||||||
|
)
|
||||||
{
|
{
|
||||||
_contentProviderRegistry = contentProviderRegistry;
|
_contentProviderRegistry = contentProviderRegistry;
|
||||||
|
_rootContentProvider = new Lazy<IRootContentProvider>(serviceProvider.GetRequiredService<IRootContentProvider>);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IItem> GetItemByFullNameAsync(FullName fullName, PointInTime? pointInTime,
|
public async Task<IItem> GetItemByFullNameAsync(FullName fullName, PointInTime? pointInTime,
|
||||||
@@ -23,6 +29,8 @@ public class TimelessContentProvider : ITimelessContentProvider
|
|||||||
{
|
{
|
||||||
//TODO time modifications
|
//TODO time modifications
|
||||||
var contentProviderName = fullName.Path.Split(Constants.SeparatorChar).FirstOrDefault();
|
var contentProviderName = fullName.Path.Split(Constants.SeparatorChar).FirstOrDefault();
|
||||||
|
if (contentProviderName == "") return _rootContentProvider.Value;
|
||||||
|
|
||||||
var contentProvider = _contentProviderRegistry.ContentProviders.FirstOrDefault(p => p.Name == contentProviderName);
|
var contentProvider = _contentProviderRegistry.ContentProviders.FirstOrDefault(p => p.Name == contentProviderName);
|
||||||
|
|
||||||
if (contentProvider is null)
|
if (contentProvider is null)
|
||||||
@@ -37,7 +45,7 @@ public class TimelessContentProvider : ITimelessContentProvider
|
|||||||
{
|
{
|
||||||
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
||||||
{
|
{
|
||||||
if(!contentProvider.CanHandlePath(nativePath)) continue;
|
if (!contentProvider.CanHandlePath(nativePath)) continue;
|
||||||
|
|
||||||
return await contentProvider.GetItemByNativePathAsync(nativePath, pointInTime ?? PointInTime.Present);
|
return await contentProvider.GetItemByNativePathAsync(nativePath, pointInTime ?? PointInTime.Present);
|
||||||
}
|
}
|
||||||
@@ -49,7 +57,7 @@ public class TimelessContentProvider : ITimelessContentProvider
|
|||||||
{
|
{
|
||||||
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
||||||
{
|
{
|
||||||
if(!contentProvider.CanHandlePath(nativePath)) continue;
|
if (!contentProvider.CanHandlePath(nativePath)) continue;
|
||||||
|
|
||||||
return contentProvider.GetFullName(nativePath);
|
return contentProvider.GetFullName(nativePath);
|
||||||
}
|
}
|
||||||
@@ -61,7 +69,7 @@ public class TimelessContentProvider : ITimelessContentProvider
|
|||||||
{
|
{
|
||||||
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
foreach (var contentProvider in _contentProviderRegistry.ContentProviders)
|
||||||
{
|
{
|
||||||
if(!contentProvider.CanHandlePath(fullName)) continue;
|
if (!contentProvider.CanHandlePath(fullName)) continue;
|
||||||
|
|
||||||
return contentProvider.GetNativePath(fullName);
|
return contentProvider.GetNativePath(fullName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
|||||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||||
private readonly bool _isCaseInsensitive;
|
private readonly bool _isCaseInsensitive;
|
||||||
|
|
||||||
public LocalContentProvider(ITimelessContentProvider timelessContentProvider) : base(LocalContentProviderConstants.ContentProviderId)
|
public LocalContentProvider(ITimelessContentProvider timelessContentProvider)
|
||||||
|
: base(LocalContentProviderConstants.ContentProviderId, timelessContentProvider)
|
||||||
{
|
{
|
||||||
_timelessContentProvider = timelessContentProvider;
|
_timelessContentProvider = timelessContentProvider;
|
||||||
_isCaseInsensitive = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
_isCaseInsensitive = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||||
@@ -66,13 +67,13 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
|||||||
PointInTime pointInTime,
|
PointInTime pointInTime,
|
||||||
bool forceResolve = false,
|
bool forceResolve = false,
|
||||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||||
ItemInitializationSettings itemInitializationSettings = default)
|
ItemInitializationSettings? itemInitializationSettings = null)
|
||||||
{
|
{
|
||||||
var path = nativePath.Path;
|
var path = nativePath.Path;
|
||||||
Exception? innerException;
|
Exception? innerException;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if ((path?.Length ?? 0) == 0)
|
if (path.Length == 0)
|
||||||
{
|
{
|
||||||
return Task.FromResult((IItem) this);
|
return Task.FromResult((IItem) this);
|
||||||
}
|
}
|
||||||
@@ -81,7 +82,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
|||||||
return Task.FromResult((IItem) DirectoryToContainer(
|
return Task.FromResult((IItem) DirectoryToContainer(
|
||||||
new DirectoryInfo(path!.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar),
|
new DirectoryInfo(path!.TrimEnd(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar),
|
||||||
pointInTime,
|
pointInTime,
|
||||||
!itemInitializationSettings.SkipChildInitialization)
|
itemInitializationSettings)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if (File.Exists(path))
|
else if (File.Exists(path))
|
||||||
@@ -193,18 +194,21 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Container DirectoryToContainer(DirectoryInfo directoryInfo, PointInTime pointInTime,
|
private Container DirectoryToContainer(DirectoryInfo directoryInfo, PointInTime pointInTime,
|
||||||
bool initializeChildren = true)
|
ItemInitializationSettings? initializationSettings = null)
|
||||||
{
|
{
|
||||||
|
initializationSettings ??= new();
|
||||||
|
|
||||||
var fullName = GetFullName(directoryInfo.FullName);
|
var fullName = GetFullName(directoryInfo.FullName);
|
||||||
var parentFullName = fullName.GetParent();
|
var parentFullName = fullName.GetParent();
|
||||||
var parent =
|
var parent =
|
||||||
parentFullName is null
|
initializationSettings.Parent
|
||||||
|
?? (parentFullName is null
|
||||||
? null
|
? null
|
||||||
: new AbsolutePath(
|
: new AbsolutePath(
|
||||||
_timelessContentProvider,
|
_timelessContentProvider,
|
||||||
pointInTime,
|
pointInTime,
|
||||||
parentFullName,
|
parentFullName,
|
||||||
AbsolutePathType.Container);
|
AbsolutePathType.Container));
|
||||||
var exceptions = new ObservableCollection<Exception>();
|
var exceptions = new ObservableCollection<Exception>();
|
||||||
|
|
||||||
var children = new ObservableCollection<AbsolutePath>();
|
var children = new ObservableCollection<AbsolutePath>();
|
||||||
@@ -229,7 +233,7 @@ public sealed partial class LocalContentProvider : ContentProviderBase, ILocalCo
|
|||||||
children
|
children
|
||||||
);
|
);
|
||||||
|
|
||||||
if (initializeChildren)
|
if (!initializationSettings.SkipChildInitialization)
|
||||||
{
|
{
|
||||||
Task.Run(async () => await LoadChildren(container, directoryInfo, children, pointInTime, exceptions));
|
Task.Run(async () => await LoadChildren(container, directoryInfo, children, pointInTime, exceptions));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace FileTime.Providers.LocalAdmin;
|
|||||||
//TODO: this should be a RemoteContentProvider if there will be one
|
//TODO: this should be a RemoteContentProvider if there will be one
|
||||||
public class AdminContentProvider : RemoteContentProvider, IAdminContentProvider
|
public class AdminContentProvider : RemoteContentProvider, IAdminContentProvider
|
||||||
{
|
{
|
||||||
public AdminContentProvider() : base("local", "localAdmin")
|
public AdminContentProvider(ITimelessContentProvider timelessContentProvider) : base(timelessContentProvider, "local", "localAdmin")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ namespace FileTime.Providers.Remote;
|
|||||||
|
|
||||||
public class RemoteContentProvider : ContentProviderBase, IRemoteContentProvider
|
public class RemoteContentProvider : ContentProviderBase, IRemoteContentProvider
|
||||||
{
|
{
|
||||||
public RemoteContentProvider(string remoteName, string name = "remote") : base(name)
|
public RemoteContentProvider(
|
||||||
|
ITimelessContentProvider timelessContentProvider,
|
||||||
|
string remoteName,
|
||||||
|
string name = "remote")
|
||||||
|
: base(name, timelessContentProvider)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user