Exception text, Icons

This commit is contained in:
2022-02-02 13:29:51 +01:00
parent 3e553dd448
commit d795ddcd11
11 changed files with 183 additions and 64 deletions

View File

@@ -122,6 +122,7 @@
<converters:IsNullConverter x:Key="IsNotNullConverter" Inverse="true"/>
<converters:IsEmptyConverter x:Key="IsEmptyConverter"/>
<converters:IsEmptyConverter x:Key="IsNotEmptyConverter" Inverse="true"/>
<converters:ExceptionToStringConverter x:Key="ExceptionToStringConverter"/>
</ResourceDictionary>
</Application.Resources>

View File

@@ -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)

View 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

View File

@@ -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

View File

@@ -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();
}
}
}

View File

@@ -31,6 +31,8 @@ namespace FileTime.Avalonia.Converters
};
SvgSource? source;
try
{
var path = _iconProvider.GetImage(item)!;
if (path.Type == Models.ImagePathType.Absolute)
{
@@ -44,6 +46,11 @@ namespace FileTime.Avalonia.Converters
{
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 };
}

View File

@@ -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<SpecialPathWithIcon> _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);
}
return GetAssetPath(icon);
}
var parts = nameLineValue.Split(',');
if (parts.Length >= 2 && long.TryParse(parts[^1], out var parsedResourceId))
private static ImagePath GetAssetPath(string iconName)
{
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 new ImagePath(ImagePathType.Asset, "/Assets/material/" + iconName);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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();
}

View File

@@ -260,7 +260,7 @@
VerticalAlignment="Stretch"
Fill="{DynamicResource ContentSeparatorBrush}" />
<Grid Grid.Column="4">
<Grid Grid.Column="4" IsVisible="{Binding AppState.SelectedTab.ChildContainer,Converter={StaticResource IsNotNullConverter}}">
<ListBox
Classes="ContentListView"
IsEnabled="False"
@@ -283,20 +283,32 @@
HorizontalAlignment="Center"
FontWeight="Bold"
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
</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>
<DataTemplate>
<TextBlock Text="{Binding}"/>
<TextBlock Text="{Binding, Converter={StaticResource ExceptionToStringConverter}}"/>
</DataTemplate>
</ItemsRepeater.ItemTemplate>
</ItemsRepeater>
</Grid>
</Grid>
</Grid>
</Grid>
<Grid
HorizontalAlignment="Center"