diff --git a/src/GuiApp/FileTime.Avalonia/App.axaml b/src/GuiApp/FileTime.Avalonia/App.axaml
index a3122c3..4fce1de 100644
--- a/src/GuiApp/FileTime.Avalonia/App.axaml
+++ b/src/GuiApp/FileTime.Avalonia/App.axaml
@@ -122,6 +122,7 @@
+
diff --git a/src/GuiApp/FileTime.Avalonia/Application/TabContainer.cs b/src/GuiApp/FileTime.Avalonia/Application/TabContainer.cs
index ba06d62..ab76098 100644
--- a/src/GuiApp/FileTime.Avalonia/Application/TabContainer.cs
+++ b/src/GuiApp/FileTime.Avalonia/Application/TabContainer.cs
@@ -50,7 +50,7 @@ namespace FileTime.Avalonia.Application
_selectedItem = value;
OnPropertyChanged("SelectedItem");
- SelectedItemChanged();
+ SelectedItemChanged().Wait();
}
}
}
@@ -152,7 +152,7 @@ namespace FileTime.Avalonia.Application
}
var items = await _currentLocation.GetItems();
- if (items != null && items.Count > 0)
+ if (items?.Count > 0)
{
foreach (var item in items)
{
@@ -206,7 +206,7 @@ namespace FileTime.Avalonia.Application
}
}
- private async void SelectedItemChanged()
+ private async Task SelectedItemChanged()
{
try
{
@@ -215,6 +215,15 @@ namespace FileTime.Avalonia.Application
catch { }
}
+ public async Task SetCurrentSelectedItem(IItem newItem)
+ {
+ try
+ {
+ await Tab.SetCurrentSelectedItem(newItem);
+ }
+ catch { }
+ }
+
public async Task Open()
{
if (ChildContainer != null)
diff --git a/src/GuiApp/FileTime.Avalonia/Assets/material/desktop.svg b/src/GuiApp/FileTime.Avalonia/Assets/material/desktop.svg
new file mode 100644
index 0000000..5467d85
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/Assets/material/desktop.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Assets/material/folder-music.svg b/src/GuiApp/FileTime.Avalonia/Assets/material/folder-music.svg
new file mode 100644
index 0000000..8f4e952
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/Assets/material/folder-music.svg
@@ -0,0 +1,3 @@
+
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Converters/ExceptionToStringConverter.cs b/src/GuiApp/FileTime.Avalonia/Converters/ExceptionToStringConverter.cs
new file mode 100644
index 0000000..b1aeda9
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/Converters/ExceptionToStringConverter.cs
@@ -0,0 +1,23 @@
+using System;
+using System.Globalization;
+using Avalonia.Data.Converters;
+
+namespace FileTime.Avalonia.Converters
+{
+ public class ExceptionToStringConverter : IValueConverter
+ {
+ public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ if (value is not Exception e) return value;
+
+ if (e is UnauthorizedAccessException) return e.Message;
+
+ return $"{e.Message} ({e.GetType().FullName})";
+ }
+
+ public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Converters/ItemToImageConverter.cs b/src/GuiApp/FileTime.Avalonia/Converters/ItemToImageConverter.cs
index 9b9301a..21288f9 100644
--- a/src/GuiApp/FileTime.Avalonia/Converters/ItemToImageConverter.cs
+++ b/src/GuiApp/FileTime.Avalonia/Converters/ItemToImageConverter.cs
@@ -31,18 +31,25 @@ namespace FileTime.Avalonia.Converters
};
SvgSource? source;
- var path = _iconProvider.GetImage(item)!;
- if (path.Type == Models.ImagePathType.Absolute)
+ try
{
- source = SvgSource.Load(path.Path!, null);
+ var path = _iconProvider.GetImage(item)!;
+ if (path.Type == Models.ImagePathType.Absolute)
+ {
+ source = SvgSource.Load(path.Path!, null);
+ }
+ else if (path.Type == Models.ImagePathType.Raw)
+ {
+ return path.Image;
+ }
+ else
+ {
+ source = SvgSource.Load("avares://FileTime.Avalonia" + path.Path, null);
+ }
}
- else if(path.Type == Models.ImagePathType.Raw)
+ catch
{
- return path.Image;
- }
- else
- {
- source = SvgSource.Load("avares://FileTime.Avalonia" + path.Path, null);
+ source = SvgSource.Load("avares://FileTime.Avalonia/Assets/material/file.svg", null);
}
return new SvgImage { Source = source };
}
diff --git a/src/GuiApp/FileTime.Avalonia/IconProviders/MaterialIconProvider.cs b/src/GuiApp/FileTime.Avalonia/IconProviders/MaterialIconProvider.cs
index 6c2fdab..ef88a6a 100644
--- a/src/GuiApp/FileTime.Avalonia/IconProviders/MaterialIconProvider.cs
+++ b/src/GuiApp/FileTime.Avalonia/IconProviders/MaterialIconProvider.cs
@@ -1,30 +1,50 @@
-using Avalonia.Media.Imaging;
-using FileTime.Avalonia.Misc;
using FileTime.Avalonia.Models;
using FileTime.Core.Models;
using FileTime.Providers.Local;
-using System;
-using System.IO;
+using Syroot.Windows.IO;
+using System.Collections.Generic;
using System.Linq;
-using System.Runtime.InteropServices;
namespace FileTime.Avalonia.IconProviders
{
public class MaterialIconProvider : IIconProvider
{
+ private readonly List _specialPaths = new();
public bool EnableAdvancedIcons { get; set; } = true;
+ public MaterialIconProvider()
+ {
+ _specialPaths.Add(new SpecialPathWithIcon(KnownFolders.Desktop.Path, GetAssetPath("desktop.svg")));
+ _specialPaths.Add(new SpecialPathWithIcon(KnownFolders.Documents.Path, GetAssetPath("folder-resource.svg")));
+ _specialPaths.Add(new SpecialPathWithIcon(KnownFolders.DownloadsLocalized.Path, GetAssetPath("folder-download.svg")));
+ _specialPaths.Add(new SpecialPathWithIcon(KnownFolders.MusicLocalized.Path, GetAssetPath("folder-music.svg")));
+ _specialPaths.Add(new SpecialPathWithIcon(KnownFolders.Pictures.Path, GetAssetPath("folder-images.svg")));
+ _specialPaths.Add(new SpecialPathWithIcon(KnownFolders.Profile.Path, GetAssetPath("folder-home.svg")));
+ _specialPaths.Add(new SpecialPathWithIcon(KnownFolders.Videos.Path, GetAssetPath("folder-video.svg")));
+ }
+
public ImagePath GetImage(IItem item)
{
var icon = item is IContainer ? "folder.svg" : "file.svg";
+ string? localPath = item switch
+ {
+ LocalFolder folder => folder.Directory.FullName,
+ LocalFile file => file.File.FullName,
+ _ => null
+ };
if (EnableAdvancedIcons)
{
+ if (localPath != null && _specialPaths.Find(p => p.Path == localPath) is SpecialPathWithIcon specialPath)
+ {
+ return specialPath.IconPath;
+ }
+
if (item is IElement element)
{
- if (element is LocalFile localFile && (element.FullName?.EndsWith(".svg") ?? false))
+ if (element is LocalFile && (localPath?.EndsWith(".svg") ?? false))
{
- return new ImagePath(ImagePathType.Absolute, localFile.File.FullName);
+ return new ImagePath(ImagePathType.Absolute, localPath);
}
icon = !element.Name.Contains('.')
? icon
@@ -34,42 +54,13 @@ namespace FileTime.Avalonia.IconProviders
_ => 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);
+ return GetAssetPath(icon);
+ }
+
+ private static ImagePath GetAssetPath(string iconName)
+ {
+ return new ImagePath(ImagePathType.Asset, "/Assets/material/" + iconName);
}
}
}
diff --git a/src/GuiApp/FileTime.Avalonia/IconProviders/SpecialPathWithIcon.cs b/src/GuiApp/FileTime.Avalonia/IconProviders/SpecialPathWithIcon.cs
new file mode 100644
index 0000000..4f9702f
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/IconProviders/SpecialPathWithIcon.cs
@@ -0,0 +1,16 @@
+using FileTime.Avalonia.Models;
+
+namespace FileTime.Avalonia.IconProviders
+{
+ public class SpecialPathWithIcon
+ {
+ public string Path { get; }
+ public ImagePath IconPath { get; }
+
+ public SpecialPathWithIcon(string path, ImagePath iconPath)
+ {
+ Path = path;
+ IconPath = iconPath;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/IconProviders/WindowsSystemIconHelper.cs b/src/GuiApp/FileTime.Avalonia/IconProviders/WindowsSystemIconHelper.cs
new file mode 100644
index 0000000..aaafb11
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/IconProviders/WindowsSystemIconHelper.cs
@@ -0,0 +1,49 @@
+using System;
+using System.IO;
+using Avalonia.Media.Imaging;
+using FileTime.Avalonia.Misc;
+using FileTime.Avalonia.Models;
+using FileTime.Providers.Local;
+
+namespace FileTime.Avalonia.IconProviders
+{
+ public static class WindowsSystemIconHelper
+ {
+ public static ImagePath? GetImageByDesktopIni(LocalFolder folder)
+ {
+ 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 null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/ViewModels/MainPageViewModel.cs b/src/GuiApp/FileTime.Avalonia/ViewModels/MainPageViewModel.cs
index ace11db..b00c744 100644
--- a/src/GuiApp/FileTime.Avalonia/ViewModels/MainPageViewModel.cs
+++ b/src/GuiApp/FileTime.Avalonia/ViewModels/MainPageViewModel.cs
@@ -780,7 +780,12 @@ namespace FileTime.Avalonia.ViewModels
await AppState.SelectedTab.OpenContainer(newLocation);
var selectedItemName = AppState.SelectedTab.SelectedItem?.Item.Name;
- if (!(await AppState.SelectedTab.CurrentLocation.GetItems()).Select(i => i.Item.Name).Any(n => n == selectedItemName))
+ var currentLocationItems = await AppState.SelectedTab.CurrentLocation.GetItems();
+ if(currentLocationItems.FirstOrDefault(i => i.Item.Name.ToLower() == AppState.RapidTravelText.ToLower()) is IItemViewModel matchItem)
+ {
+ await AppState.SelectedTab.SetCurrentSelectedItem(matchItem.Item);
+ }
+ else if (!currentLocationItems.Select(i => i.Item.Name).Any(n => n == selectedItemName))
{
await AppState.SelectedTab.MoveCursorToFirst();
}
diff --git a/src/GuiApp/FileTime.Avalonia/Views/MainWindow.axaml b/src/GuiApp/FileTime.Avalonia/Views/MainWindow.axaml
index 4091fb0..bf4ae59 100644
--- a/src/GuiApp/FileTime.Avalonia/Views/MainWindow.axaml
+++ b/src/GuiApp/FileTime.Avalonia/Views/MainWindow.axaml
@@ -260,7 +260,7 @@
VerticalAlignment="Stretch"
Fill="{DynamicResource ContentSeparatorBrush}" />
-
+
+ IsVisible="{Binding AppState.SelectedTab.ChildContainer.Exceptions.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
Empty
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+