Exception text, Icons
This commit is contained in:
@@ -122,6 +122,7 @@
|
|||||||
<converters:IsNullConverter x:Key="IsNotNullConverter" Inverse="true"/>
|
<converters:IsNullConverter x:Key="IsNotNullConverter" Inverse="true"/>
|
||||||
<converters:IsEmptyConverter x:Key="IsEmptyConverter"/>
|
<converters:IsEmptyConverter x:Key="IsEmptyConverter"/>
|
||||||
<converters:IsEmptyConverter x:Key="IsNotEmptyConverter" Inverse="true"/>
|
<converters:IsEmptyConverter x:Key="IsNotEmptyConverter" Inverse="true"/>
|
||||||
|
<converters:ExceptionToStringConverter x:Key="ExceptionToStringConverter"/>
|
||||||
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace FileTime.Avalonia.Application
|
|||||||
_selectedItem = value;
|
_selectedItem = value;
|
||||||
|
|
||||||
OnPropertyChanged("SelectedItem");
|
OnPropertyChanged("SelectedItem");
|
||||||
SelectedItemChanged();
|
SelectedItemChanged().Wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,7 +152,7 @@ namespace FileTime.Avalonia.Application
|
|||||||
}
|
}
|
||||||
|
|
||||||
var items = await _currentLocation.GetItems();
|
var items = await _currentLocation.GetItems();
|
||||||
if (items != null && items.Count > 0)
|
if (items?.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var item in items)
|
foreach (var item in items)
|
||||||
{
|
{
|
||||||
@@ -206,7 +206,7 @@ namespace FileTime.Avalonia.Application
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void SelectedItemChanged()
|
private async Task SelectedItemChanged()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -215,6 +215,15 @@ namespace FileTime.Avalonia.Application
|
|||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task SetCurrentSelectedItem(IItem newItem)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Tab.SetCurrentSelectedItem(newItem);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
public async Task Open()
|
public async Task Open()
|
||||||
{
|
{
|
||||||
if (ChildContainer != null)
|
if (ChildContainer != null)
|
||||||
|
|||||||
3
src/GuiApp/FileTime.Avalonia/Assets/material/desktop.svg
Normal file
3
src/GuiApp/FileTime.Avalonia/Assets/material/desktop.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<svg style="width:24px;height:24px" viewBox="0 0 24 24">
|
||||||
|
<path fill="#448aff" d="M21,16H3V4H21M21,2H3C1.89,2 1,2.89 1,4V16A2,2 0 0,0 3,18H10V20H8V22H16V20H14V18H21A2,2 0 0,0 23,16V4C23,2.89 22.1,2 21,2Z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 217 B |
@@ -0,0 +1,3 @@
|
|||||||
|
<svg style="width:24px;height:24px" viewBox="0 0 24 24">
|
||||||
|
<path fill="#e57373" d="M10 4L12 6H20C21.1 6 22 6.89 22 8V18C22 19.1 21.1 20 20 20H4C2.89 20 2 19.1 2 18L2 6C2 4.89 2.89 4 4 4H10M19 9H15.5V13.06L15 13C13.9 13 13 13.9 13 15C13 16.11 13.9 17 15 17C16.11 17 17 16.11 17 15V11H19V9Z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 301 B |
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,6 +31,8 @@ namespace FileTime.Avalonia.Converters
|
|||||||
};
|
};
|
||||||
|
|
||||||
SvgSource? source;
|
SvgSource? source;
|
||||||
|
try
|
||||||
|
{
|
||||||
var path = _iconProvider.GetImage(item)!;
|
var path = _iconProvider.GetImage(item)!;
|
||||||
if (path.Type == Models.ImagePathType.Absolute)
|
if (path.Type == Models.ImagePathType.Absolute)
|
||||||
{
|
{
|
||||||
@@ -44,6 +46,11 @@ namespace FileTime.Avalonia.Converters
|
|||||||
{
|
{
|
||||||
source = SvgSource.Load<SvgSource>("avares://FileTime.Avalonia" + path.Path, null);
|
source = SvgSource.Load<SvgSource>("avares://FileTime.Avalonia" + path.Path, null);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
source = SvgSource.Load<SvgSource>("avares://FileTime.Avalonia/Assets/material/file.svg", null);
|
||||||
|
}
|
||||||
return new SvgImage { Source = source };
|
return new SvgImage { Source = source };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,50 @@
|
|||||||
using Avalonia.Media.Imaging;
|
|
||||||
using FileTime.Avalonia.Misc;
|
|
||||||
using FileTime.Avalonia.Models;
|
using FileTime.Avalonia.Models;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Providers.Local;
|
using FileTime.Providers.Local;
|
||||||
using System;
|
using Syroot.Windows.IO;
|
||||||
using System.IO;
|
using System.Collections.Generic;
|
||||||
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
|
||||||
{
|
{
|
||||||
|
private readonly List<SpecialPathWithIcon> _specialPaths = new();
|
||||||
public bool EnableAdvancedIcons { get; set; } = true;
|
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)
|
public ImagePath GetImage(IItem item)
|
||||||
{
|
{
|
||||||
var icon = item is IContainer ? "folder.svg" : "file.svg";
|
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 (EnableAdvancedIcons)
|
||||||
{
|
{
|
||||||
|
if (localPath != null && _specialPaths.Find(p => p.Path == localPath) is SpecialPathWithIcon specialPath)
|
||||||
|
{
|
||||||
|
return specialPath.IconPath;
|
||||||
|
}
|
||||||
|
|
||||||
if (item is IElement element)
|
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 = !element.Name.Contains('.')
|
||||||
? icon
|
? icon
|
||||||
@@ -34,42 +54,13 @@ namespace FileTime.Avalonia.IconProviders
|
|||||||
_ => icon
|
_ => 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);
|
|
||||||
}
|
}
|
||||||
|
return GetAssetPath(icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
var parts = nameLineValue.Split(',');
|
private static ImagePath GetAssetPath(string iconName)
|
||||||
if (parts.Length >= 2 && long.TryParse(parts[^1], out var parsedResourceId))
|
|
||||||
{
|
{
|
||||||
if (parsedResourceId < 0) parsedResourceId *= -1;
|
return new ImagePath(ImagePathType.Asset, "/Assets/material/" + iconName);
|
||||||
|
|
||||||
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,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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -780,7 +780,12 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
await AppState.SelectedTab.OpenContainer(newLocation);
|
await AppState.SelectedTab.OpenContainer(newLocation);
|
||||||
|
|
||||||
var selectedItemName = AppState.SelectedTab.SelectedItem?.Item.Name;
|
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();
|
await AppState.SelectedTab.MoveCursorToFirst();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,7 +260,7 @@
|
|||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
Fill="{DynamicResource ContentSeparatorBrush}" />
|
Fill="{DynamicResource ContentSeparatorBrush}" />
|
||||||
|
|
||||||
<Grid Grid.Column="4">
|
<Grid Grid.Column="4" IsVisible="{Binding AppState.SelectedTab.ChildContainer,Converter={StaticResource IsNotNullConverter}}">
|
||||||
<ListBox
|
<ListBox
|
||||||
Classes="ContentListView"
|
Classes="ContentListView"
|
||||||
IsEnabled="False"
|
IsEnabled="False"
|
||||||
@@ -283,20 +283,32 @@
|
|||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
FontWeight="Bold"
|
FontWeight="Bold"
|
||||||
Foreground="{DynamicResource ErrorBrush}"
|
Foreground="{DynamicResource ErrorBrush}"
|
||||||
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Exceptions, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Exceptions.Count, Converter={StaticResource EqualityConverter}, ConverterParameter=0}">
|
||||||
Empty
|
Empty
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
<ItemsRepeater Items="{Binding AppState.SelectedTab.ChildContainer.Exceptions}">
|
<Grid
|
||||||
|
RowDefinitions="Auto, Auto"
|
||||||
|
IsVisible="{Binding AppState.SelectedTab.ChildContainer.Exceptions.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Margin="0,0,0,10"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Text="There were some errors while opening container."
|
||||||
|
Foreground="{DynamicResource ErrorBrush}" />
|
||||||
|
|
||||||
|
<ItemsRepeater Grid.Row="1" Items="{Binding AppState.SelectedTab.ChildContainer.Exceptions}">
|
||||||
<ItemsRepeater.ItemTemplate>
|
<ItemsRepeater.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding}"/>
|
<TextBlock Text="{Binding, Converter={StaticResource ExceptionToStringConverter}}"/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsRepeater.ItemTemplate>
|
</ItemsRepeater.ItemTemplate>
|
||||||
</ItemsRepeater>
|
</ItemsRepeater>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
|
|||||||
Reference in New Issue
Block a user