IconProvider, container exceptions, refactor
This commit is contained in:
@@ -1,12 +1,11 @@
|
|||||||
using FileTime.Core.Command;
|
using FileTime.Core.Command;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Providers;
|
|
||||||
|
|
||||||
namespace FileTime.App.Core.Clipboard
|
namespace FileTime.App.Core.Clipboard
|
||||||
{
|
{
|
||||||
public class Clipboard : IClipboard
|
public class Clipboard : IClipboard
|
||||||
{
|
{
|
||||||
private readonly List<AbsolutePath> _content;
|
private List<AbsolutePath> _content;
|
||||||
public IReadOnlyList<AbsolutePath> Content { get; }
|
public IReadOnlyList<AbsolutePath> Content { get; }
|
||||||
public Type? CommandType { get; private set; }
|
public Type? CommandType { get; private set; }
|
||||||
|
|
||||||
@@ -39,7 +38,7 @@ namespace FileTime.App.Core.Clipboard
|
|||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
_content.Clear();
|
_content = new List<AbsolutePath>();
|
||||||
CommandType = null;
|
CommandType = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ namespace FileTime.Core.Models
|
|||||||
{
|
{
|
||||||
public interface IContainer : IItem
|
public interface IContainer : IItem
|
||||||
{
|
{
|
||||||
|
IReadOnlyList<Exception> Exceptions { get; }
|
||||||
Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default);
|
Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default);
|
||||||
Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default);
|
Task<IReadOnlyList<IContainer>?> GetContainers(CancellationToken token = default);
|
||||||
Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default);
|
Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default);
|
||||||
@@ -16,6 +17,7 @@ namespace FileTime.Core.Models
|
|||||||
Task<bool> IsExists(string name);
|
Task<bool> IsExists(string name);
|
||||||
|
|
||||||
Task<IContainer> Clone();
|
Task<IContainer> Clone();
|
||||||
|
Task<bool> CanOpen();
|
||||||
|
|
||||||
bool IsLoaded { get; }
|
bool IsLoaded { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace FileTime.Core.Models
|
|||||||
public bool CanRename => BaseContainer.CanRename;
|
public bool CanRename => BaseContainer.CanRename;
|
||||||
|
|
||||||
public IContentProvider Provider => BaseContainer.Provider;
|
public IContentProvider Provider => BaseContainer.Provider;
|
||||||
|
public IReadOnlyList<Exception> Exceptions => BaseContainer.Exceptions;
|
||||||
|
|
||||||
public AsyncEventHandler Refreshed { get; }
|
public AsyncEventHandler Refreshed { get; }
|
||||||
|
|
||||||
@@ -164,5 +165,6 @@ namespace FileTime.Core.Models
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async Task Rename(string newName) => await BaseContainer.Rename(newName);
|
public async Task Rename(string newName) => await BaseContainer.Rename(newName);
|
||||||
|
public async Task<bool> CanOpen() => await BaseContainer.CanOpen();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,8 @@ namespace FileTime.Core.Providers
|
|||||||
|
|
||||||
public AsyncEventHandler Refreshed { get; } = new();
|
public AsyncEventHandler Refreshed { get; } = new();
|
||||||
|
|
||||||
|
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
|
||||||
|
|
||||||
public TopContainer(IEnumerable<IContentProvider> contentProviders)
|
public TopContainer(IEnumerable<IContentProvider> contentProviders)
|
||||||
{
|
{
|
||||||
_contentProviders = new List<IContentProvider>(contentProviders);
|
_contentProviders = new List<IContentProvider>(contentProviders);
|
||||||
@@ -62,5 +64,7 @@ namespace FileTime.Core.Providers
|
|||||||
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
|
public Task<IContainer> Clone() => Task.FromResult((IContainer)this);
|
||||||
|
|
||||||
public Task Rename(string newName) => throw new NotSupportedException();
|
public Task Rename(string newName) => throw new NotSupportedException();
|
||||||
|
|
||||||
|
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,7 @@ namespace FileTime.Core.Timeline
|
|||||||
|
|
||||||
public IContentProvider Provider { get; }
|
public IContentProvider Provider { get; }
|
||||||
public IContentProvider VirtualProvider { get; }
|
public IContentProvider VirtualProvider { get; }
|
||||||
|
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
|
||||||
|
|
||||||
public TimeContainer(string name, IContainer parent, IContentProvider contentProvider, IContentProvider virtualContentProvider, PointInTime pointInTime)
|
public TimeContainer(string name, IContainer parent, IContentProvider contentProvider, IContentProvider virtualContentProvider, PointInTime pointInTime)
|
||||||
{
|
{
|
||||||
@@ -117,5 +118,6 @@ namespace FileTime.Core.Timeline
|
|||||||
if (elementDiff.Type != DifferenceItemType.Container) throw new ArgumentException($"{elementDiff}'s {nameof(Difference.Type)} property is not {DifferenceItemType.Element}.");
|
if (elementDiff.Type != DifferenceItemType.Container) throw new ArgumentException($"{elementDiff}'s {nameof(Difference.Type)} property is not {DifferenceItemType.Element}.");
|
||||||
return new TimeElement(elementDiff.Name, this, Provider, elementDiff.AbsolutePath.VirtualContentProvider ?? elementDiff.AbsolutePath.ContentProvider);
|
return new TimeElement(elementDiff.Name, this, Provider, elementDiff.AbsolutePath.VirtualContentProvider ?? elementDiff.AbsolutePath.ContentProvider);
|
||||||
}
|
}
|
||||||
|
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,8 @@ namespace FileTime.Core.Timeline
|
|||||||
{
|
{
|
||||||
public class TimeProvider : IContentProvider
|
public class TimeProvider : IContentProvider
|
||||||
{
|
{
|
||||||
|
private readonly PointInTime _pointInTime;
|
||||||
|
|
||||||
public bool IsLoaded => true;
|
public bool IsLoaded => true;
|
||||||
|
|
||||||
public AsyncEventHandler Refreshed { get; } = new();
|
public AsyncEventHandler Refreshed { get; } = new();
|
||||||
@@ -22,7 +24,7 @@ namespace FileTime.Core.Timeline
|
|||||||
|
|
||||||
public IContentProvider Provider => this;
|
public IContentProvider Provider => this;
|
||||||
|
|
||||||
private readonly PointInTime _pointInTime;
|
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
|
||||||
|
|
||||||
public TimeProvider(PointInTime pointInTime)
|
public TimeProvider(PointInTime pointInTime)
|
||||||
{
|
{
|
||||||
@@ -85,5 +87,6 @@ namespace FileTime.Core.Timeline
|
|||||||
public Task Rename(string newName) => throw new NotSupportedException();
|
public Task Rename(string newName) => throw new NotSupportedException();
|
||||||
|
|
||||||
public void SetParent(IContainer container) { }
|
public void SetParent(IContainer container) { }
|
||||||
|
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,6 +120,8 @@
|
|||||||
<converters:ItemToImageConverter x:Key="ItemToImageConverter"/>
|
<converters:ItemToImageConverter x:Key="ItemToImageConverter"/>
|
||||||
<converters:IsNullConverter x:Key="IsNullConverter"/>
|
<converters:IsNullConverter x:Key="IsNullConverter"/>
|
||||||
<converters:IsNullConverter x:Key="IsNotNullConverter" Inverse="true"/>
|
<converters:IsNullConverter x:Key="IsNotNullConverter" Inverse="true"/>
|
||||||
|
<converters:IsEmptyConverter x:Key="IsEmptyConverter"/>
|
||||||
|
<converters:IsEmptyConverter x:Key="IsNotEmptyConverter" Inverse="true"/>
|
||||||
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
@@ -132,7 +134,7 @@
|
|||||||
<Setter Property="FontSize" Value="16"/>
|
<Setter Property="FontSize" Value="16"/>
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="TextBlock.SmallText">
|
<Style Selector="TextBlock.SmallText">
|
||||||
<Setter Property="FontSize" Value="16"/>
|
<Setter Property="FontSize" Value="12"/>
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="ListBox.ContentListView">
|
<Style Selector="ListBox.ContentListView">
|
||||||
<Setter Property="Background" Value="Transparent"/>
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
@@ -145,5 +147,13 @@
|
|||||||
<ContextMenu Items="{Binding Converter={StaticResource ContextMenuGenerator}}"/>
|
<ContextMenu Items="{Binding Converter={StaticResource ContextMenuGenerator}}"/>
|
||||||
</Setter>
|
</Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Grid.PlacesItem">
|
||||||
|
<Setter Property="Background" Value="#01000000"/>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Grid.PlacesItem:pointerover">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource AppBackgroundColor}"/>
|
||||||
|
</Style>
|
||||||
</Application.Styles>
|
</Application.Styles>
|
||||||
</Application>
|
</Application>
|
||||||
|
|||||||
23
src/GuiApp/FileTime.Avalonia/Converters/IsEmptyConverter.cs
Normal file
23
src/GuiApp/FileTime.Avalonia/Converters/IsEmptyConverter.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using Avalonia.Data.Converters;
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Converters
|
||||||
|
{
|
||||||
|
public class IsEmptyConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public bool Inverse { get; set; }
|
||||||
|
|
||||||
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
var result = value is string s && string.IsNullOrWhiteSpace(s);
|
||||||
|
if (Inverse) result = !result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,26 +5,45 @@ using Avalonia.Svg.Skia;
|
|||||||
using FileTime.Avalonia.IconProviders;
|
using FileTime.Avalonia.IconProviders;
|
||||||
using FileTime.Avalonia.ViewModels;
|
using FileTime.Avalonia.ViewModels;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace FileTime.Avalonia.Converters
|
namespace FileTime.Avalonia.Converters
|
||||||
{
|
{
|
||||||
public class ItemToImageConverter : IValueConverter
|
public class ItemToImageConverter : IValueConverter
|
||||||
{
|
{
|
||||||
|
private readonly IIconProvider _iconProvider;
|
||||||
|
|
||||||
|
public ItemToImageConverter()
|
||||||
|
{
|
||||||
|
_iconProvider = App.ServiceProvider.GetService<IIconProvider>()!;
|
||||||
|
}
|
||||||
|
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
if (value == null) return null;
|
if (value == null) return null;
|
||||||
|
|
||||||
IIconProvider converter = new MaterialIconProvider();
|
|
||||||
|
|
||||||
IItem item = value switch
|
IItem item = value switch
|
||||||
{
|
{
|
||||||
ContainerViewModel container => container.Container,
|
ContainerViewModel container => container.Container,
|
||||||
ElementViewModel element => element.Element,
|
ElementViewModel element => element.Element,
|
||||||
|
IItem i => i,
|
||||||
_ => throw new NotImplementedException()
|
_ => throw new NotImplementedException()
|
||||||
};
|
};
|
||||||
|
|
||||||
var path = converter.GetImage(item)!;
|
SvgSource? source;
|
||||||
var source = SvgSource.Load<SvgSource>("avares://FileTime.Avalonia" + path, null);
|
var path = _iconProvider.GetImage(item)!;
|
||||||
|
if (path.Type == Models.ImagePathType.Absolute)
|
||||||
|
{
|
||||||
|
source = SvgSource.Load<SvgSource>(path.Path!, null);
|
||||||
|
}
|
||||||
|
else if(path.Type == Models.ImagePathType.Raw)
|
||||||
|
{
|
||||||
|
return path.Image;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
source = SvgSource.Load<SvgSource>("avares://FileTime.Avalonia" + path.Path, null);
|
||||||
|
}
|
||||||
return new SvgImage { Source = source };
|
return new SvgImage { Source = source };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,16 +11,17 @@
|
|||||||
<None Remove=".gitignore" />
|
<None Remove=".gitignore" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="0.10.11" />
|
<PackageReference Include="Avalonia" Version="0.10.12" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.11" />
|
<PackageReference Include="Avalonia.Desktop" Version="0.10.12" />
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.11" />
|
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.12" />
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.11" />
|
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.12" />
|
||||||
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.11.1" />
|
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.12" />
|
||||||
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.11.5" />
|
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.12" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
|
||||||
<PackageReference Include="MvvmGen" Version="1.1.2" />
|
<PackageReference Include="MvvmGen" Version="1.1.2" />
|
||||||
|
<PackageReference Include="Syroot.Windows.IO.KnownFolders" Version="1.2.3" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\AppCommon\FileTime.App.Core\FileTime.App.Core.csproj" />
|
<ProjectReference Include="..\..\AppCommon\FileTime.App.Core\FileTime.App.Core.csproj" />
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
using FileTime.Avalonia.Models;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.Avalonia.IconProviders
|
namespace FileTime.Avalonia.IconProviders
|
||||||
{
|
{
|
||||||
public interface IIconProvider
|
public interface IIconProvider
|
||||||
{
|
{
|
||||||
string GetImage(IItem item);
|
ImagePath GetImage(IItem item);
|
||||||
|
bool EnableAdvancedIcons { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,23 +1,30 @@
|
|||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using FileTime.Avalonia.Misc;
|
||||||
|
using FileTime.Avalonia.Models;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Providers.Local;
|
using FileTime.Providers.Local;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace FileTime.Avalonia.IconProviders
|
namespace FileTime.Avalonia.IconProviders
|
||||||
{
|
{
|
||||||
public class MaterialIconProvider : IIconProvider
|
public class MaterialIconProvider : IIconProvider
|
||||||
{
|
{
|
||||||
public string GetImage(IItem item)
|
public bool EnableAdvancedIcons { get; set; } = true;
|
||||||
|
|
||||||
|
public ImagePath GetImage(IItem item)
|
||||||
{
|
{
|
||||||
var icon = "file.svg";
|
var icon = item is IContainer ? "folder.svg" : "file.svg";
|
||||||
if (item is IContainer)
|
|
||||||
|
if (EnableAdvancedIcons)
|
||||||
{
|
{
|
||||||
icon = "folder.svg";
|
if (item is IElement element)
|
||||||
}
|
|
||||||
else if (item is IElement element)
|
|
||||||
{
|
{
|
||||||
if(element is LocalFile localFile && element.FullName.EndsWith(".svg"))
|
if (element is LocalFile localFile && (element.FullName?.EndsWith(".svg") ?? false))
|
||||||
{
|
{
|
||||||
return localFile.File.FullName;
|
return new ImagePath(ImagePathType.Absolute, localFile.File.FullName);
|
||||||
}
|
}
|
||||||
icon = !element.Name.Contains('.')
|
icon = !element.Name.Contains('.')
|
||||||
? icon
|
? icon
|
||||||
@@ -27,7 +34,42 @@ namespace FileTime.Avalonia.IconProviders
|
|||||||
_ => icon
|
_ => icon
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return "/Assets/material/" + icon;
|
/*else if (item is LocalFolder folder && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
var file = new FileInfo(Path.Combine(folder.FullName, "desktop.ini"));
|
||||||
|
if (file.Exists)
|
||||||
|
{
|
||||||
|
var lines = File.ReadAllLines(file.FullName);
|
||||||
|
if (Array.Find(lines, l => l.StartsWith("iconresource", StringComparison.OrdinalIgnoreCase)) is string iconLine)
|
||||||
|
{
|
||||||
|
var nameLineValue = string.Join('=', iconLine.Split('=')[1..]);
|
||||||
|
var environemntVariables = Environment.GetEnvironmentVariables();
|
||||||
|
foreach (var keyo in environemntVariables.Keys)
|
||||||
|
{
|
||||||
|
if (keyo is string key && environemntVariables[key] is string value)
|
||||||
|
{
|
||||||
|
nameLineValue = nameLineValue.Replace($"%{key}%", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var parts = nameLineValue.Split(',');
|
||||||
|
if (parts.Length >= 2 && long.TryParse(parts[^1], out var parsedResourceId))
|
||||||
|
{
|
||||||
|
if (parsedResourceId < 0) parsedResourceId *= -1;
|
||||||
|
|
||||||
|
var extractedIcon = NativeMethodHelpers.GetIconResource(string.Join(',', parts[..^1]), (uint)parsedResourceId);
|
||||||
|
|
||||||
|
var extractedIconAsStream = new MemoryStream();
|
||||||
|
extractedIcon.Save(extractedIconAsStream);
|
||||||
|
extractedIconAsStream.Position = 0;
|
||||||
|
|
||||||
|
return new ImagePath(ImagePathType.Raw, new Bitmap(extractedIconAsStream));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
return new ImagePath(ImagePathType.Asset, "/Assets/material/" + icon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System.IO;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using FileTime.Avalonia.Misc;
|
||||||
|
using FileTime.Avalonia.Models;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Providers.Local;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.IconProviders
|
||||||
|
{
|
||||||
|
public class SystemIconProvider : IIconProvider
|
||||||
|
{
|
||||||
|
public bool EnableAdvancedIcons { get; set; }
|
||||||
|
|
||||||
|
public ImagePath GetImage(IItem item)
|
||||||
|
{
|
||||||
|
if (item is LocalFile file)
|
||||||
|
{
|
||||||
|
var extractedIconAsStream = new MemoryStream();
|
||||||
|
var extractedIcon = System.Drawing.Icon.ExtractAssociatedIcon(file.File.FullName);
|
||||||
|
extractedIcon.Save(extractedIconAsStream);
|
||||||
|
extractedIconAsStream.Position = 0;
|
||||||
|
return new ImagePath(ImagePathType.Raw, new Bitmap(extractedIconAsStream));
|
||||||
|
}
|
||||||
|
|
||||||
|
var icon = item is IContainer ? "folder.svg" : "file.svg";
|
||||||
|
return new ImagePath(ImagePathType.Asset, "/Assets/material/" + icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
73
src/GuiApp/FileTime.Avalonia/Misc/WindowsNativeMethods.cs
Normal file
73
src/GuiApp/FileTime.Avalonia/Misc/WindowsNativeMethods.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using System;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Misc
|
||||||
|
{
|
||||||
|
public static class WindowsNativeMethods
|
||||||
|
{
|
||||||
|
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||||
|
internal static extern IntPtr LoadLibrary(string lpLibFileName);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||||
|
internal static extern int LoadString(IntPtr hInstance, uint wID, StringBuilder lpBuffer, int nBufferMax);
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
public static extern IntPtr LoadIcon(IntPtr hInstance, IntPtr lpIconName);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
public static extern int FreeLibrary(IntPtr hLibModule);
|
||||||
|
|
||||||
|
[DllImport("shell32.dll")]
|
||||||
|
public static extern IntPtr ExtractAssociatedIcon(IntPtr hInst, StringBuilder lpIconPath, out ushort lpiIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class NativeMethodHelpers
|
||||||
|
{
|
||||||
|
public static string GetStringResource(string fileName, uint resourceId)
|
||||||
|
{
|
||||||
|
IntPtr? handle = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handle = WindowsNativeMethods.LoadLibrary(fileName);
|
||||||
|
StringBuilder buffer = new(8192); //Buffer for output from LoadString()
|
||||||
|
int length = WindowsNativeMethods.LoadString(handle.Value, resourceId, buffer, buffer.Capacity);
|
||||||
|
return buffer.ToString(0, length); //Return the part of the buffer that was used.
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (handle is IntPtr validHandle)
|
||||||
|
{
|
||||||
|
WindowsNativeMethods.FreeLibrary(validHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Icon GetIconResource(string fileName, uint resourceId)
|
||||||
|
{
|
||||||
|
IntPtr? handle = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
handle = WindowsNativeMethods.LoadLibrary(fileName);
|
||||||
|
IntPtr handle2 = WindowsNativeMethods.LoadIcon(handle.Value, new IntPtr(resourceId));
|
||||||
|
return Icon.FromHandle(handle2);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (handle is IntPtr validHandle)
|
||||||
|
{
|
||||||
|
WindowsNativeMethods.FreeLibrary(validHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*public static Icon GetAssociatedIcon()
|
||||||
|
{
|
||||||
|
ushort uicon;
|
||||||
|
StringBuilder strB = new StringBuilder(fileName);
|
||||||
|
IntPtr handle = WindowsNativeMethods.ExtractAssociatedIcon(this.Handle, strB, out uicon);
|
||||||
|
return Icon.FromHandle(handle);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/GuiApp/FileTime.Avalonia/Models/ImagePath.cs
Normal file
21
src/GuiApp/FileTime.Avalonia/Models/ImagePath.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
namespace FileTime.Avalonia.Models
|
||||||
|
{
|
||||||
|
public class ImagePath
|
||||||
|
{
|
||||||
|
public string? Path { get; }
|
||||||
|
public ImagePathType Type { get; }
|
||||||
|
public object? Image { get; }
|
||||||
|
|
||||||
|
public ImagePath(ImagePathType type, string path)
|
||||||
|
{
|
||||||
|
Path = path;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImagePath(ImagePathType type, object image)
|
||||||
|
{
|
||||||
|
Image = image;
|
||||||
|
Type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/GuiApp/FileTime.Avalonia/Models/ImagePathType.cs
Normal file
9
src/GuiApp/FileTime.Avalonia/Models/ImagePathType.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace FileTime.Avalonia.Models
|
||||||
|
{
|
||||||
|
public enum ImagePathType
|
||||||
|
{
|
||||||
|
Asset,
|
||||||
|
Absolute,
|
||||||
|
Raw
|
||||||
|
}
|
||||||
|
}
|
||||||
16
src/GuiApp/FileTime.Avalonia/Models/PlaceInfo.cs
Normal file
16
src/GuiApp/FileTime.Avalonia/Models/PlaceInfo.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Models
|
||||||
|
{
|
||||||
|
public class PlaceInfo
|
||||||
|
{
|
||||||
|
public string Name { get; }
|
||||||
|
public IContainer Container { get; }
|
||||||
|
|
||||||
|
public PlaceInfo(string name, IContainer container)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Container = container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,9 @@ namespace FileTime.Avalonia.Models
|
|||||||
[Property]
|
[Property]
|
||||||
private string _fullName;
|
private string _fullName;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private string _label;
|
||||||
|
|
||||||
[Property]
|
[Property]
|
||||||
private long _size;
|
private long _size;
|
||||||
|
|
||||||
@@ -37,11 +40,17 @@ namespace FileTime.Avalonia.Models
|
|||||||
_driveInfo = driveInfo;
|
_driveInfo = driveInfo;
|
||||||
_container = container;
|
_container = container;
|
||||||
|
|
||||||
Name = container.Name;
|
Refresh();
|
||||||
FullName = container.FullName;
|
}
|
||||||
Size = driveInfo.TotalSize;
|
|
||||||
Free = driveInfo.AvailableFreeSpace;
|
private void Refresh()
|
||||||
Used = driveInfo.TotalSize - driveInfo.AvailableFreeSpace;
|
{
|
||||||
|
Name = _container.Name;
|
||||||
|
FullName = _container.FullName;
|
||||||
|
Label = _driveInfo.VolumeLabel;
|
||||||
|
Size = _driveInfo.TotalSize;
|
||||||
|
Free = _driveInfo.AvailableFreeSpace;
|
||||||
|
Used = _driveInfo.TotalSize - _driveInfo.AvailableFreeSpace;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using System.Collections.Generic;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using FileTime.Avalonia.Misc;
|
||||||
|
|
||||||
#pragma warning disable CA1416
|
#pragma warning disable CA1416
|
||||||
namespace FileTime.Avalonia.Services
|
namespace FileTime.Avalonia.Services
|
||||||
@@ -50,7 +51,7 @@ namespace FileTime.Avalonia.Services
|
|||||||
{
|
{
|
||||||
if (parsedResourceId < 0) parsedResourceId *= -1;
|
if (parsedResourceId < 0) parsedResourceId *= -1;
|
||||||
|
|
||||||
text = GetStringResource(parts[0], (uint)parsedResourceId);
|
text = NativeMethodHelpers.GetStringResource(string.Join(',', parts[..^1]), (uint)parsedResourceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -231,37 +232,6 @@ namespace FileTime.Avalonia.Services
|
|||||||
|
|
||||||
return (resultX, resultY);
|
return (resultX, resultY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string GetStringResource(string fileName, uint resourceId)
|
|
||||||
{
|
|
||||||
IntPtr? handle = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
handle = NativeMethods.LoadLibrary(fileName);
|
|
||||||
StringBuilder buffer = new(8192); //Buffer for output from LoadString()
|
|
||||||
int length = NativeMethods.LoadString(handle.Value, resourceId, buffer, buffer.Capacity);
|
|
||||||
return buffer.ToString(0, length); //Return the part of the buffer that was used.
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (handle is IntPtr validHandle)
|
|
||||||
{
|
|
||||||
NativeMethods.FreeLibrary(validHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class NativeMethods
|
|
||||||
{
|
|
||||||
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
|
||||||
internal static extern IntPtr LoadLibrary(string lpLibFileName);
|
|
||||||
|
|
||||||
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
|
||||||
internal static extern int LoadString(IntPtr hInstance, uint wID, StringBuilder lpBuffer, int nBufferMax);
|
|
||||||
|
|
||||||
[DllImport("kernel32.dll")]
|
|
||||||
public static extern int FreeLibrary(IntPtr hLibModule);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#pragma warning restore CA1416
|
#pragma warning restore CA1416
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using FileTime.Avalonia.Application;
|
using FileTime.Avalonia.Application;
|
||||||
|
using FileTime.Avalonia.IconProviders;
|
||||||
using FileTime.Avalonia.Services;
|
using FileTime.Avalonia.Services;
|
||||||
using FileTime.Avalonia.ViewModels;
|
using FileTime.Avalonia.ViewModels;
|
||||||
using FileTime.Core.Command;
|
using FileTime.Core.Command;
|
||||||
@@ -21,7 +22,8 @@ namespace FileTime.Avalonia
|
|||||||
{
|
{
|
||||||
serviceCollection = serviceCollection
|
serviceCollection = serviceCollection
|
||||||
.AddLogging()
|
.AddLogging()
|
||||||
.AddSingleton<ItemNameConverterService>();
|
.AddSingleton<ItemNameConverterService>()
|
||||||
|
.AddSingleton<IIconProvider, MaterialIconProvider>();
|
||||||
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private bool _isRefreshing;
|
private bool _isRefreshing;
|
||||||
private bool _isInitialized;
|
private bool _isInitialized;
|
||||||
private INewItemProcessor _newItemProcessor;
|
private readonly INewItemProcessor _newItemProcessor;
|
||||||
|
|
||||||
[Property]
|
[Property]
|
||||||
private IContainer _container;
|
private IContainer _container;
|
||||||
@@ -37,17 +37,19 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
[Property]
|
[Property]
|
||||||
private ContainerViewModel? _parent;
|
private ContainerViewModel? _parent;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private List<Exception> _exceptions;
|
||||||
|
|
||||||
public IItem Item => _container;
|
public IItem Item => _container;
|
||||||
|
|
||||||
private readonly ObservableCollection<ContainerViewModel> _containers = new ObservableCollection<ContainerViewModel>();
|
private ObservableCollection<ContainerViewModel> _containers = new();
|
||||||
|
|
||||||
private readonly ObservableCollection<ElementViewModel> _elements = new ObservableCollection<ElementViewModel>();
|
private ObservableCollection<ElementViewModel> _elements = new();
|
||||||
|
|
||||||
private readonly ObservableCollection<IItemViewModel> _items = new ObservableCollection<IItemViewModel>();
|
private ObservableCollection<IItemViewModel> _items = new();
|
||||||
|
|
||||||
public List<IItemViewModel> ChildrenToAdopt { get; } = new List<IItemViewModel>();
|
public List<IItemViewModel> ChildrenToAdopt { get; } = new List<IItemViewModel>();
|
||||||
|
|
||||||
|
|
||||||
[PropertyInvalidate(nameof(IsSelected))]
|
[PropertyInvalidate(nameof(IsSelected))]
|
||||||
[PropertyInvalidate(nameof(IsAlternative))]
|
[PropertyInvalidate(nameof(IsAlternative))]
|
||||||
[PropertyInvalidate(nameof(IsMarked))]
|
[PropertyInvalidate(nameof(IsMarked))]
|
||||||
@@ -64,7 +66,7 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
|
|
||||||
public List<ItemNamePart> DisplayName => ItemNameConverterService.GetDisplayName(this);
|
public List<ItemNamePart> DisplayName => ItemNameConverterService.GetDisplayName(this);
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete($"This property is for databinding only, use {nameof(GetContainers)} method instead.")]
|
||||||
public ObservableCollection<ContainerViewModel> Containers
|
public ObservableCollection<ContainerViewModel> Containers
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -72,9 +74,17 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
if (!_isInitialized) Task.Run(Refresh);
|
if (!_isInitialized) Task.Run(Refresh);
|
||||||
return _containers;
|
return _containers;
|
||||||
}
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _containers)
|
||||||
|
{
|
||||||
|
_containers = value;
|
||||||
|
OnPropertyChanged(nameof(Containers));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete]
|
[Obsolete($"This property is for databinding only, use {nameof(GetElements)} method instead.")]
|
||||||
public ObservableCollection<ElementViewModel> Elements
|
public ObservableCollection<ElementViewModel> Elements
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -82,9 +92,16 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
if (!_isInitialized) Task.Run(Refresh);
|
if (!_isInitialized) Task.Run(Refresh);
|
||||||
return _elements;
|
return _elements;
|
||||||
}
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _elements)
|
||||||
|
{
|
||||||
|
_elements = value;
|
||||||
|
OnPropertyChanged(nameof(Elements));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
[Obsolete]
|
}
|
||||||
|
[Obsolete($"This property is for databinding only, use {nameof(GetItems)} method instead.")]
|
||||||
public ObservableCollection<IItemViewModel> Items
|
public ObservableCollection<IItemViewModel> Items
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -92,6 +109,14 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
if (!_isInitialized) Task.Run(Refresh);
|
if (!_isInitialized) Task.Run(Refresh);
|
||||||
return _items;
|
return _items;
|
||||||
}
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != _items)
|
||||||
|
{
|
||||||
|
_items = value;
|
||||||
|
OnPropertyChanged(nameof(Items));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContainerViewModel(INewItemProcessor newItemProcessor, ContainerViewModel? parent, IContainer container, ItemNameConverterService itemNameConverterService) : this(itemNameConverterService)
|
public ContainerViewModel(INewItemProcessor newItemProcessor, ContainerViewModel? parent, IContainer container, ItemNameConverterService itemNameConverterService) : this(itemNameConverterService)
|
||||||
@@ -125,44 +150,41 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
|
|
||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
|
|
||||||
|
Exceptions = new List<Exception>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_isRefreshing = true;
|
_isRefreshing = true;
|
||||||
|
|
||||||
var containers = (await _container.GetContainers())!.Select(c => AdoptOrReuseOrCreateItem(c, (c2) => new ContainerViewModel(_newItemProcessor, this, c2, ItemNameConverterService))).ToList();
|
var containers = (await _container.GetContainers())!.Select(c => AdoptOrReuseOrCreateItem(c, (c2) => new ContainerViewModel(_newItemProcessor, this, c2, ItemNameConverterService))).ToList();
|
||||||
var elements = (await _container.GetElements())!.Select(e => AdoptOrReuseOrCreateItem(e, (e2) => new ElementViewModel(e2, this, ItemNameConverterService))).ToList();
|
var elements = (await _container.GetElements())!.Select(e => AdoptOrReuseOrCreateItem(e, (e2) => new ElementViewModel(e2, this, ItemNameConverterService))).ToList();
|
||||||
|
Exceptions = new List<Exception>(_container.Exceptions);
|
||||||
|
|
||||||
var containersToRemove = _containers.Except(containers);
|
foreach (var containerToRemove in _containers.Except(containers))
|
||||||
|
|
||||||
_containers.Clear();
|
|
||||||
_elements.Clear();
|
|
||||||
_items.Clear();
|
|
||||||
|
|
||||||
foreach (var containerToRemove in containersToRemove)
|
|
||||||
{
|
{
|
||||||
containerToRemove?.Dispose();
|
containerToRemove?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (initializeChildren)
|
||||||
|
{
|
||||||
foreach (var container in containers)
|
foreach (var container in containers)
|
||||||
{
|
{
|
||||||
if (initializeChildren) await container.Init(false);
|
await container.Init(false);
|
||||||
|
|
||||||
_containers.Add(container);
|
|
||||||
_items.Add(container);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var element in elements)
|
|
||||||
{
|
|
||||||
_elements.Add(element);
|
|
||||||
_items.Add(element);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < _items.Count; i++)
|
for (var i = 0; i < _items.Count; i++)
|
||||||
{
|
{
|
||||||
_items[i].IsAlternative = i % 2 == 1;
|
_items[i].IsAlternative = i % 2 == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Containers = new ObservableCollection<ContainerViewModel>(containers);
|
||||||
|
Elements = new ObservableCollection<ElementViewModel>(elements);
|
||||||
|
Items = new ObservableCollection<IItemViewModel>(containers.Cast<IItemViewModel>().Concat(elements));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_exceptions.Add(e);
|
||||||
}
|
}
|
||||||
catch { }
|
|
||||||
|
|
||||||
await _newItemProcessor.UpdateMarkedItems(this);
|
await _newItemProcessor.UpdateMarkedItems(this);
|
||||||
|
|
||||||
@@ -193,9 +215,9 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_containers.Clear();
|
_containers = new ObservableCollection<ContainerViewModel>();
|
||||||
_elements.Clear();
|
_elements = new ObservableCollection<ElementViewModel>();
|
||||||
_items.Clear();
|
_items = new ObservableCollection<IItemViewModel>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<ObservableCollection<ContainerViewModel>> GetContainers()
|
public async Task<ObservableCollection<ContainerViewModel>> GetContainers()
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
using FileTime.Core.Command;
|
using FileTime.Core.Command;
|
||||||
using FileTime.Core.Timeline;
|
using FileTime.Core.Timeline;
|
||||||
using FileTime.Core.Providers;
|
using FileTime.Core.Providers;
|
||||||
|
using Syroot.Windows.IO;
|
||||||
|
using FileTime.Avalonia.IconProviders;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
|
||||||
namespace FileTime.Avalonia.ViewModels
|
namespace FileTime.Avalonia.ViewModels
|
||||||
{
|
{
|
||||||
@@ -42,6 +45,8 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
private IClipboard _clipboard;
|
private IClipboard _clipboard;
|
||||||
private TimeRunner _timeRunner;
|
private TimeRunner _timeRunner;
|
||||||
private IEnumerable<IContentProvider> _contentProviders;
|
private IEnumerable<IContentProvider> _contentProviders;
|
||||||
|
private IIconProvider _iconProvider;
|
||||||
|
|
||||||
private Func<Task>? _inputHandler;
|
private Func<Task>? _inputHandler;
|
||||||
|
|
||||||
[Property]
|
[Property]
|
||||||
@@ -59,9 +64,15 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
[Property]
|
[Property]
|
||||||
private List<RootDriveInfo> _rootDriveInfos;
|
private List<RootDriveInfo> _rootDriveInfos;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private List<PlaceInfo> _places;
|
||||||
|
|
||||||
[Property]
|
[Property]
|
||||||
private string _messageBoxText;
|
private string _messageBoxText;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private ObservableCollection<string> _popupTexts = new ObservableCollection<string>();
|
||||||
|
|
||||||
public IReadOnlyList<ReadOnlyParallelCommands> TimelineCommands => _timeRunner.ParallelCommands;
|
public IReadOnlyList<ReadOnlyParallelCommands> TimelineCommands => _timeRunner.ParallelCommands;
|
||||||
|
|
||||||
async partial void OnInitialize()
|
async partial void OnInitialize()
|
||||||
@@ -69,8 +80,9 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
_clipboard = App.ServiceProvider.GetService<IClipboard>()!;
|
_clipboard = App.ServiceProvider.GetService<IClipboard>()!;
|
||||||
_timeRunner = App.ServiceProvider.GetService<TimeRunner>()!;
|
_timeRunner = App.ServiceProvider.GetService<TimeRunner>()!;
|
||||||
_contentProviders = App.ServiceProvider.GetService<IEnumerable<IContentProvider>>()!;
|
_contentProviders = App.ServiceProvider.GetService<IEnumerable<IContentProvider>>()!;
|
||||||
|
_iconProvider = App.ServiceProvider.GetService<IIconProvider>()!;
|
||||||
var inputInterface = (BasicInputHandler)App.ServiceProvider.GetService<IInputInterface>()!;
|
var inputInterface = (BasicInputHandler)App.ServiceProvider.GetService<IInputInterface>()!;
|
||||||
inputInterface.InputHandler = ReadInputs2;
|
inputInterface.InputHandler = ReadInputs;
|
||||||
App.ServiceProvider.GetService<TopContainer>();
|
App.ServiceProvider.GetService<TopContainer>();
|
||||||
|
|
||||||
_timeRunner.CommandsChanged += (o, e) => OnPropertyChanged(nameof(TimelineCommands));
|
_timeRunner.CommandsChanged += (o, e) => OnPropertyChanged(nameof(TimelineCommands));
|
||||||
@@ -103,8 +115,68 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
driveInfos.Add(driveInfo);
|
driveInfos.Add(driveInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RootDriveInfos = driveInfos.OrderBy(d => d.Name).ToList();
|
RootDriveInfos = driveInfos.OrderBy(d => d.Name).ToList();
|
||||||
|
|
||||||
|
var places = new List<PlaceInfo>();
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
{
|
||||||
|
var placesFolders = new List<KnownFolder>()
|
||||||
|
{
|
||||||
|
KnownFolders.Profile,
|
||||||
|
KnownFolders.Desktop,
|
||||||
|
KnownFolders.DocumentsLocalized,
|
||||||
|
KnownFolders.DownloadsLocalized,
|
||||||
|
KnownFolders.Music,
|
||||||
|
KnownFolders.Pictures,
|
||||||
|
KnownFolders.Videos,
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var placesFolder in placesFolders)
|
||||||
|
{
|
||||||
|
var possibleContainer = await LocalContentProvider.GetByPath(placesFolder.Path);
|
||||||
|
if (possibleContainer is IContainer container)
|
||||||
|
{
|
||||||
|
var name = container.Name;
|
||||||
|
if (await container.GetByPath("desktop.ini") is LocalFile element)
|
||||||
|
{
|
||||||
|
var lines = File.ReadAllLines(element.File.FullName);
|
||||||
|
if (Array.Find(lines, l => l.StartsWith("localizedresourcename", StringComparison.OrdinalIgnoreCase)) is string nameLine)
|
||||||
|
{
|
||||||
|
var nameLineValue = string.Join('=', nameLine.Split('=')[1..]);
|
||||||
|
var environemntVariables = Environment.GetEnvironmentVariables();
|
||||||
|
foreach (var keyo in environemntVariables.Keys)
|
||||||
|
{
|
||||||
|
if (keyo is string key && environemntVariables[key] is string value)
|
||||||
|
{
|
||||||
|
nameLineValue = nameLineValue.Replace($"%{key}%", value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameLineValue.StartsWith("@"))
|
||||||
|
{
|
||||||
|
var parts = nameLineValue[1..].Split(',');
|
||||||
|
if (parts.Length >= 2 && long.TryParse(parts[^1], out var parsedResourceId))
|
||||||
|
{
|
||||||
|
if (parsedResourceId < 0) parsedResourceId *= -1;
|
||||||
|
|
||||||
|
name = NativeMethodHelpers.GetStringResource(string.Join(',', parts[..^1]), (uint)parsedResourceId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
name = nameLineValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
places.Add(new PlaceInfo(name, container));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("TODO linux places");
|
||||||
|
}
|
||||||
|
Places = places;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IContainer?> GetContainerForWindowsDrive(DriveInfo drive)
|
private async Task<IContainer?> GetContainerForWindowsDrive(DriveInfo drive)
|
||||||
@@ -123,6 +195,12 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
await AppState.SelectedTab.Open();
|
await AppState.SelectedTab.Open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task OpenContainer(IContainer container)
|
||||||
|
{
|
||||||
|
AppState.RapidTravelText = "";
|
||||||
|
await AppState.SelectedTab.OpenContainer(container);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task OpenOrRun()
|
public async Task OpenOrRun()
|
||||||
{
|
{
|
||||||
if (AppState.SelectedTab.SelectedItem is ContainerViewModel)
|
if (AppState.SelectedTab.SelectedItem is ContainerViewModel)
|
||||||
@@ -530,6 +608,20 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task ToggleAdvancedIcons()
|
||||||
|
{
|
||||||
|
_iconProvider.EnableAdvancedIcons = !_iconProvider.EnableAdvancedIcons;
|
||||||
|
var text = "Advanced icons are: " + (_iconProvider.EnableAdvancedIcons ? "ON" : "OFF");
|
||||||
|
_popupTexts.Add(text);
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await Task.Delay(5000);
|
||||||
|
await Dispatcher.UIThread.InvokeAsync(() => _popupTexts.Remove(text));
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public async void ProcessInputs()
|
public async void ProcessInputs()
|
||||||
{
|
{
|
||||||
@@ -714,7 +806,7 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
_inputHandler = inputHandler;
|
_inputHandler = inputHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string?[]> ReadInputs2(IEnumerable<Core.Interactions.InputElement> fields)
|
public async Task<string?[]> ReadInputs(IEnumerable<Core.Interactions.InputElement> fields)
|
||||||
{
|
{
|
||||||
var waiting = true;
|
var waiting = true;
|
||||||
var result = new string[0];
|
var result = new string[0];
|
||||||
@@ -912,9 +1004,14 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
RefreshCurrentLocation),
|
RefreshCurrentLocation),
|
||||||
new CommandBinding(
|
new CommandBinding(
|
||||||
"go to",
|
"go to",
|
||||||
FileTime.App.Core.Command.Commands.Refresh,
|
FileTime.App.Core.Command.Commands.Dummy,
|
||||||
new KeyWithModifiers[]{new KeyWithModifiers(Key.L, ctrl: true)},
|
new KeyWithModifiers[]{new KeyWithModifiers(Key.L, ctrl: true)},
|
||||||
GoToContainer),
|
GoToContainer),
|
||||||
|
new CommandBinding(
|
||||||
|
"toggle advanced icons",
|
||||||
|
FileTime.App.Core.Command.Commands.Dummy,
|
||||||
|
new KeyWithModifiers[]{new KeyWithModifiers(Key.Z),new KeyWithModifiers(Key.I)},
|
||||||
|
ToggleAdvancedIcons),
|
||||||
};
|
};
|
||||||
var universalCommandBindings = new List<CommandBinding>()
|
var universalCommandBindings = new List<CommandBinding>()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|
||||||
<Grid Grid.Column="2" IsVisible="{Binding ShowAttributes,ElementName=ItemRoot}">
|
<Grid Grid.Column="2" IsVisible="{Binding ShowAttributes,ElementName=ItemRoot}">
|
||||||
<Grid ColumnDefinitions="180,40">
|
<Grid ColumnDefinitions="180,45">
|
||||||
<TextBlock Text="{Binding Item.CreatedAt}"/>
|
<TextBlock Text="{Binding Item.CreatedAt}"/>
|
||||||
<TextBlock Grid.Column="1" Text="{Binding Item.Attributes}"/>
|
<TextBlock Grid.Column="1" Text="{Binding Item.Attributes}"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
@@ -36,7 +35,6 @@
|
|||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="0,0,0,10"
|
Margin="0,0,0,10"
|
||||||
Classes="NormalText"
|
|
||||||
Text="Drives" />
|
Text="Drives" />
|
||||||
|
|
||||||
<ItemsRepeater
|
<ItemsRepeater
|
||||||
@@ -53,25 +51,35 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Source="{SvgImage /Assets/material/folder.svg}" />
|
Source="{SvgImage /Assets/material/folder.svg}" />
|
||||||
|
|
||||||
<TextBlock
|
<StackPanel
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Classes="NormalText"
|
Orientation="Horizontal">
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
VerticalAlignment="Center"
|
||||||
Text="{Binding FullName}" />
|
Text="{Binding FullName}" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Margin="5,0,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Classes="SmallText"
|
||||||
|
Text="{Binding Label}" IsVisible="{Binding Label,Converter={StaticResource IsNotEmptyConverter}}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
<StackPanel HorizontalAlignment="Right"
|
<StackPanel HorizontalAlignment="Right"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
VerticalAlignment="Center">
|
VerticalAlignment="Center">
|
||||||
|
|
||||||
<TextBlock Classes="SmallText" Text="{Binding Free, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}">
|
<TextBlock Classes="SmallText" VerticalAlignment="Center" Text="{Binding Free, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}">
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
<TextBlock Classes="SmallText" Text=" / ">
|
<TextBlock Classes="SmallText" VerticalAlignment="Center" Text=" / ">
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
<TextBlock Classes="SmallText" Text="{Binding Size, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}">
|
<TextBlock Classes="SmallText" VerticalAlignment="Center" Text="{Binding Size, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}">
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
@@ -79,8 +87,40 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Grid.ColumnSpan="2"
|
Grid.ColumnSpan="2"
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Maximum="{Binding Size}"
|
Maximum="100"
|
||||||
Value="{Binding Used}" />
|
Value="{Binding UsedPercentage}" />
|
||||||
|
</Grid>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsRepeater.ItemTemplate>
|
||||||
|
</ItemsRepeater>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Grid.Row="1" CornerRadius="10" Background="{DynamicResource ContainerBackgroundBrush}" Padding="0,10" Margin="10">
|
||||||
|
<Grid RowDefinitions="Auto,Auto">
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Margin="10,0,10,10"
|
||||||
|
Text="Places" />
|
||||||
|
|
||||||
|
<ItemsRepeater
|
||||||
|
Grid.Row="1"
|
||||||
|
Items="{Binding Places}">
|
||||||
|
<ItemsRepeater.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Grid Classes="PlacesItem" PointerPressed="OnPlacePointerPressed" 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>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsRepeater.ItemTemplate>
|
</ItemsRepeater.ItemTemplate>
|
||||||
@@ -234,15 +274,27 @@
|
|||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Items.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Name="ChildEmpty"
|
x:Name="ChildEmpty"
|
||||||
Margin="10"
|
Margin="10"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
Foreground="{DynamicResource ErrorBrush}"
|
Foreground="{DynamicResource ErrorBrush}"
|
||||||
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Items.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
|
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Exceptions, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
||||||
Empty
|
Empty
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
|
<ItemsRepeater Items="{Binding AppState.SelectedTab.ChildContainer.Exceptions}">
|
||||||
|
<ItemsRepeater.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsRepeater.ItemTemplate>
|
||||||
|
</ItemsRepeater>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
@@ -314,6 +366,28 @@
|
|||||||
Content="No" />
|
Content="No" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<ItemsRepeater Items="{Binding PopupTexts}" Margin="0,0,0,20" HorizontalAlignment="Center" VerticalAlignment="Bottom" IsVisible="{Binding PopupTexts.Count,Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
||||||
|
<ItemsRepeater.Styles>
|
||||||
|
<Style Selector="TextBlock">
|
||||||
|
<Style.Animations>
|
||||||
|
<Animation Duration="0:0:1">
|
||||||
|
<KeyFrame Cue="0%">
|
||||||
|
<Setter Property="Opacity" Value="0.0"/>
|
||||||
|
</KeyFrame>
|
||||||
|
<KeyFrame Cue="100%">
|
||||||
|
<Setter Property="Opacity" Value="1.0"/>
|
||||||
|
</KeyFrame>
|
||||||
|
</Animation>
|
||||||
|
</Style.Animations>
|
||||||
|
</Style>
|
||||||
|
</ItemsRepeater.Styles>
|
||||||
|
<ItemsRepeater.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<TextBlock Text="{Binding}" HorizontalAlignment="Center"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</ItemsRepeater.ItemTemplate>
|
||||||
|
</ItemsRepeater>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid Grid.Row="3">
|
<Grid Grid.Row="3">
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Avalonia.Input;
|
|||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using FileTime.Avalonia.Misc;
|
using FileTime.Avalonia.Misc;
|
||||||
|
using FileTime.Avalonia.Models;
|
||||||
using FileTime.Avalonia.ViewModels;
|
using FileTime.Avalonia.ViewModels;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@@ -86,12 +87,25 @@ namespace FileTime.Avalonia.Views
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InputText_AttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs args)
|
private void InputText_AttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is TextBox inputText && inputText.DataContext is InputElementWrapper inputElementWrapper && inputElementWrapper == ViewModel!.Inputs.First())
|
if (sender is TextBox inputText && inputText.DataContext is InputElementWrapper inputElementWrapper && inputElementWrapper == ViewModel!.Inputs.First())
|
||||||
{
|
{
|
||||||
inputText.Focus();
|
inputText.Focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnPlacePointerPressed(object sender, PointerPressedEventArgs e)
|
||||||
|
{
|
||||||
|
if(!e.Handled
|
||||||
|
&& ViewModel != null
|
||||||
|
&& e.GetCurrentPoint(this).Properties.IsLeftButtonPressed
|
||||||
|
&& sender is StyledElement control
|
||||||
|
&& control.DataContext is PlaceInfo placeInfo)
|
||||||
|
{
|
||||||
|
ViewModel.OpenContainer(placeInfo.Container).Wait();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,7 @@ namespace FileTime.Providers.Local
|
|||||||
public bool IsCaseInsensitive { get; }
|
public bool IsCaseInsensitive { get; }
|
||||||
public bool CanDelete => false;
|
public bool CanDelete => false;
|
||||||
public bool CanRename => false;
|
public bool CanRename => false;
|
||||||
|
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
|
||||||
|
|
||||||
public LocalContentProvider(ILogger<LocalContentProvider> logger)
|
public LocalContentProvider(ILogger<LocalContentProvider> logger)
|
||||||
{
|
{
|
||||||
@@ -93,5 +94,6 @@ namespace FileTime.Providers.Local
|
|||||||
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default) => Task.FromResult(_elements);
|
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default) => Task.FromResult(_elements);
|
||||||
|
|
||||||
public Task Rename(string newName) => throw new NotSupportedException();
|
public Task Rename(string newName) => throw new NotSupportedException();
|
||||||
|
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ namespace FileTime.Providers.Local
|
|||||||
private IReadOnlyList<IItem>? _items;
|
private IReadOnlyList<IItem>? _items;
|
||||||
private IReadOnlyList<IContainer>? _containers;
|
private IReadOnlyList<IContainer>? _containers;
|
||||||
private IReadOnlyList<IElement>? _elements;
|
private IReadOnlyList<IElement>? _elements;
|
||||||
|
private List<Exception> _exceptions;
|
||||||
private readonly IContainer? _parent;
|
private readonly IContainer? _parent;
|
||||||
|
|
||||||
public bool IsHidden => (Directory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
|
public bool IsHidden => (Directory.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
|
||||||
@@ -30,12 +31,16 @@ namespace FileTime.Providers.Local
|
|||||||
public string Attributes => GetAttributes();
|
public string Attributes => GetAttributes();
|
||||||
|
|
||||||
public DateTime CreatedAt => Directory.CreationTime;
|
public DateTime CreatedAt => Directory.CreationTime;
|
||||||
|
public IReadOnlyList<Exception> Exceptions { get; }
|
||||||
|
|
||||||
public LocalFolder(DirectoryInfo directory, LocalContentProvider contentProvider, IContainer? parent)
|
public LocalFolder(DirectoryInfo directory, LocalContentProvider contentProvider, IContainer? parent)
|
||||||
{
|
{
|
||||||
Directory = directory;
|
Directory = directory;
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
|
|
||||||
|
_exceptions = new List<Exception>();
|
||||||
|
Exceptions = _exceptions.AsReadOnly();
|
||||||
|
|
||||||
Name = directory.Name.TrimEnd(Path.DirectorySeparatorChar);
|
Name = directory.Name.TrimEnd(Path.DirectorySeparatorChar);
|
||||||
FullName = parent?.FullName == null ? Name : parent.FullName + Constants.SeparatorChar + Name;
|
FullName = parent?.FullName == null ? Name : parent.FullName + Constants.SeparatorChar + Name;
|
||||||
Provider = contentProvider;
|
Provider = contentProvider;
|
||||||
@@ -49,13 +54,17 @@ namespace FileTime.Providers.Local
|
|||||||
{
|
{
|
||||||
_containers = new List<IContainer>();
|
_containers = new List<IContainer>();
|
||||||
_elements = new List<IElement>();
|
_elements = new List<IElement>();
|
||||||
|
_exceptions.Clear();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_containers = Directory.GetDirectories().Select(d => new LocalFolder(d, Provider, this)).OrderBy(d => d.Name).ToList().AsReadOnly();
|
_containers = Directory.GetDirectories().Select(d => new LocalFolder(d, Provider, this)).OrderBy(d => d.Name).ToList().AsReadOnly();
|
||||||
_elements = Directory.GetFiles().Select(f => new LocalFile(f, this, Provider)).OrderBy(f => f.Name).ToList().AsReadOnly();
|
_elements = Directory.GetFiles().Select(f => new LocalFile(f, this, Provider)).OrderBy(f => f.Name).ToList().AsReadOnly();
|
||||||
}
|
}
|
||||||
catch { }
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_exceptions.Add(e);
|
||||||
|
}
|
||||||
|
|
||||||
_items = _containers.Cast<IItem>().Concat(_elements).ToList().AsReadOnly();
|
_items = _containers.Cast<IItem>().Concat(_elements).ToList().AsReadOnly();
|
||||||
Refreshed?.InvokeAsync(this, AsyncEventArgs.Empty);
|
Refreshed?.InvokeAsync(this, AsyncEventArgs.Empty);
|
||||||
@@ -144,5 +153,6 @@ namespace FileTime.Providers.Local
|
|||||||
+ ((Directory.Attributes & FileAttributes.System) == FileAttributes.System ? "s" : "-");
|
+ ((Directory.Attributes & FileAttributes.System) == FileAttributes.System ? "s" : "-");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -25,6 +25,7 @@ namespace FileTime.Providers.Smb
|
|||||||
public IContentProvider Provider => this;
|
public IContentProvider Provider => this;
|
||||||
public bool CanDelete => false;
|
public bool CanDelete => false;
|
||||||
public bool CanRename => false;
|
public bool CanRename => false;
|
||||||
|
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
|
||||||
|
|
||||||
public AsyncEventHandler Refreshed { get; } = new();
|
public AsyncEventHandler Refreshed { get; } = new();
|
||||||
|
|
||||||
@@ -98,5 +99,6 @@ namespace FileTime.Providers.Smb
|
|||||||
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default) => Task.FromResult(_elements);
|
public Task<IReadOnlyList<IElement>?> GetElements(CancellationToken token = default) => Task.FromResult(_elements);
|
||||||
|
|
||||||
public Task Rename(string newName) => throw new NotSupportedException();
|
public Task Rename(string newName) => throw new NotSupportedException();
|
||||||
|
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,7 @@ namespace FileTime.Providers.Smb
|
|||||||
public bool CanRename => true;
|
public bool CanRename => true;
|
||||||
|
|
||||||
public AsyncEventHandler Refreshed { get; } = new();
|
public AsyncEventHandler Refreshed { get; } = new();
|
||||||
|
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
|
||||||
|
|
||||||
public SmbFolder(string name, SmbContentProvider contentProvider, SmbShare smbShare, IContainer parent)
|
public SmbFolder(string name, SmbContentProvider contentProvider, SmbShare smbShare, IContainer parent)
|
||||||
{
|
{
|
||||||
@@ -119,5 +120,6 @@ namespace FileTime.Providers.Smb
|
|||||||
if (_elements == null) await Refresh();
|
if (_elements == null) await Refresh();
|
||||||
return _elements;
|
return _elements;
|
||||||
}
|
}
|
||||||
|
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,8 +32,9 @@ namespace FileTime.Providers.Smb
|
|||||||
public SmbContentProvider Provider { get; }
|
public SmbContentProvider Provider { get; }
|
||||||
|
|
||||||
IContentProvider IItem.Provider => Provider;
|
IContentProvider IItem.Provider => Provider;
|
||||||
public bool CanDelete => false;
|
public bool CanDelete => true;
|
||||||
public bool CanRename => false;
|
public bool CanRename => false;
|
||||||
|
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
|
||||||
|
|
||||||
public AsyncEventHandler Refreshed { get; } = new();
|
public AsyncEventHandler Refreshed { get; } = new();
|
||||||
|
|
||||||
@@ -186,5 +187,6 @@ namespace FileTime.Providers.Smb
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Task Rename(string newName) => throw new NotSupportedException();
|
public Task Rename(string newName) => throw new NotSupportedException();
|
||||||
|
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,6 +27,7 @@ namespace FileTime.Providers.Smb
|
|||||||
public bool CanRename => false;
|
public bool CanRename => false;
|
||||||
|
|
||||||
public AsyncEventHandler Refreshed { get; } = new();
|
public AsyncEventHandler Refreshed { get; } = new();
|
||||||
|
public IReadOnlyList<Exception> Exceptions { get; } = new List<Exception>().AsReadOnly();
|
||||||
|
|
||||||
public SmbShare(string name, SmbContentProvider contentProvider, IContainer parent, SmbClientContext smbClientContext)
|
public SmbShare(string name, SmbContentProvider contentProvider, IContainer parent, SmbClientContext smbClientContext)
|
||||||
{
|
{
|
||||||
@@ -156,5 +157,6 @@ namespace FileTime.Providers.Smb
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Task Rename(string newName) => throw new NotSupportedException();
|
public Task Rename(string newName) => throw new NotSupportedException();
|
||||||
|
public Task<bool> CanOpen() => Task.FromResult(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user