This commit is contained in:
2022-02-23 22:47:43 +01:00
parent 4952c68ce9
commit cef8e5de18
20 changed files with 1790 additions and 41 deletions

View File

@@ -0,0 +1,9 @@
using FileTime.Core.Models;
namespace FileTime.App.Core.Models
{
public interface IHaveContainer
{
IContainer Container { get; }
}
}

View File

@@ -8,12 +8,13 @@ namespace FileTime.Core.Components
public class Tab public class Tab
{ {
private IItem? _currentSelectedItem; private IItem? _currentSelectedItem;
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
private IContainer _currentLocation; private IContainer _currentLocation;
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
private readonly List<AbsolutePath> _history = new();
private string? _lastPath; private string? _lastPath;
private bool _currentlySelecting = false; private bool _currentlySelecting;
private readonly object _guardSetCurrentSelectedItemCTS = new(); private readonly object _guardSetCurrentSelectedItemCTS = new();
private CancellationTokenSource? _setCurrentSelectedItemCTS; private CancellationTokenSource? _setCurrentSelectedItemCTS;
@@ -22,9 +23,18 @@ namespace FileTime.Core.Components
public bool AutoRefresh { get; set; } public bool AutoRefresh { get; set; }
public IReadOnlyList<AbsolutePath> History { get; }
public AsyncEventHandler CurrentLocationChanged = new(); public AsyncEventHandler CurrentLocationChanged = new();
public AsyncEventHandler HistoryChanged { get; } = new();
public AsyncEventHandler<bool> CurrentSelectedItemChanged = new(); public AsyncEventHandler<bool> CurrentSelectedItemChanged = new();
public Tab()
{
_currentLocation = null!;
History = _history.AsReadOnly();
}
public async Task Init(IContainer currentPath) public async Task Init(IContainer currentPath)
{ {
await SetCurrentLocation(currentPath); await SetCurrentLocation(currentPath);
@@ -49,6 +59,7 @@ namespace FileTime.Core.Components
} }
_currentLocation = value; _currentLocation = value;
await AddHistoryItem(_currentLocation);
await CurrentLocationChanged.InvokeAsync(this, AsyncEventArgs.Empty); await CurrentLocationChanged.InvokeAsync(this, AsyncEventArgs.Empty);
var currentLocationItems = await (await GetCurrentLocation()).GetItems(); var currentLocationItems = await (await GetCurrentLocation()).GetItems();
@@ -58,6 +69,22 @@ namespace FileTime.Core.Components
} }
} }
private async Task AddHistoryItem(IContainer container)
{
var containerPath = new AbsolutePath(container);
if (_history.Count == 0 || _history.Last() != containerPath)
{
_history.Add(containerPath);
}
while (_history.Count > 50)
{
_history.RemoveAt(0);
}
await HistoryChanged.InvokeAsync(this, AsyncEventArgs.Empty);
}
public Task<IItem?> GetCurrentSelectedItem() public Task<IItem?> GetCurrentSelectedItem()
{ {
return Task.FromResult(_currentSelectedItem); return Task.FromResult(_currentSelectedItem);

View File

@@ -82,6 +82,8 @@ namespace FileTime.Core.Models
? await VirtualContentProvider.GetByPath(Path) ? await VirtualContentProvider.GetByPath(Path)
: null; : null;
if (ContentProvider == null) return null;
result ??= await ContentProvider.GetByPath(Path); result ??= await ContentProvider.GetByPath(Path);
return result; return result;

View File

@@ -97,6 +97,7 @@ namespace FileTime.Core.Providers
{ {
lock (_initializationGuard) lock (_initializationGuard)
{ {
if (_initialized) return;
if (!_initializing) if (!_initializing)
{ {
_initializing = true; _initializing = true;
@@ -109,8 +110,8 @@ namespace FileTime.Core.Providers
try try
{ {
if (_initialized) return; if (_initialized) return;
_initialized = true;
await Init(); await Init();
_initialized = true;
IsLoaded = true; IsLoaded = true;
} }
finally finally

View File

@@ -0,0 +1,148 @@
// Autogenerated
namespace InitableService;
public interface IInitable
{
void Init();
}
public interface IInitable<T1>
{
void Init(T1 obj1);
}
public interface IInitable<T1, T2>
{
void Init(T1 obj1, T2 obj2);
}
public interface IInitable<T1, T2, T3>
{
void Init(T1 obj1, T2 obj2, T3 obj3);
}
public interface IInitable<T1, T2, T3, T4>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4);
}
public interface IInitable<T1, T2, T3, T4, T5>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5);
}
public interface IInitable<T1, T2, T3, T4, T5, T6>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6);
}
public interface IInitable<T1, T2, T3, T4, T5, T6, T7>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7);
}
public interface IInitable<T1, T2, T3, T4, T5, T6, T7, T8>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8);
}
public interface IInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9);
}
public interface IInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10);
}
public interface IInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11);
}
public interface IInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12);
}
public interface IInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13);
}
public interface IInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14);
}
public interface IInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>
{
void Init(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14, T15 obj15);
}
public interface IAsyncInitable
{
Task InitAsync();
}
public interface IAsyncInitable<T1>
{
Task InitAsync(T1 obj1);
}
public interface IAsyncInitable<T1, T2>
{
Task InitAsync(T1 obj1, T2 obj2);
}
public interface IAsyncInitable<T1, T2, T3>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3);
}
public interface IAsyncInitable<T1, T2, T3, T4>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4);
}
public interface IAsyncInitable<T1, T2, T3, T4, T5>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5);
}
public interface IAsyncInitable<T1, T2, T3, T4, T5, T6>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6);
}
public interface IAsyncInitable<T1, T2, T3, T4, T5, T6, T7>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7);
}
public interface IAsyncInitable<T1, T2, T3, T4, T5, T6, T7, T8>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8);
}
public interface IAsyncInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9);
}
public interface IAsyncInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10);
}
public interface IAsyncInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11);
}
public interface IAsyncInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12);
}
public interface IAsyncInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13);
}
public interface IAsyncInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14);
}
public interface IAsyncInitable<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15>
{
Task InitAsync(T1 obj1, T2 obj2, T3 obj3, T4 obj4, T5 obj5, T6 obj6, T7 obj7, T8 obj8, T9 obj9, T10 obj10, T11 obj11, T12 obj12, T13 obj13, T14 obj14, T15 obj15);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="6.0.0" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,180 @@
#!/usr/bin/env dotnet-script
{
const string header =
@"// Autogenerated
using InitableService;
namespace Microsoft.Extensions.DependencyInjection;
public static class InitableExtensions
{
";
const string footer = "}";
using var initableWriter = File.CreateText("InitableExtensions.cs");
initableWriter.WriteLine(header);
const int generateForParams = 15;
for (var i = 0; i <= generateForParams; i++)
{
WriteInitableExtension(initableWriter, false, i);
initableWriter.WriteLine();
}
for (var i = 0; i <= generateForParams; i++)
{
WriteInitableExtension(initableWriter, true, i);
initableWriter.WriteLine();
}
initableWriter.WriteLine(footer);
for (var i = 0; i <= generateForParams; i++)
{
WriteInitableResolver(initableWriter, false, i);
initableWriter.WriteLine();
}
for (var i = 0; i <= generateForParams; i++)
{
WriteInitableResolver(initableWriter, true, i);
initableWriter.WriteLine();
}
initableWriter.Flush();
}
void WriteInitableExtension(StreamWriter initableWriter, bool isAsync, int i)
{
initableWriter.Write($"\tpublic static {(isAsync ? "Async" : "")}Resolver");
if (i > 0)
{
initableWriter.Write("<");
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c)));
initableWriter.Write(">");
}
initableWriter.Write($" Get{(isAsync ? "Async" : "")}InitableResolver");
if (i > 0)
{
initableWriter.Write("<");
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c)));
initableWriter.Write(">");
}
initableWriter.Write("(");
var thisParameter = "this IServiceProvider serviceProvider";
if (i > 0)
{
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => $"T{c} obj{c}").Prepend(thisParameter)));
}
else
{
initableWriter.Write(thisParameter);
}
initableWriter.WriteLine(")");
initableWriter.WriteLine("\t{");
initableWriter.Write($"\t\treturn new {(isAsync ? "Async" : "")}Resolver");
if (i > 0)
{
initableWriter.Write("<");
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c)));
initableWriter.Write(">");
}
initableWriter.Write("(");
if (i > 0)
{
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => $"obj{c}").Prepend("serviceProvider")));
}
else
{
initableWriter.Write("serviceProvider");
}
initableWriter.WriteLine(");");
initableWriter.WriteLine("\t}");
}
void WriteInitableResolver(StreamWriter initableWriter, bool isAsync, int i)
{
initableWriter.Write($"public class {(isAsync ? "Async" : "")}Resolver");
if (i > 0)
{
initableWriter.Write("<");
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c)));
initableWriter.Write(">");
}
initableWriter.WriteLine();
initableWriter.WriteLine("{");
initableWriter.WriteLine("\tIServiceProvider _serviceProvider;");
if (i > 0)
{
for (var j = 1; j <= i; j++)
{
initableWriter.WriteLine($"\tprivate T{j} _obj{j};");
}
}
initableWriter.Write($"\tpublic {(isAsync ? "Async" : "")}Resolver(");
if (i > 0)
{
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => $"T{c} obj{c}").Prepend("IServiceProvider serviceProvider")));
}
else
{
initableWriter.Write("IServiceProvider serviceProvider");
}
initableWriter.WriteLine(")");
initableWriter.WriteLine("\t{");
initableWriter.WriteLine("\t\t_serviceProvider = serviceProvider;");
if (i > 0)
{
for (var j = 1; j <= i; j++)
{
initableWriter.WriteLine($"\t\t_obj{j} = obj{j};");
}
}
initableWriter.WriteLine("\t}");
initableWriter.WriteLine("");
var returnType = isAsync ? "async Task<TResult>" : "TResult";
initableWriter.WriteLine($"\tpublic {returnType} GetService{(isAsync ? "Async" : "")}<TResult>()");
initableWriter.Write($"\t\twhere TResult : class, I{(isAsync ? "Async" : "")}Initable");
if (i > 0)
{
initableWriter.Write("<");
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c)));
initableWriter.Write(">");
}
initableWriter.WriteLine("");
initableWriter.WriteLine("\t{");
initableWriter.WriteLine("\t\tvar initableService = _serviceProvider.GetService<TResult>()!;");
if (isAsync)
{
initableWriter.Write("\t\tawait initableService.InitAsync");
}
else
{
initableWriter.Write("\t\tinitableService.Init");
}
initableWriter.Write("(");
if (i > 0)
{
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => $"_obj{c}")));
}
initableWriter.WriteLine(");");
initableWriter.WriteLine("\t\treturn initableService;");
initableWriter.WriteLine("\t}");
initableWriter.WriteLine("}");
}

View File

@@ -0,0 +1,66 @@
#!/usr/bin/env dotnet-script
{
const string header =
@"// Autogenerated
namespace InitableService;
";
const string footer = "";
using var initableWriter = File.CreateText("Initable.cs");
initableWriter.WriteLine(header);
const int generateForParams = 15;
for (var i = 0; i <= generateForParams; i++)
{
WriteInitable(initableWriter, false, i);
}
for (var i = 0; i <= generateForParams; i++)
{
WriteInitable(initableWriter, true, i);
initableWriter.WriteLine();
}
initableWriter.WriteLine(footer);
initableWriter.Flush();
}
void WriteInitable(StreamWriter initableWriter, bool isAsync, int i)
{
initableWriter.Write($"public interface I{(isAsync ? "Async" : "")}Initable");
if (i > 0)
{
initableWriter.Write("<");
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c)));
initableWriter.Write(">");
}
initableWriter.WriteLine();
initableWriter.WriteLine("{");
if (isAsync)
{
initableWriter.Write("\tTask InitAsync");
}
else
{
initableWriter.Write("\tvoid Init");
}
if (i > 0)
{
/*initableWriter.Write("<");
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => "T" + c)));
initableWriter.Write(">");*/
initableWriter.Write("(");
initableWriter.Write(string.Join(", ", Enumerable.Range(1, i).Select(c => $"T{c} obj{c}")));
initableWriter.Write(")");
}
else
{
initableWriter.Write("()");
}
initableWriter.WriteLine(";");
initableWriter.WriteLine("}");
}

View File

@@ -41,6 +41,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.Tools.Compression"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.Providers.Sftp", "Providers\FileTime.Providers.Sftp\FileTime.Providers.Sftp.csproj", "{0E650206-801D-4E8D-95BA-4565B32092E1}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileTime.Providers.Sftp", "Providers\FileTime.Providers.Sftp\FileTime.Providers.Sftp.csproj", "{0E650206-801D-4E8D-95BA-4565B32092E1}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InitableService", "Core\InitableService\InitableService.csproj", "{B1520189-8646-4DE8-B5C9-46AE04B4D01C}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@@ -315,6 +317,26 @@ Global
{0E650206-801D-4E8D-95BA-4565B32092E1}.Release|x64.Build.0 = Release|Any CPU {0E650206-801D-4E8D-95BA-4565B32092E1}.Release|x64.Build.0 = Release|Any CPU
{0E650206-801D-4E8D-95BA-4565B32092E1}.Release|x86.ActiveCfg = Release|Any CPU {0E650206-801D-4E8D-95BA-4565B32092E1}.Release|x86.ActiveCfg = Release|Any CPU
{0E650206-801D-4E8D-95BA-4565B32092E1}.Release|x86.Build.0 = Release|Any CPU {0E650206-801D-4E8D-95BA-4565B32092E1}.Release|x86.Build.0 = Release|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Debug|ARM.ActiveCfg = Debug|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Debug|ARM.Build.0 = Debug|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Debug|ARM64.Build.0 = Debug|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Debug|x64.ActiveCfg = Debug|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Debug|x64.Build.0 = Debug|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Debug|x86.ActiveCfg = Debug|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Debug|x86.Build.0 = Debug|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Release|Any CPU.Build.0 = Release|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Release|ARM.ActiveCfg = Release|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Release|ARM.Build.0 = Release|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Release|ARM64.ActiveCfg = Release|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Release|ARM64.Build.0 = Release|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Release|x64.ActiveCfg = Release|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Release|x64.Build.0 = Release|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Release|x86.ActiveCfg = Release|Any CPU
{B1520189-8646-4DE8-B5C9-46AE04B4D01C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -333,6 +355,7 @@ Global
{22B33BC6-3987-4BE6-8C54-BFC75C78CCE7} = {890275FF-943A-4D07-83BA-14E5C52D7846} {22B33BC6-3987-4BE6-8C54-BFC75C78CCE7} = {890275FF-943A-4D07-83BA-14E5C52D7846}
{B6F6A8F9-9B7B-4E3E-AE99-A90ECFDDC966} = {0D2B4BAA-0399-459C-B022-41DB7F408225} {B6F6A8F9-9B7B-4E3E-AE99-A90ECFDDC966} = {0D2B4BAA-0399-459C-B022-41DB7F408225}
{0E650206-801D-4E8D-95BA-4565B32092E1} = {517D96CE-A956-4638-A93D-465D34DE22B1} {0E650206-801D-4E8D-95BA-4565B32092E1} = {517D96CE-A956-4638-A93D-465D34DE22B1}
{B1520189-8646-4DE8-B5C9-46AE04B4D01C} = {38B1B927-4201-4B7A-87EE-737B8C6D4090}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8D679DCE-AC84-4A91-BFED-8F8D8E1D8183} SolutionGuid = {8D679DCE-AC84-4A91-BFED-8F8D8E1D8183}

View File

@@ -187,19 +187,11 @@
</Setter> </Setter>
</Style> </Style>
<Style Selector="Grid.RootDriveInfo"> <Style Selector="Grid.SidebarContainerPresenter">
<Setter Property="Background" Value="#01000000"/> <Setter Property="Background" Value="#01000000"/>
</Style> </Style>
<Style Selector="Grid.RootDriveInfo:pointerover"> <Style Selector="Grid.SidebarContainerPresenter:pointerover">
<Setter Property="Background" Value="{DynamicResource AppBackgroundColor}"/>
</Style>
<Style Selector="Grid.PlacesItem">
<Setter Property="Background" Value="#01000000"/>
</Style>
<Style Selector="Grid.PlacesItem:pointerover">
<Setter Property="Background" Value="{DynamicResource AppBackgroundColor}"/> <Setter Property="Background" Value="{DynamicResource AppBackgroundColor}"/>
</Style> </Style>

View File

@@ -1,4 +1,4 @@
using AsyncEvent; using AsyncEvent;
using FileTime.Core.Components; using FileTime.Core.Components;
using FileTime.Core.Models; using FileTime.Core.Models;
using FileTime.Providers.Local; using FileTime.Providers.Local;
@@ -16,6 +16,8 @@ using FileTime.Core.Search;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using FileTime.Core.Services; using FileTime.Core.Services;
using FileTime.Core.ContainerSizeScanner; using FileTime.Core.ContainerSizeScanner;
using System.Collections.Generic;
using FileTime.Core.Providers;
namespace FileTime.Avalonia.Application namespace FileTime.Avalonia.Application
{ {
@@ -71,6 +73,9 @@ namespace FileTime.Avalonia.Application
[Property] [Property]
private IItemPreviewViewModel? _itemPreview; private IItemPreviewViewModel? _itemPreview;
[Property]
private List<HistoryItemViewModel> _history = new();
public async Task SetSelectedItemAsync(IItemViewModel? value) public async Task SetSelectedItemAsync(IItemViewModel? value)
{ {
if (_selectedItem != value) if (_selectedItem != value)
@@ -86,7 +91,38 @@ namespace FileTime.Avalonia.Application
{ {
_tabState = new TabState(Tab); _tabState = new TabState(Tab);
_timeRunner.RefreshContainer.Add(TimeRunnerContainerRefreshed); _timeRunner.RefreshContainer.Add(TimeRunnerContainerRefreshed);
Tab.HistoryChanged.Add(TabHistoryChanged);
}
private async Task TabHistoryChanged(object? sender, AsyncEventArgs e, CancellationToken token)
{
await RefreshHistory();
}
private async Task RefreshHistory()
{
var newHistory = new List<HistoryItemViewModel>();
var counter = 0;
AbsolutePath? lastPath = null;
foreach (var history in Tab.History.Reverse())
{
try
{
var historyItemVM = await _serviceProvider.GetAsyncInitableResolver(history).GetServiceAsync<HistoryItemViewModel>();
if (historyItemVM.Container != null && historyItemVM.Container is not IContentProvider && lastPath != history)
{
lastPath = history;
newHistory.Add(historyItemVM);
counter++;
if (counter == 10) break;
}
}
catch { }
}
History = newHistory;
} }
private async Task TimeRunnerContainerRefreshed(object? sender, AbsolutePath container, CancellationToken token = default) private async Task TimeRunnerContainerRefreshed(object? sender, AbsolutePath container, CancellationToken token = default)

View File

@@ -52,6 +52,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\AppCommon\FileTime.App.Core\FileTime.App.Core.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.DependencyInjection\FileTime.App.DependencyInjection.csproj" />
<ProjectReference Include="..\..\Core\InitableService\InitableService.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AvaloniaXaml Update="Views\MainWindow.axaml"> <AvaloniaXaml Update="Views\MainWindow.axaml">

View File

@@ -1,8 +1,9 @@
using FileTime.App.Core.Models;
using FileTime.Core.Models; using FileTime.Core.Models;
namespace FileTime.Avalonia.Models namespace FileTime.Avalonia.Models
{ {
public class PlaceInfo public class PlaceInfo : IHaveContainer
{ {
public string Name { get; } public string Name { get; }
public IContainer Container { get; } public IContainer Container { get; }

View File

@@ -1,4 +1,5 @@
using FileTime.Core.Models; using FileTime.App.Core.Models;
using FileTime.Core.Models;
using FileTime.Providers.Local; using FileTime.Providers.Local;
using MvvmGen; using MvvmGen;
using System.IO; using System.IO;
@@ -7,7 +8,7 @@ using System.Runtime.InteropServices;
namespace FileTime.Avalonia.Models namespace FileTime.Avalonia.Models
{ {
[ViewModel] [ViewModel]
public partial class RootDriveInfo public partial class RootDriveInfo : IHaveContainer
{ {
private readonly DriveInfo _driveInfo; private readonly DriveInfo _driveInfo;
private readonly IContainer _container; private readonly IContainer _container;

View File

@@ -8,7 +8,6 @@ using FileTime.Avalonia.Logging;
using FileTime.Avalonia.Services; using FileTime.Avalonia.Services;
using FileTime.Avalonia.ViewModels; using FileTime.Avalonia.ViewModels;
using FileTime.Avalonia.ViewModels.ItemPreview; using FileTime.Avalonia.ViewModels.ItemPreview;
using FileTime.Core.Command;
using FileTime.Core.Interactions; using FileTime.Core.Interactions;
using FileTime.Core.Persistence; using FileTime.Core.Persistence;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
@@ -29,6 +28,7 @@ namespace FileTime.Avalonia
.AddTransient<SizeContainerViewModel>() .AddTransient<SizeContainerViewModel>()
.AddTransient<SizeElementViewmodel>() .AddTransient<SizeElementViewmodel>()
.AddTransient<SizeContainerPreview>() .AddTransient<SizeContainerPreview>()
.AddTransient<HistoryItemViewModel>()
.AddSingleton<IInputInterface, BasicInputHandler>(); .AddSingleton<IInputInterface, BasicInputHandler>();
} }
internal static IServiceCollection AddServices(this IServiceCollection serviceCollection) internal static IServiceCollection AddServices(this IServiceCollection serviceCollection)

View File

@@ -228,6 +228,11 @@ namespace FileTime.Avalonia.ViewModels
} }
} }
foreach (var oldContainer in _containers.Except(newContainers))
{
oldContainer.Unload(recursive: true, unloadParent: false, unloadEvents: true);
}
if (silent) if (silent)
{ {
_containers = new ObservableCollection<ContainerViewModel>(newContainers); _containers = new ObservableCollection<ContainerViewModel>(newContainers);
@@ -251,10 +256,15 @@ namespace FileTime.Avalonia.ViewModels
_exceptions.Add(e); _exceptions.Add(e);
} }
try
{
await _newItemProcessor.UpdateMarkedItems(this, CancellationToken.None); await _newItemProcessor.UpdateMarkedItems(this, CancellationToken.None);
}
finally
{
_isRefreshing = false; _isRefreshing = false;
} }
}
private int GetNewItemPosition<TItem, T>(TItem itemToAdd, IList<T> items) where TItem : IItemViewModel where T : IItemViewModel private int GetNewItemPosition<TItem, T>(TItem itemToAdd, IList<T> items) where TItem : IItemViewModel where T : IItemViewModel
{ {
@@ -320,7 +330,12 @@ namespace FileTime.Avalonia.ViewModels
if (unloadEvents) if (unloadEvents)
{ {
if (BaseContainer is ContainerSizeContainer sizeContainer)
{
sizeContainer.SizeChanged.Remove(UpdateSize);
}
Container.Refreshed.Remove(Container_Refreshed); Container.Refreshed.Remove(Container_Refreshed);
Container.LazyLoadingChanged.Remove(Container_LazyLoadingChanged);
} }
_containers.Clear(); _containers.Clear();

View File

@@ -0,0 +1,19 @@
using FileTime.Core.Models;
using InitableService;
using System;
using System.Threading.Tasks;
namespace FileTime.Avalonia.ViewModels
{
public class HistoryItemViewModel : IAsyncInitable<AbsolutePath>
{
public string? Name { get; private set; }
public IContainer? Container { get; private set; }
public async Task InitAsync(AbsolutePath path)
{
Container = await path.ResolveAsync() as IContainer ?? throw new ArgumentException($"Parameter must be {nameof(IContainer)}", nameof(path));
Name = Container.DisplayName;
}
}
}

View File

@@ -41,7 +41,7 @@
</StackPanel> </StackPanel>
</Grid> </Grid>
<Grid Grid.Row="1" RowDefinitions="Auto,Auto"> <Grid Grid.Row="1" RowDefinitions="Auto,Auto,Auto">
<Border CornerRadius="10" Background="{DynamicResource ContainerBackgroundBrush}" Padding="10" Margin="10"> <Border CornerRadius="10" Background="{DynamicResource ContainerBackgroundBrush}" Padding="10" Margin="10">
<Grid RowDefinitions="Auto,Auto"> <Grid RowDefinitions="Auto,Auto">
@@ -55,7 +55,7 @@
Items="{Binding RootDriveInfos}"> Items="{Binding RootDriveInfos}">
<ItemsRepeater.ItemTemplate> <ItemsRepeater.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid Classes="RootDriveInfo" PointerPressed="OnRootDrivePointerPressed" Cursor="Hand"> <Grid Classes="SidebarContainerPresenter" PointerPressed="OnHasContainerPointerPressed" Cursor="Hand">
<Grid Margin="0,5" ColumnDefinitions="Auto,*,Auto" RowDefinitions="Auto,Auto"> <Grid Margin="0,5" ColumnDefinitions="Auto,*,Auto" RowDefinitions="Auto,Auto">
<Image <Image
Grid.RowSpan="2" Grid.RowSpan="2"
@@ -128,7 +128,7 @@
Items="{Binding Places}"> Items="{Binding Places}">
<ItemsRepeater.ItemTemplate> <ItemsRepeater.ItemTemplate>
<DataTemplate> <DataTemplate>
<Grid Classes="PlacesItem" PointerPressed="OnPlacePointerPressed" Cursor="Hand"> <Grid Classes="SidebarContainerPresenter" PointerPressed="OnHasContainerPointerPressed" Cursor="Hand">
<StackPanel Orientation="Horizontal" Margin="10,5" HorizontalAlignment="Stretch"> <StackPanel Orientation="Horizontal" Margin="10,5" HorizontalAlignment="Stretch">
<Image <Image
Width="20" Width="20"
@@ -147,6 +147,39 @@
</ItemsRepeater> </ItemsRepeater>
</Grid> </Grid>
</Border> </Border>
<Border Grid.Row="2" CornerRadius="10" Background="{DynamicResource ContainerBackgroundBrush}" Padding="0,10" Margin="10">
<Grid RowDefinitions="Auto,Auto">
<TextBlock
Margin="10,0,10,10"
Text="History" />
<ItemsRepeater
Grid.Row="1"
Items="{Binding AppState.SelectedTab.History}">
<ItemsRepeater.ItemTemplate>
<DataTemplate>
<Grid Classes="SidebarContainerPresenter" PointerPressed="OnHasContainerPointerPressed" Cursor="Hand">
<StackPanel Orientation="Horizontal" Margin="10,5" HorizontalAlignment="Stretch">
<Image
Width="20"
Height="20"
VerticalAlignment="Center"
Source="{Binding Container,Converter={StaticResource ItemToImageConverter}}" />
<TextBlock
Margin="5,0,0,0"
VerticalAlignment="Center"
Text="{Binding Name}" />
</StackPanel>
</Grid>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</Grid>
</Border>
</Grid> </Grid>
<Grid Grid.Column="1" Grid.Row="1" RowDefinitions="Auto,40,*,Auto"> <Grid Grid.Column="1" Grid.Row="1" RowDefinitions="Auto,40,*,Auto">

View File

@@ -3,6 +3,7 @@ using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using FileTime.App.Core.Models;
using FileTime.Avalonia.Misc; using FileTime.Avalonia.Misc;
using FileTime.Avalonia.Models; using FileTime.Avalonia.Models;
using FileTime.Avalonia.ViewModels; using FileTime.Avalonia.ViewModels;
@@ -93,31 +94,19 @@ namespace FileTime.Avalonia.Views
} }
} }
private void OnPlacePointerPressed(object sender, PointerPressedEventArgs e) private void OnHasContainerPointerPressed(object sender, PointerPressedEventArgs e)
{ {
if (!e.Handled if (!e.Handled
&& ViewModel != null && ViewModel != null
&& e.GetCurrentPoint(this).Properties.IsLeftButtonPressed && e.GetCurrentPoint(this).Properties.IsLeftButtonPressed
&& sender is StyledElement control && sender is StyledElement control
&& control.DataContext is PlaceInfo placeInfo) && control.DataContext is IHaveContainer hasContainer)
{ {
ViewModel.CommandHandlerService.OpenContainer(placeInfo.Container); ViewModel.CommandHandlerService.OpenContainer(hasContainer.Container);
e.Handled = true; e.Handled = true;
} }
} }
private void OnRootDrivePointerPressed(object sender, PointerPressedEventArgs e)
{
if (!e.Handled
&& ViewModel != null
&& e.GetCurrentPoint(this).Properties.IsLeftButtonPressed
&& sender is StyledElement control
&& control.DataContext is RootDriveInfo rootDriveInfo)
{
ViewModel.CommandHandlerService.OpenContainer(rootDriveInfo.Container);
e.Handled = true;
}
}
private void OnWindowClosed(object sender, EventArgs e) private void OnWindowClosed(object sender, EventArgs e)
{ {
try try