Contaienr size scan WIP
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>FileTime.App.ContainerSizeScanner</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\FileTime.Core.Abstraction\FileTime.Core.Abstraction.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,9 @@
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
public interface IContainerScanSnapshotProvider : IContentProvider
|
||||
{
|
||||
ISizeScanTask StartSizeScan(IContainer scanSizeOf);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using DeclarativeProperty;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
public interface IContainerSizeScanContainer : ISizeItem, IContainer
|
||||
{
|
||||
public Task AddSizeSourceAsync(IDeclarativeProperty<long> sizeElement);
|
||||
ObservableCollection<IContainerSizeScanContainer> ChildContainers { get; }
|
||||
IContainer RealContainer { get; init; }
|
||||
IDeclarativeProperty<long> Size { get; }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
public interface ISizeItem : IItem
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using FileTime.App.Core.ViewModels.ItemPreview;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
public interface ISizePreviewItem : IItemPreviewViewModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using FileTime.Core.Models;
|
||||
using InitableService;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
public interface ISizeScanTask : IInitable<IContainer>
|
||||
{
|
||||
IContainerSizeScanContainer SizeContainer { get; }
|
||||
void Start();
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using FileTime.App.Core.Exceptions;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
using InitableService;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
public class ContainerScanSnapshotProvider : ContentProviderBase, IContainerScanSnapshotProvider
|
||||
{
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly List<ISizeScanTask> _sizeScanTasks = new();
|
||||
internal const string ContentProviderName = "container-size-scan";
|
||||
|
||||
public ContainerScanSnapshotProvider(
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
IServiceProvider serviceProvider)
|
||||
: base(ContentProviderName, timelessContentProvider)
|
||||
{
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public override async Task<IItem> GetItemByFullNameAsync(
|
||||
FullName fullName,
|
||||
PointInTime pointInTime,
|
||||
bool forceResolve = false,
|
||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||
ItemInitializationSettings itemInitializationSettings = null
|
||||
)
|
||||
{
|
||||
if (fullName.Path == ContentProviderName)
|
||||
return this;
|
||||
|
||||
var pathParts = fullName.Path.Split(Constants.SeparatorChar);
|
||||
|
||||
var item = _sizeScanTasks.FirstOrDefault(t => t.SizeContainer.Name == pathParts[1])?.SizeContainer;
|
||||
|
||||
if (pathParts.Length == 2)
|
||||
return item ?? throw new ItemNotFoundException(fullName);
|
||||
|
||||
for (var i = 2; i < pathParts.Length - 1 && item != null; i++)
|
||||
{
|
||||
var childName = pathParts[i];
|
||||
item = item.ChildContainers.FirstOrDefault(c => c.Name == childName);
|
||||
}
|
||||
|
||||
if (item is not null)
|
||||
{
|
||||
var container = item.ChildContainers.FirstOrDefault(c => c.Name == pathParts[^1]);
|
||||
if (container is not null) return container;
|
||||
|
||||
var childName = item.RealContainer.FullName?.GetChild(pathParts[^1]);
|
||||
if (childName is null) throw new ItemNotFoundException(fullName);
|
||||
|
||||
return await _timelessContentProvider.GetItemByFullNameAsync(
|
||||
childName,
|
||||
pointInTime,
|
||||
forceResolve,
|
||||
forceResolvePathType,
|
||||
itemInitializationSettings
|
||||
);
|
||||
}
|
||||
|
||||
throw new ItemNotFoundException(fullName);
|
||||
}
|
||||
|
||||
public override async Task<IItem> GetItemByNativePathAsync(
|
||||
NativePath nativePath,
|
||||
PointInTime pointInTime,
|
||||
bool forceResolve = false,
|
||||
AbsolutePathType forceResolvePathType = AbsolutePathType.Unknown,
|
||||
ItemInitializationSettings itemInitializationSettings = default
|
||||
) =>
|
||||
await GetItemByFullNameAsync(
|
||||
new FullName(nativePath.Path),
|
||||
pointInTime,
|
||||
forceResolve,
|
||||
forceResolvePathType,
|
||||
itemInitializationSettings
|
||||
);
|
||||
|
||||
public override NativePath GetNativePath(FullName fullName)
|
||||
=> new(fullName.Path);
|
||||
|
||||
public override FullName GetFullName(NativePath nativePath)
|
||||
=> new(nativePath.Path);
|
||||
|
||||
public override Task<byte[]?> GetContentAsync(
|
||||
IElement element,
|
||||
int? maxLength = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
//TODO read from original source
|
||||
=> Task.FromResult((byte[]?) null);
|
||||
|
||||
public override bool CanHandlePath(NativePath path)
|
||||
=> path.Path.StartsWith(ContentProviderName);
|
||||
|
||||
public ISizeScanTask StartSizeScan(IContainer scanSizeOf)
|
||||
{
|
||||
var searchTask = _serviceProvider
|
||||
.GetInitableResolver(scanSizeOf)
|
||||
.GetRequiredService<ISizeScanTask>();
|
||||
|
||||
_sizeScanTasks.Add(searchTask);
|
||||
searchTask.Start();
|
||||
Items.Add(new AbsolutePath(_timelessContentProvider, searchTask.SizeContainer));
|
||||
|
||||
return searchTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using FileTime.App.Core.ViewModels.ItemPreview;
|
||||
using ObservableComputations;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
public class ContainerSizeContainerPreview : ISizePreviewItem
|
||||
{
|
||||
public const string PreviewName = "SizePreviewContainer";
|
||||
public string Name => PreviewName;
|
||||
|
||||
public ObservableCollection<ISizePreviewItem> Items { get; }
|
||||
|
||||
public ContainerSizeContainerPreview(IContainerSizeScanContainer container)
|
||||
{
|
||||
Items = container
|
||||
.ChildContainers
|
||||
.Ordering(c => c.Size)
|
||||
.Taking(0, 10)
|
||||
.Selecting();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.App.Core.ViewModels.ItemPreview;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
public class ContainerSizePreviewProvider : IItemPreviewProvider
|
||||
{
|
||||
public bool CanHandle(IItem item) => item is ContainerSizeScanContainer;
|
||||
|
||||
public Task<IItemPreviewViewModel> CreatePreviewAsync(IItem item)
|
||||
{
|
||||
if(item is not ContainerSizeScanContainer container) throw new NotSupportedException();
|
||||
|
||||
return Task.FromResult((IItemPreviewViewModel)new ContainerSizeContainerPreview(container));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using DeclarativeProperty;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
//TODO: create readonly version
|
||||
public class ContainerSizeScanContainer : IContainerSizeScanContainer
|
||||
{
|
||||
private readonly ReadOnlyExtensionCollection _readOnlyExtensions;
|
||||
private readonly BehaviorSubject<bool> _isLoading = new(false);
|
||||
private readonly CombineProperty<long, long> _size;
|
||||
public required string Name { get; init; }
|
||||
public required string DisplayName { get; init; }
|
||||
public required FullName? FullName { get; init; }
|
||||
public required NativePath? NativePath { get; init; }
|
||||
public AbsolutePath? Parent { get; init; }
|
||||
public bool IsHidden => false;
|
||||
public bool IsExists => true;
|
||||
public DateTime? CreatedAt { get; }
|
||||
public SupportsDelete CanDelete => SupportsDelete.True;
|
||||
public bool CanRename => false;
|
||||
public IContentProvider Provider { get; }
|
||||
public string? Attributes => null;
|
||||
public AbsolutePathType Type => AbsolutePathType.Container;
|
||||
public PointInTime PointInTime => PointInTime.Present;
|
||||
public ObservableCollection<Exception> Exceptions { get; } = new();
|
||||
public ExtensionCollection Extensions { get; } = new();
|
||||
ReadOnlyExtensionCollection IItem.Extensions => _readOnlyExtensions;
|
||||
public IItem WithParent(AbsolutePath parent) => throw new NotImplementedException();
|
||||
|
||||
public ObservableCollection<AbsolutePath> Items { get; } = new();
|
||||
public IObservable<bool> IsLoading { get; }
|
||||
public bool? IsLoaded { get; private set; }
|
||||
public Task WaitForLoaded(CancellationToken token = default) => throw new NotImplementedException();
|
||||
|
||||
public bool AllowRecursiveDeletion => false;
|
||||
|
||||
public IDeclarativeProperty<long> Size => _size;
|
||||
public ObservableCollection<IContainerSizeScanContainer> ChildContainers { get; } = new();
|
||||
public required IContainer RealContainer { get; init; }
|
||||
|
||||
public ContainerSizeScanContainer(IContainerScanSnapshotProvider provider)
|
||||
{
|
||||
_readOnlyExtensions = new ReadOnlyExtensionCollection(Extensions);
|
||||
IsLoading = _isLoading.AsObservable();
|
||||
|
||||
_size = new(childContainerSizes => Task.FromResult(childContainerSizes.Sum()));
|
||||
CreatedAt = DateTime.Now;
|
||||
Provider = provider;
|
||||
}
|
||||
|
||||
public async Task AddSizeSourceAsync(IDeclarativeProperty<long> sizeElement)
|
||||
=> await _size.AddSourceAsync(sizeElement);
|
||||
|
||||
public Task StartLoadingAsync()
|
||||
{
|
||||
_isLoading.OnNext(true);
|
||||
IsLoaded = false;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopLoadingAsync()
|
||||
{
|
||||
_isLoading.OnNext(false);
|
||||
IsLoaded = true;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
public record ContainerSizeScanElement(
|
||||
string Name,
|
||||
string DisplayName,
|
||||
FullName FullName,
|
||||
NativePath NativePath,
|
||||
AbsolutePath? Parent,
|
||||
bool IsHidden,
|
||||
bool IsExists,
|
||||
DateTime? CreatedAt,
|
||||
SupportsDelete CanDelete,
|
||||
bool CanRename,
|
||||
string? Attributes,
|
||||
IContentProvider Provider,
|
||||
PointInTime PointInTime,
|
||||
ObservableCollection<Exception> Exceptions,
|
||||
ReadOnlyExtensionCollection Extensions) : IElement
|
||||
{
|
||||
public AbsolutePathType Type => AbsolutePathType.Element;
|
||||
|
||||
public IItem WithParent(AbsolutePath parent) => this with { Parent = parent };
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\FileTime.Core.ContentAccess\FileTime.Core.ContentAccess.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.ContainerSizeScanner.Abstractions\FileTime.App.ContainerSizeScanner.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
117
src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanTask.cs
Normal file
117
src/AppCommon/FileTime.App.ContainerSizeScanner/SizeScanTask.cs
Normal file
@@ -0,0 +1,117 @@
|
||||
using DeclarativeProperty;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Models.Extensions;
|
||||
using FileTime.Core.Timeline;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
public class SizeScanTask : ISizeScanTask
|
||||
{
|
||||
private IContainer _scanSizeOf = null!;
|
||||
private readonly IContainerScanSnapshotProvider _containerScanSnapshotProvider;
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly ILogger<SizeScanTask> _logger;
|
||||
private Thread? _sizeScanThread;
|
||||
private static int _searchId = 1;
|
||||
public IContainerSizeScanContainer SizeContainer { get; private set; } = null!;
|
||||
|
||||
public SizeScanTask(
|
||||
IContainerScanSnapshotProvider containerScanSnapshotProvider,
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
ILogger<SizeScanTask> logger)
|
||||
{
|
||||
_containerScanSnapshotProvider = containerScanSnapshotProvider;
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Init(IContainer scanSizeOf)
|
||||
{
|
||||
_scanSizeOf = scanSizeOf;
|
||||
var name = $"{_searchId++}_{scanSizeOf.Name}";
|
||||
var randomId = ContainerScanSnapshotProvider.ContentProviderName + Constants.SeparatorChar + name;
|
||||
SizeContainer = new ContainerSizeScanContainer(_containerScanSnapshotProvider)
|
||||
{
|
||||
Name = name,
|
||||
DisplayName = scanSizeOf.DisplayName,
|
||||
FullName = new FullName(randomId),
|
||||
NativePath = new NativePath(randomId),
|
||||
Parent = new AbsolutePath(_timelessContentProvider, _containerScanSnapshotProvider),
|
||||
RealContainer = scanSizeOf
|
||||
};
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (_sizeScanThread != null) return;
|
||||
|
||||
var sizeScanThread = new Thread(Run);
|
||||
sizeScanThread.Start();
|
||||
_sizeScanThread = sizeScanThread;
|
||||
}
|
||||
|
||||
private async void Run()
|
||||
{
|
||||
try
|
||||
{
|
||||
await TraverseTree(_scanSizeOf, SizeContainer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error while scanning container {ContainerName}", _scanSizeOf.Name);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: make static
|
||||
private async Task TraverseTree(
|
||||
IContainer realContainer,
|
||||
IContainerSizeScanContainer container)
|
||||
{
|
||||
var resolvedItems = new List<IItem>(realContainer.Items.Count);
|
||||
foreach (var item in realContainer.Items)
|
||||
{
|
||||
var resolvedItem = await item.ResolveAsync();
|
||||
resolvedItems.Add(resolvedItem);
|
||||
}
|
||||
|
||||
foreach (var element in resolvedItems.OfType<IElement>())
|
||||
{
|
||||
var fileExtension = element.GetExtension<FileExtension>();
|
||||
if (fileExtension?.Size is not { } size) continue;
|
||||
|
||||
var childName = container.FullName!.GetChild(element.Name).Path;
|
||||
await container.AddSizeSourceAsync(new DeclarativeProperty<long>(size));
|
||||
container.Items.Add(new AbsolutePath(
|
||||
_timelessContentProvider,
|
||||
PointInTime.Present,
|
||||
new FullName(childName),
|
||||
AbsolutePathType.Element));
|
||||
}
|
||||
|
||||
foreach (var childContainer in resolvedItems.OfType<IContainer>())
|
||||
{
|
||||
var childName = container.FullName!.GetChild(childContainer.Name).Path;
|
||||
var childSearchContainer = new ContainerSizeScanContainer(_containerScanSnapshotProvider)
|
||||
{
|
||||
Name = childContainer.Name,
|
||||
DisplayName = childContainer.DisplayName,
|
||||
FullName = new FullName(childName),
|
||||
NativePath = new NativePath(childName),
|
||||
Parent = new AbsolutePath(_timelessContentProvider, container),
|
||||
RealContainer = childContainer
|
||||
};
|
||||
|
||||
container.ChildContainers.Add(childSearchContainer);
|
||||
await container.AddSizeSourceAsync(childSearchContainer.Size);
|
||||
container.Items.Add(new AbsolutePath(
|
||||
_timelessContentProvider,
|
||||
PointInTime.Present,
|
||||
new FullName(childName),
|
||||
AbsolutePathType.Container));
|
||||
|
||||
await TraverseTree(childContainer, childSearchContainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
src/AppCommon/FileTime.App.ContainerSizeScanner/Startup.cs
Normal file
18
src/AppCommon/FileTime.App.ContainerSizeScanner/Startup.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace FileTime.App.ContainerSizeScanner;
|
||||
|
||||
public static class Startup
|
||||
{
|
||||
public static IServiceCollection AddContainerSizeScanner(this IServiceCollection services)
|
||||
{
|
||||
services.TryAddSingleton<IContainerScanSnapshotProvider, ContainerScanSnapshotProvider>();
|
||||
services.AddSingleton<IContentProvider>(sp => sp.GetRequiredService<IContainerScanSnapshotProvider>());
|
||||
services.AddTransient<ISizeScanTask, SizeScanTask>();
|
||||
services.AddTransient<IItemPreviewProvider, ContainerSizePreviewProvider>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using FileTime.App.Core.ViewModels.ItemPreview;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.Services;
|
||||
|
||||
public interface IItemPreviewProvider
|
||||
{
|
||||
bool CanHandle(IItem item);
|
||||
Task<IItemPreviewViewModel> CreatePreviewAsync(IItem item);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace FileTime.App.Core.UserCommand;
|
||||
|
||||
public sealed class ScanSizeCommand : IIdentifiableUserCommand
|
||||
{
|
||||
public const string ScanSizeCommandName = "scan_size";
|
||||
public static readonly ScanSizeCommand Instance = new();
|
||||
|
||||
private ScanSizeCommand()
|
||||
{
|
||||
}
|
||||
|
||||
public string UserCommandID => ScanSizeCommandName;
|
||||
public string Title => "Scan size";
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using FileTime.App.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels.ItemPreview;
|
||||
|
||||
public interface IElementPreviewViewModel : IItemPreviewViewModel
|
||||
{
|
||||
ItemPreviewMode Mode { get; }
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using FileTime.App.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.ViewModels.ItemPreview;
|
||||
|
||||
public interface IItemPreviewViewModel
|
||||
{
|
||||
ItemPreviewMode Mode { get; }
|
||||
string Name { get; }
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
<ProjectReference Include="..\..\Tools\FileTime.Tools\FileTime.Tools.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.CommandPalette.Abstractions\FileTime.App.CommandPalette.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.CommandPalette\FileTime.App.CommandPalette.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.ContainerSizeScanner.Abstractions\FileTime.App.ContainerSizeScanner.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||
<ProjectReference Include="..\..\Core\FileTime.Core.Command\FileTime.Core.Command.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.FrequencyNavigation.Abstractions\FileTime.App.FrequencyNavigation.Abstractions.csproj" />
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using FileTime.App.Core.ViewModels.ItemPreview;
|
||||
using FileTime.Core.Models;
|
||||
using InitableService;
|
||||
|
||||
namespace FileTime.App.Core.Services;
|
||||
|
||||
public class ElementPreviewProvider : IItemPreviewProvider
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ElementPreviewProvider(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public bool CanHandle(IItem item) => item is IElement;
|
||||
|
||||
public async Task<IItemPreviewViewModel> CreatePreviewAsync(IItem item)
|
||||
{
|
||||
if (item is not IElement element) throw new NotSupportedException();
|
||||
|
||||
return await _serviceProvider
|
||||
.GetAsyncInitableResolver(element)
|
||||
.GetRequiredServiceAsync<ElementPreviewViewModel>();
|
||||
}
|
||||
}
|
||||
@@ -9,14 +9,21 @@ namespace FileTime.App.Core.Services;
|
||||
public class ItemPreviewService : IItemPreviewService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IEnumerable<IItemPreviewProvider> _itemPreviewProviders;
|
||||
public IObservable<IItemPreviewViewModel?> ItemPreview { get; }
|
||||
|
||||
public ItemPreviewService(IAppState appState, IServiceProvider serviceProvider)
|
||||
public ItemPreviewService(
|
||||
IAppState appState,
|
||||
IServiceProvider serviceProvider,
|
||||
IEnumerable<IItemPreviewProvider> itemPreviewProviders)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_itemPreviewProviders = itemPreviewProviders;
|
||||
ItemPreview = appState
|
||||
.SelectedTab
|
||||
.Select(t => t?.CurrentSelectedItem.Throttle(TimeSpan.FromMilliseconds(250)) ?? Observable.Return<IItemViewModel?>(null))
|
||||
.Select(t =>
|
||||
t?.CurrentSelectedItem.Throttle(TimeSpan.FromMilliseconds(250))
|
||||
?? Observable.Return<IItemViewModel?>(null))
|
||||
.Switch()
|
||||
.Select(item =>
|
||||
item == null
|
||||
@@ -30,11 +37,12 @@ public class ItemPreviewService : IItemPreviewService
|
||||
|
||||
private async Task<IItemPreviewViewModel?> Map(IItemViewModel itemViewModel)
|
||||
{
|
||||
return itemViewModel.BaseItem switch
|
||||
{
|
||||
IElement element => await _serviceProvider.GetAsyncInitableResolver(element)
|
||||
.GetRequiredServiceAsync<ElementPreviewViewModel>(),
|
||||
_ => null
|
||||
};
|
||||
ArgumentNullException.ThrowIfNull(itemViewModel.BaseItem);
|
||||
|
||||
var itemPreviewProvider = _itemPreviewProviders.FirstOrDefault(p => p.CanHandle(itemViewModel.BaseItem));
|
||||
|
||||
return itemPreviewProvider is null
|
||||
? null
|
||||
: await itemPreviewProvider.CreatePreviewAsync(itemViewModel.BaseItem);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,8 @@ public class TabPersistenceService : ITabPersistenceService
|
||||
//TODO: make this a configuration maybe?
|
||||
private readonly List<string> _contentProvidersNotToRestore = new()
|
||||
{
|
||||
"search"
|
||||
"search",
|
||||
"container-size-scan"
|
||||
};
|
||||
|
||||
private record PersistenceRoot(TabStates? TabStates);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System.Diagnostics;
|
||||
using DeclarativeProperty;
|
||||
using FileTime.App.ContainerSizeScanner;
|
||||
using FileTime.App.Core.UserCommand;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.App.Search;
|
||||
using FileTime.Core.Command;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Interactions;
|
||||
@@ -20,6 +22,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly IUserCommandHandlerService _userCommandHandlerService;
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
private readonly IContainerScanSnapshotProvider _containerScanSnapshotProvider;
|
||||
private IDeclarativeProperty<IContainer?>? _currentLocation;
|
||||
private IDeclarativeProperty<IItemViewModel?>? _currentSelectedItem;
|
||||
private ITabViewModel? _currentSelectedTab;
|
||||
@@ -32,7 +35,8 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
IItemNameConverterService itemNameConverterService,
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
IUserCommandHandlerService userCommandHandlerService,
|
||||
IContentAccessorFactory contentAccessorFactory) : base(appState)
|
||||
IContentAccessorFactory contentAccessorFactory,
|
||||
IContainerScanSnapshotProvider containerScanSnapshotProvider) : base(appState)
|
||||
{
|
||||
_systemClipboardService = systemClipboardService;
|
||||
_userCommunicationService = userCommunicationService;
|
||||
@@ -41,6 +45,7 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
_userCommandHandlerService = userCommandHandlerService;
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
_containerScanSnapshotProvider = containerScanSnapshotProvider;
|
||||
SaveCurrentLocation(l => _currentLocation = l);
|
||||
SaveCurrentSelectedItem(i => _currentSelectedItem = i);
|
||||
SaveSelectedTab(t => _currentSelectedTab = t);
|
||||
@@ -51,10 +56,20 @@ public class ToolUserCommandHandlerService : UserCommandHandlerServiceBase
|
||||
new TypeUserCommandHandler<CopyNativePathCommand>(CopyNativePath),
|
||||
new TypeUserCommandHandler<CopyBase64Command>(CopyBase64),
|
||||
new TypeUserCommandHandler<SearchCommand>(Search),
|
||||
new TypeUserCommandHandler<ScanSizeCommand>(ScanSize),
|
||||
new TypeUserCommandHandler<SortItemsCommand>(SortItems),
|
||||
});
|
||||
}
|
||||
|
||||
private async Task ScanSize()
|
||||
{
|
||||
if (_currentLocation?.Value is null) return;
|
||||
|
||||
var searchTask = _containerScanSnapshotProvider.StartSizeScan(_currentLocation.Value);
|
||||
var openContainerCommand = new OpenContainerCommand(new AbsolutePath(_timelessContentProvider, searchTask.SizeContainer));
|
||||
await _userCommandHandlerService.HandleCommandAsync(openContainerCommand);
|
||||
}
|
||||
|
||||
private async Task SortItems(SortItemsCommand sortItemsCommand)
|
||||
{
|
||||
if (_currentSelectedTab is null) return;
|
||||
|
||||
@@ -27,6 +27,7 @@ public static class Startup
|
||||
serviceCollection.TryAddSingleton<IItemPreviewService, ItemPreviewService>();
|
||||
serviceCollection.TryAddSingleton<ITimelineViewModel, TimelineViewModel>();
|
||||
serviceCollection.TryAddSingleton<IRefreshSmoothnessCalculator, RefreshSmoothnessCalculator>();
|
||||
serviceCollection.TryAddSingleton<IItemPreviewProvider, ElementPreviewProvider>();
|
||||
|
||||
return serviceCollection
|
||||
.AddCommandHandlers()
|
||||
|
||||
@@ -48,6 +48,7 @@ public class DefaultIdentifiableCommandHandlerRegister : IStartupHandler
|
||||
AddUserCommand(RefreshCommand.Instance);
|
||||
AddUserCommand(RenameCommand.Instance);
|
||||
AddUserCommand(RunOrOpenCommand.Instance);
|
||||
AddUserCommand(ScanSizeCommand.Instance);
|
||||
AddUserCommand(StartCommandSchedulerCommand.Instance);
|
||||
AddUserCommand(SortItemsCommand.OrderByNameCommand);
|
||||
AddUserCommand(SortItemsCommand.OrderByNameDescCommand);
|
||||
|
||||
@@ -7,13 +7,14 @@ using MvvmGen;
|
||||
namespace FileTime.App.Core.ViewModels.ItemPreview;
|
||||
|
||||
[ViewModel]
|
||||
public partial class ElementPreviewViewModel : IItemPreviewViewModel, IAsyncInitable<IElement>
|
||||
public partial class ElementPreviewViewModel : IElementPreviewViewModel, IAsyncInitable<IElement>
|
||||
{
|
||||
public const string PreviewName = "ElementPreview";
|
||||
private record EncodingResult(char BinaryChar, string PartialResult);
|
||||
|
||||
private const int MaxTextPreviewSize = 1024 * 1024;
|
||||
|
||||
private static readonly List<Encoding> _encodings = new()
|
||||
private static readonly List<Encoding> Encodings = new()
|
||||
{
|
||||
Encoding.UTF8,
|
||||
Encoding.Unicode,
|
||||
@@ -27,6 +28,8 @@ public partial class ElementPreviewViewModel : IItemPreviewViewModel, IAsyncInit
|
||||
[Property] private string? _textContent;
|
||||
[Property] private string? _textEncoding;
|
||||
|
||||
public string Name => PreviewName;
|
||||
|
||||
public async Task InitAsync(IElement element)
|
||||
{
|
||||
try
|
||||
@@ -59,7 +62,7 @@ public partial class ElementPreviewViewModel : IItemPreviewViewModel, IAsyncInit
|
||||
(string, Encoding?) GetNormalizedText(byte[] data)
|
||||
{
|
||||
var binaryCharacter = new Dictionary<string, EncodingResult>();
|
||||
foreach (var encoding in _encodings)
|
||||
foreach (var encoding in Encodings)
|
||||
{
|
||||
var text = encoding.GetString(data);
|
||||
var binary = false;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using DynamicData;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using DynamicData;
|
||||
using FileTime.Core.ContentAccess;
|
||||
using FileTime.Core.Enums;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
@@ -111,6 +111,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Tools.Compression"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.Tools.Compression.Core", "Tools\FileTime.Tools.Compression.Core\FileTime.Tools.Compression.Core.csproj", "{EE1721A0-D15A-4E40-BEA5-8AB6BAB8FD44}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.App.ContainerSizeScanner", "AppCommon\FileTime.App.ContainerSizeScanner\FileTime.App.ContainerSizeScanner.csproj", "{E5FD38ED-6E4B-42AA-850B-470B939B836B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileTime.App.ContainerSizeScanner.Abstractions", "AppCommon\FileTime.App.ContainerSizeScanner.Abstractions\FileTime.App.ContainerSizeScanner.Abstractions.csproj", "{826AFD32-E36B-48BA-BC1E-1476B393CF24}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -297,6 +301,14 @@ Global
|
||||
{EE1721A0-D15A-4E40-BEA5-8AB6BAB8FD44}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EE1721A0-D15A-4E40-BEA5-8AB6BAB8FD44}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EE1721A0-D15A-4E40-BEA5-8AB6BAB8FD44}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E5FD38ED-6E4B-42AA-850B-470B939B836B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E5FD38ED-6E4B-42AA-850B-470B939B836B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E5FD38ED-6E4B-42AA-850B-470B939B836B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E5FD38ED-6E4B-42AA-850B-470B939B836B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{826AFD32-E36B-48BA-BC1E-1476B393CF24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{826AFD32-E36B-48BA-BC1E-1476B393CF24}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{826AFD32-E36B-48BA-BC1E-1476B393CF24}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{826AFD32-E36B-48BA-BC1E-1476B393CF24}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -348,6 +360,8 @@ Global
|
||||
{9062F7D2-34DE-44B7-A2D6-8B3AFDEBB606} = {778AAF38-20FF-438C-A9C3-60850C8B5A27}
|
||||
{58243F14-15A6-4601-A071-F99BE896D027} = {8C3CFEFE-78A5-4940-B388-D15FCE02ECE9}
|
||||
{EE1721A0-D15A-4E40-BEA5-8AB6BAB8FD44} = {8C3CFEFE-78A5-4940-B388-D15FCE02ECE9}
|
||||
{E5FD38ED-6E4B-42AA-850B-470B939B836B} = {A5291117-3001-498B-AC8B-E14F71F72570}
|
||||
{826AFD32-E36B-48BA-BC1E-1476B393CF24} = {A5291117-3001-498B-AC8B-E14F71F72570}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {859FB3DF-C60A-46B1-82E5-90274905D1EF}
|
||||
|
||||
@@ -2,6 +2,7 @@ using Avalonia;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using FileTime.App.CommandPalette;
|
||||
using FileTime.App.ContainerSizeScanner;
|
||||
using FileTime.App.DependencyInjection;
|
||||
using FileTime.App.FrequencyNavigation;
|
||||
using FileTime.App.Search;
|
||||
@@ -25,6 +26,7 @@ public class App : Application
|
||||
.AddServerCoreServices()
|
||||
.AddFrequencyNavigation()
|
||||
.AddCommandPalette()
|
||||
.AddContainerSizeScanner()
|
||||
.AddSearch()
|
||||
.AddCompression()
|
||||
.AddConfiguration(configuration)
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.CommandPalette\FileTime.App.CommandPalette.csproj" />
|
||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.ContainerSizeScanner\FileTime.App.ContainerSizeScanner.csproj" />
|
||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Core\FileTime.App.Core.csproj" />
|
||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
|
||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.FrequencyNavigation\FileTime.App.FrequencyNavigation.csproj" />
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.CommandPalette.Abstractions\FileTime.App.CommandPalette.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.ContainerSizeScanner\FileTime.App.ContainerSizeScanner.csproj" />
|
||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.FrequencyNavigation.Abstractions\FileTime.App.FrequencyNavigation.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\..\Providers\FileTime.Providers.Local.Abstractions\FileTime.Providers.Local.Abstractions.csproj" />
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<ResourceInclude Source="avares://FileTime.GuiApp/Resources/Brushes.axaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary>
|
||||
<converters:ItemViewModeToBrushConverter
|
||||
AlternativeBrush="{StaticResource AlternativeItemForegroundBrush}"
|
||||
DefaultBrush="{StaticResource ForegroundBrush}"
|
||||
@@ -27,14 +27,17 @@
|
||||
x:Key="ItemViewModeToBackgroundConverter" />
|
||||
<converters:NamePartShrinkerConverter x:Key="NamePartShrinkerConverter" />
|
||||
<converters:ItemViewModelIsAttributeTypeConverter x:Key="ItemViewModelIsAttributeTypeConverter" />
|
||||
<converters:ItemViewModelIsAttributeTypeConverter Invert="true" x:Key="ItemViewModelIsNotAttributeTypeConverter" />
|
||||
<converters:ItemViewModelIsAttributeTypeConverter Invert="true"
|
||||
x:Key="ItemViewModelIsNotAttributeTypeConverter" />
|
||||
<converters:GetFileExtensionConverter x:Key="GetFileExtensionConverter" />
|
||||
<converters:FormatSizeConverter x:Key="FormatSizeConverter" />
|
||||
<converters:DateTimeConverter x:Key="DateTimeConverter" />
|
||||
<converters:SplitStringConverter x:Key="SplitStringConverter" />
|
||||
<converters:CompareConverter x:Key="EqualsConverter" />
|
||||
<converters:CompareConverter ComparisonCondition="{x:Static converters:ComparisonCondition.NotEqual}" x:Key="NotEqualsConverter" />
|
||||
<converters:CompareConverter ComparisonCondition="{x:Static converters:ComparisonCondition.GreaterThan}" x:Key="GreaterThanConverter" />
|
||||
<converters:CompareConverter ComparisonCondition="{x:Static converters:ComparisonCondition.NotEqual}"
|
||||
x:Key="NotEqualsConverter" />
|
||||
<converters:CompareConverter ComparisonCondition="{x:Static converters:ComparisonCondition.GreaterThan}"
|
||||
x:Key="GreaterThanConverter" />
|
||||
<converters:ExceptionToStringConverter x:Key="ExceptionToStringConverter" />
|
||||
<converters:CommandToCommandNameConverter x:Key="CommandToCommandNameConverter" />
|
||||
<converters:ItemToImageConverter x:Key="ItemToImageConverter" />
|
||||
@@ -44,4 +47,6 @@
|
||||
x:Key="PathPreformatter" />
|
||||
<converters:ContextMenuGenerator x:Key="ContextMenuGenerator" />
|
||||
<converters:TextDecorationConverter x:Key="TextDecorationConverter" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
@@ -27,8 +27,10 @@
|
||||
xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
|
||||
xmlns:ia="clr-namespace:Avalonia.Xaml.Interactions.Core;assembly=Avalonia.Xaml.Interactions"
|
||||
xmlns:interactions="using:FileTime.Core.Interactions"
|
||||
xmlns:itemPreview="clr-namespace:FileTime.App.Core.ViewModels.ItemPreview;assembly=FileTime.App.Core"
|
||||
xmlns:local="using:FileTime.GuiApp.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:sizePreview="clr-namespace:FileTime.App.ContainerSizeScanner;assembly=FileTime.App.ContainerSizeScanner"
|
||||
xmlns:vm="using:FileTime.GuiApp.ViewModels"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Window.Resources>
|
||||
@@ -45,8 +47,7 @@
|
||||
</Window.Styles>
|
||||
|
||||
<Grid Background="{DynamicResource AppBackgroundBrush}">
|
||||
<Grid IsVisible="{Binding Loading, Converter={x:Static BoolConverters.Not}, FallbackValue=False}"
|
||||
x:DataType="vm:IMainWindowViewModel">
|
||||
<Grid IsVisible="{Binding Loading, Converter={x:Static BoolConverters.Not}, FallbackValue=False}" x:DataType="vm:IMainWindowViewModel">
|
||||
|
||||
<Grid ColumnDefinitions="250,*" RowDefinitions="Auto,*">
|
||||
|
||||
@@ -60,10 +61,8 @@
|
||||
|
||||
<Grid ColumnDefinitions="*, Auto">
|
||||
<StackPanel Margin="20,10" Orientation="Horizontal">
|
||||
<local:PathPresenter
|
||||
DataContext="{Binding AppState.SelectedTab^.CurrentLocation^.FullName.Path, Converter={StaticResource PathPreformatter}}" />
|
||||
<TextBlock Foreground="{StaticResource AccentBrush}"
|
||||
Text="{Binding AppState.SelectedTab^.CurrentSelectedItem.Value.DisplayNameText}" />
|
||||
<local:PathPresenter DataContext="{Binding AppState.SelectedTab^.CurrentLocation^.FullName.Path, Converter={StaticResource PathPreformatter}}" />
|
||||
<TextBlock Foreground="{StaticResource AccentBrush}" Text="{Binding AppState.SelectedTab^.CurrentSelectedItem.Value.DisplayNameText}" />
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
@@ -363,8 +362,7 @@
|
||||
Grid.Column="0"
|
||||
Grid.Row="1"
|
||||
Margin="0,5,5,5">
|
||||
<TextBlock Text="{Binding DisplayDetailLabel^}"
|
||||
TextAlignment="Right" />
|
||||
<TextBlock Text="{Binding DisplayDetailLabel^}" TextAlignment="Right" />
|
||||
|
||||
<ProgressBar
|
||||
Margin="0,5,0,0"
|
||||
@@ -376,9 +374,7 @@
|
||||
Grid.Column="1"
|
||||
Grid.Row="1"
|
||||
Margin="5,5,0,5">
|
||||
<TextBlock
|
||||
Text="{Binding TotalProgress^, StringFormat={}{0}%}"
|
||||
TextAlignment="Right" />
|
||||
<TextBlock Text="{Binding TotalProgress^, StringFormat={}{0}%}" TextAlignment="Right" />
|
||||
|
||||
<ProgressBar
|
||||
Margin="0,5,0,0"
|
||||
@@ -417,8 +413,7 @@
|
||||
<Grid RowDefinitions="Auto,1">
|
||||
<StackPanel Margin="20,0,20,0" Orientation="Horizontal">
|
||||
|
||||
<TextBlock Text="{Binding TabNumber, StringFormat=({0})}"
|
||||
VerticalAlignment="Center" />
|
||||
<TextBlock Text="{Binding TabNumber, StringFormat=({0})}" VerticalAlignment="Center" />
|
||||
|
||||
<TextBlock
|
||||
Margin="5,0,0,0"
|
||||
@@ -464,8 +459,7 @@
|
||||
Width="1" />
|
||||
|
||||
<Grid Grid.Column="2" RowDefinitions="Auto,*">
|
||||
<Grid
|
||||
IsVisible="{Binding AppState.SelectedTab^.CurrentLocation.Value.IsLoading^, FallbackValue=False}">
|
||||
<Grid IsVisible="{Binding AppState.SelectedTab^.CurrentLocation.Value.IsLoading^, FallbackValue=False}">
|
||||
<Image
|
||||
Classes="LoadingAnimation"
|
||||
Height="40"
|
||||
@@ -484,8 +478,7 @@
|
||||
x:Name="CurrentItems">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="corevm:IItemViewModel">
|
||||
<local:ItemView HorizontalAlignment="Stretch"
|
||||
HorizontalContentAlignment="Stretch" />
|
||||
<local:ItemView HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
@@ -511,14 +504,11 @@
|
||||
Width="1" />
|
||||
|
||||
<Grid Grid.Column="4">
|
||||
<Grid
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^, Converter={x:Static ObjectConverters.IsNull}}">
|
||||
<Grid
|
||||
IsVisible="{Binding AppState.SelectedTab^.SelectedsChildren.Value, Converter={x:Static ObjectConverters.IsNotNull}, FallbackValue=False}">
|
||||
<Grid IsVisible="{Binding ItemPreviewService.ItemPreview^, Converter={x:Static ObjectConverters.IsNull}}">
|
||||
<Grid IsVisible="{Binding AppState.SelectedTab^.SelectedsChildren.Value, Converter={x:Static ObjectConverters.IsNotNull}, FallbackValue=False}">
|
||||
<Grid RowDefinitions="Auto, Auto, *">
|
||||
|
||||
<Grid
|
||||
IsVisible="{Binding AppState.SelectedTab^.CurrentSelectedItemAsContainer.Value.Container.IsLoading^, FallbackValue=False}">
|
||||
<Grid IsVisible="{Binding AppState.SelectedTab^.CurrentSelectedItemAsContainer.Value.Container.IsLoading^, FallbackValue=False}">
|
||||
<Image
|
||||
Classes="LoadingAnimation"
|
||||
Height="40"
|
||||
@@ -527,8 +517,7 @@
|
||||
</Grid>
|
||||
|
||||
|
||||
<ItemsRepeater Grid.Row="1"
|
||||
ItemsSource="{Binding AppState.SelectedTab^.CurrentLocation.Value.Exceptions}">
|
||||
<ItemsRepeater Grid.Row="1" ItemsSource="{Binding AppState.SelectedTab^.CurrentLocation.Value.Exceptions}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock
|
||||
@@ -565,9 +554,7 @@
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
IsVisible="{Binding AppState.SelectedTab^.SelectedsChildren.Value, Converter={x:Static ObjectConverters.IsNull}, ConverterParameter=0, FallbackValue=False}"
|
||||
RowDefinitions="Auto, Auto">
|
||||
<Grid IsVisible="{Binding AppState.SelectedTab^.SelectedsChildren.Value, Converter={x:Static ObjectConverters.IsNull}, ConverterParameter=0, FallbackValue=False}" RowDefinitions="Auto, Auto">
|
||||
<TextBlock
|
||||
Foreground="{DynamicResource ErrorBrush}"
|
||||
HorizontalAlignment="Center"
|
||||
@@ -575,8 +562,7 @@
|
||||
Text="There were some errors while opening container."
|
||||
TextWrapping="Wrap" />
|
||||
|
||||
<ItemsRepeater Grid.Row="1"
|
||||
ItemsSource="{Binding AppState.SelectedTab^.CurrentSelectedItem.Value.BaseItem.Exceptions}">
|
||||
<ItemsRepeater Grid.Row="1" ItemsSource="{Binding AppState.SelectedTab^.CurrentSelectedItem.Value.BaseItem.Exceptions}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock
|
||||
@@ -588,30 +574,109 @@
|
||||
</ItemsRepeater>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<Grid DataContext="{Binding ItemPreviewService.ItemPreview^}" IsVisible="{Binding Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||
<Grid IsVisible="{Binding Name, Converter={StaticResource EqualsConverter}, ConverterParameter={x:Static itemPreview:ElementPreviewViewModel.PreviewName}}" x:DataType="itemPreview:ElementPreviewViewModel">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualsConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Unknown}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}"
|
||||
IsVisible="{Binding Mode, Converter={StaticResource EqualsConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Unknown}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}"
|
||||
Text="Don't know how to preview this item." />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Center"
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualsConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Empty}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}"
|
||||
IsVisible="{Binding Mode, Converter={StaticResource EqualsConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Empty}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}"
|
||||
Text="Empty" />
|
||||
<Grid
|
||||
IsVisible="{Binding ItemPreviewService.ItemPreview^.Mode, Converter={StaticResource EqualsConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Text}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}"
|
||||
RowDefinitions="*, Auto">
|
||||
<Grid IsVisible="{Binding Mode, Converter={StaticResource EqualsConverter}, ConverterParameter={x:Static appCoreModels:ItemPreviewMode.Text}, FallbackValue={x:Static appCoreModels:ItemPreviewMode.Unknown}}" RowDefinitions="*, Auto">
|
||||
<ScrollViewer>
|
||||
<TextBox
|
||||
IsReadOnly="True"
|
||||
Text="{Binding ItemPreviewService.ItemPreview^.TextContent}"
|
||||
x:CompileBindings="False" />
|
||||
<TextBox IsReadOnly="True" Text="{Binding TextContent}" />
|
||||
</ScrollViewer>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
Margin="5"
|
||||
Text="{Binding ItemPreviewService.ItemPreview^.TextEncoding, StringFormat=Encoding: {0}}"
|
||||
x:CompileBindings="False" />
|
||||
Text="{Binding TextEncoding, StringFormat=Encoding: {0}}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid
|
||||
IsVisible="{Binding Name, Converter={StaticResource EqualsConverter}, ConverterParameter={x:Static sizePreview:ContainerSizeContainerPreview.PreviewName}}"
|
||||
RowDefinitions="Auto, Auto"
|
||||
x:DataType="sizePreview:ContainerSizeContainerPreview">
|
||||
<ItemsControl Items="{Binding TopItems^}" Margin="0,0,0,30">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid.Width>
|
||||
<MultiBinding Converter="{StaticResource ItemSizeToSizeConverter}">
|
||||
<MultiBinding.Bindings>
|
||||
<Binding />
|
||||
<Binding ElementName="SizeContainerPreview" Path="DataContext.TopItems^" />
|
||||
<Binding ElementName="SizeContainerPreview" Path="Bounds.Width" />
|
||||
</MultiBinding.Bindings>
|
||||
</MultiBinding>
|
||||
</Grid.Width>
|
||||
|
||||
<Rectangle HorizontalAlignment="Stretch">
|
||||
<Rectangle.Fill>
|
||||
<MultiBinding Converter="{StaticResource ItemSizeToBrushConverter}">
|
||||
<MultiBinding.Bindings>
|
||||
<Binding />
|
||||
<Binding ElementName="SizeContainerPreview" Path="DataContext.Items^" />
|
||||
</MultiBinding.Bindings>
|
||||
</MultiBinding>
|
||||
</Rectangle.Fill>
|
||||
</Rectangle>
|
||||
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||
<TextBlock
|
||||
Classes="SmallText"
|
||||
Margin="0,5,0,2"
|
||||
Text="{Binding Name}">
|
||||
<TextBlock.Foreground>
|
||||
<MultiBinding Converter="{StaticResource ItemSizeToForegroundBrushConverter}">
|
||||
<MultiBinding.Bindings>
|
||||
<Binding />
|
||||
<Binding ElementName="SizeContainerPreview" Path="DataContext.Items^" />
|
||||
</MultiBinding.Bindings>
|
||||
</MultiBinding>
|
||||
</TextBlock.Foreground>
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Classes="SmallText"
|
||||
Margin="0,2,0,5"
|
||||
Text="{Binding Size, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}">
|
||||
<TextBlock.Foreground>
|
||||
<MultiBinding Converter="{StaticResource ItemSizeToForegroundBrushConverter}">
|
||||
<MultiBinding.Bindings>
|
||||
<Binding />
|
||||
<Binding ElementName="SizeContainerPreview" Path="DataContext.Items^" />
|
||||
</MultiBinding.Bindings>
|
||||
</MultiBinding>
|
||||
</TextBlock.Foreground>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<ItemsControl
|
||||
Grid.Row="1"
|
||||
Items="{Binding Items^}"
|
||||
x:CompileBindings="False">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid ColumnDefinitions="Auto,*" Margin="0,0,0,20">
|
||||
<TextBlock Text="{Binding Name}" />
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0,0,20,0"
|
||||
Text="{Binding Size, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
@@ -654,9 +719,7 @@
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="3">
|
||||
<Grid
|
||||
IsVisible="{Binding AppState.ViewMode^, Converter={StaticResource EqualsConverter}, ConverterParameter=RapidTravel}"
|
||||
RowDefinitions="1,Auto">
|
||||
<Grid IsVisible="{Binding AppState.ViewMode^, Converter={StaticResource EqualsConverter}, ConverterParameter=RapidTravel}" RowDefinitions="1,Auto">
|
||||
|
||||
<Rectangle
|
||||
Fill="{DynamicResource ContentSeparatorBrush}"
|
||||
@@ -678,8 +741,7 @@
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
IsVisible="{Binding AppState.PossibleCommands.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
||||
<Grid IsVisible="{Binding AppState.PossibleCommands.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="1" />
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -702,8 +764,7 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Text="{Binding KeysDisplayText}" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Text="{Binding Command, Converter={StaticResource CommandToCommandNameConverter}}" />
|
||||
<TextBlock Grid.Column="1" Text="{Binding Command, Converter={StaticResource CommandToCommandNameConverter}}" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
@@ -772,10 +833,8 @@
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid>
|
||||
<Grid
|
||||
IsVisible="{Binding PreviewType, Converter={StaticResource EqualsConverter}, ConverterParameter={x:Static appInteractions:PreviewType.DoubleTextList}}">
|
||||
<ItemsControl ItemsSource="{Binding Items}"
|
||||
x:DataType="appInteractions:DoubleTextListPreview">
|
||||
<Grid IsVisible="{Binding PreviewType, Converter={StaticResource EqualsConverter}, ConverterParameter={x:Static appInteractions:PreviewType.DoubleTextList}}">
|
||||
<ItemsControl ItemsSource="{Binding Items}" x:DataType="appInteractions:DoubleTextListPreview">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid ColumnDefinitions="*,*">
|
||||
@@ -787,13 +846,11 @@
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Text}"
|
||||
TextDecorations="{Binding IsSpecial, Converter={StaticResource TextDecorationConverter}}" />
|
||||
<TextBlock Text="{Binding Text}" TextDecorations="{Binding IsSpecial, Converter={StaticResource TextDecorationConverter}}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<ItemsControl Grid.Column="1"
|
||||
ItemsSource="{Binding Text2^}">
|
||||
<ItemsControl Grid.Column="1" ItemsSource="{Binding Text2^}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel Orientation="Horizontal" />
|
||||
@@ -801,8 +858,7 @@
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Text}"
|
||||
TextDecorations="{Binding IsSpecial, Converter={StaticResource TextDecorationConverter}}" />
|
||||
<TextBlock Text="{Binding Text}" TextDecorations="{Binding IsSpecial, Converter={StaticResource TextDecorationConverter}}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
@@ -908,7 +964,7 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
IsVisible="{Binding ShowWindow^, FallbackValue=False}"
|
||||
VerticalAlignment="Stretch">
|
||||
<Grid Margin="100" Background="{DynamicResource ContainerBackgroundColor}">
|
||||
<Grid Background="{DynamicResource ContainerBackgroundColor}" Margin="100">
|
||||
<local:FrequencyNavigation IsVisible="{Binding ShowWindow^, FallbackValue=False}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
@@ -919,7 +975,7 @@
|
||||
HorizontalAlignment="Stretch"
|
||||
IsVisible="{Binding ShowWindow^, FallbackValue=False}"
|
||||
VerticalAlignment="Stretch">
|
||||
<Grid Margin="100" Background="{DynamicResource ContainerBackgroundColor}">
|
||||
<Grid Background="{DynamicResource ContainerBackgroundColor}" Margin="100">
|
||||
<local:CommandPalette IsVisible="{Binding ShowWindow^, FallbackValue=False}" />
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
@@ -10,7 +10,7 @@ public sealed class CombineProperty<TFrom, TTo> : DeclarativePropertyBase<TTo>
|
||||
_combiner = combiner;
|
||||
}
|
||||
|
||||
public async Task AddSource(IDeclarativeProperty<TFrom> source)
|
||||
public async Task AddSourceAsync(IDeclarativeProperty<TFrom> source)
|
||||
{
|
||||
if (_sourceProperties.Contains(source)) return;
|
||||
_sourceProperties.Add(source);
|
||||
|
||||
Reference in New Issue
Block a user