Search improvements, bugfix
This commit is contained in:
@@ -42,6 +42,10 @@ namespace FileTime.Core.Components
|
||||
if (_currentLocation != null)
|
||||
{
|
||||
_currentLocation.Refreshed.Remove(HandleCurrentLocationRefresh);
|
||||
if(_currentLocation is SearchContainer searchContainer)
|
||||
{
|
||||
searchContainer.SearchTaskBase.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
_currentLocation = value;
|
||||
|
||||
8
src/Core/FileTime.Core/Models/IFile.cs
Normal file
8
src/Core/FileTime.Core/Models/IFile.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace FileTime.Core.Models
|
||||
{
|
||||
public interface IFile : IElement
|
||||
{
|
||||
string Attributes { get; }
|
||||
DateTime CreatedAt { get; }
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,15 @@ namespace FileTime.Core.Search
|
||||
{
|
||||
public class ChildSearchElement : AbstractElement<IContentProvider>
|
||||
{
|
||||
public ChildSearchElement(SearchContainer searchContainer, IContentProvider provider, IContainer parent, string name, string displayName, List<ItemNamePart> searchDisplayName) : base(provider, parent, name)
|
||||
public IElement BaseElement { get; }
|
||||
|
||||
public ChildSearchElement(SearchContainer searchContainer, IContentProvider provider, IContainer parent, IElement baseElement, string name, List<ItemNamePart> searchDisplayName) : base(provider, parent, name)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
DisplayName = baseElement.DisplayName;
|
||||
NativePath = FullName;
|
||||
SearchContainer = searchContainer;
|
||||
SearchDisplayName = searchDisplayName;
|
||||
BaseElement = baseElement;
|
||||
}
|
||||
|
||||
public SearchContainer SearchContainer { get; }
|
||||
@@ -24,9 +27,9 @@ namespace FileTime.Core.Search
|
||||
|
||||
public override Task<IContentWriter> GetContentWriterAsync() => throw new NotSupportedException();
|
||||
|
||||
public override Task<long?> GetElementSize(CancellationToken token = default) => Task.FromResult((long?)null);
|
||||
public override async Task<long?> GetElementSize(CancellationToken token = default) => await BaseElement.GetElementSize(token);
|
||||
|
||||
public override string GetPrimaryAttributeText() => "";
|
||||
public override string GetPrimaryAttributeText() => BaseElement.GetPrimaryAttributeText();
|
||||
|
||||
public override Task Rename(string newName) => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,6 @@ namespace FileTime.Core.Search
|
||||
|
||||
protected override Task<bool> IsItemMatch(IItem item) => Task.FromResult(item.Name.Contains(_name));
|
||||
|
||||
public override List<ItemNamePart> GetDisplayName(IItem item) => _itemNameConverterService.GetDisplayName(item, _name);
|
||||
public override List<ItemNamePart> GetDisplayName(IItem item) => _itemNameConverterService.GetDisplayName(item.DisplayName, _name);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@ namespace FileTime.Core.Search
|
||||
|
||||
private readonly IReadOnlyList<IContainer> _containersReadOnly;
|
||||
private readonly IReadOnlyList<IElement> _elementsReadOnly;
|
||||
private readonly SearchTaskBase _searchTaskBase;
|
||||
public SearchTaskBase SearchTaskBase { get; }
|
||||
|
||||
public IContainer SearchBaseContainer { get; }
|
||||
public override bool IsExists => throw new NotImplementedException();
|
||||
@@ -25,7 +25,7 @@ namespace FileTime.Core.Search
|
||||
SearchBaseContainer = searchBaseContainer;
|
||||
_containers = new List<IContainer>();
|
||||
_elements = new List<IElement>();
|
||||
_searchTaskBase = searchTaskBase;
|
||||
SearchTaskBase = searchTaskBase;
|
||||
|
||||
_containersReadOnly = _containers.AsReadOnly();
|
||||
_elementsReadOnly = _elements.AsReadOnly();
|
||||
@@ -52,14 +52,14 @@ namespace FileTime.Core.Search
|
||||
|
||||
public async Task AddContainer(IContainer container)
|
||||
{
|
||||
var childContainer = new ChildSearchContainer(this, Provider, container, "container" + _childContainerCounter++, container.DisplayName, _searchTaskBase.GetDisplayName(container));
|
||||
var childContainer = new ChildSearchContainer(this, Provider, container, "container" + _childContainerCounter++, container.DisplayName, SearchTaskBase.GetDisplayName(container));
|
||||
_containers.Add(childContainer);
|
||||
await UpdateChildren();
|
||||
}
|
||||
|
||||
public async Task AddElement(IElement element)
|
||||
{
|
||||
var childElement = new ChildSearchElement(this, Provider, element.GetParent()!, "element" + _childElementCounter++, element.DisplayName, _searchTaskBase.GetDisplayName(element));
|
||||
var childElement = new ChildSearchElement(this, Provider, element.GetParent()!, element, "element" + _childElementCounter++, SearchTaskBase.GetDisplayName(element));
|
||||
_elements.Add(childElement);
|
||||
await UpdateChildren();
|
||||
}
|
||||
@@ -95,7 +95,7 @@ namespace FileTime.Core.Search
|
||||
|
||||
public override Task<ContainerEscapeResult> HandleEscape()
|
||||
{
|
||||
if (_searchTaskBase.Cancel()) return Task.FromResult(new ContainerEscapeResult(true));
|
||||
if (SearchTaskBase.Cancel()) return Task.FromResult(new ContainerEscapeResult(true));
|
||||
|
||||
return Task.FromResult(new ContainerEscapeResult(SearchBaseContainer));
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ namespace FileTime.Core.Services
|
||||
{
|
||||
public class ItemNameConverterService
|
||||
{
|
||||
public List<ItemNamePart> GetDisplayName(IItem item, string? searchText)
|
||||
public List<ItemNamePart> GetDisplayName(string name, string? searchText)
|
||||
{
|
||||
var nameParts = new List<ItemNamePart>();
|
||||
searchText = searchText?.ToLower();
|
||||
|
||||
var name = item is IElement ? GetFileName(item.DisplayName) : item.DisplayName;
|
||||
if (!string.IsNullOrEmpty(searchText))
|
||||
{
|
||||
var nameLeft = name;
|
||||
|
||||
@@ -218,13 +218,13 @@ namespace FileTime.Avalonia.Application
|
||||
else if (currentSelectenItem.Item is ChildSearchContainer searchContainer)
|
||||
{
|
||||
var searchContainerPreview = _serviceProvider.GetService<SearchContainerPreview>()!;
|
||||
await searchContainerPreview.Init(searchContainer, _currentLocation.Container);
|
||||
searchContainerPreview.Init(searchContainer, _currentLocation.Container);
|
||||
preview = searchContainerPreview;
|
||||
}
|
||||
else if (currentSelectenItem.Item is ChildSearchElement searchElement)
|
||||
{
|
||||
var searchElementPreview = _serviceProvider.GetService<SearchElementPreview>()!;
|
||||
await searchElementPreview.Init(searchElement, _currentLocation.Container);
|
||||
searchElementPreview.Init(searchElement, _currentLocation.Container);
|
||||
preview = searchElementPreview;
|
||||
}
|
||||
else if (currentSelectenItem is ElementViewModel elementViewModel)
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Globalization;
|
||||
using Avalonia.Data.Converters;
|
||||
using FileTime.Avalonia.Models;
|
||||
using FileTime.Avalonia.ViewModels;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Providers.Local;
|
||||
|
||||
namespace FileTime.Avalonia.Converters
|
||||
@@ -12,7 +13,9 @@ namespace FileTime.Avalonia.Converters
|
||||
public bool Invert { get; set; }
|
||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
var result = parameter is AttibuteType targetAttribute && GetAttibuteType(value) == targetAttribute;
|
||||
var attributeType = GetAttibuteType(value);
|
||||
if (parameter == null) return attributeType;
|
||||
var result = parameter is AttibuteType targetAttribute && attributeType == targetAttribute;
|
||||
if (Invert && parameter is AttibuteType) result = !result;
|
||||
return result;
|
||||
}
|
||||
@@ -21,9 +24,9 @@ namespace FileTime.Avalonia.Converters
|
||||
{
|
||||
if (value is ElementViewModel elementVM)
|
||||
{
|
||||
if (elementVM.Element is LocalFile)
|
||||
if (elementVM.BaseElement is IFile)
|
||||
{
|
||||
return AttibuteType.LocalFile;
|
||||
return AttibuteType.File;
|
||||
}
|
||||
return AttibuteType.Element;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ namespace FileTime.Avalonia.Models
|
||||
{
|
||||
public enum AttibuteType
|
||||
{
|
||||
LocalFile,
|
||||
File,
|
||||
Element,
|
||||
Container
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using System.Threading.Tasks;
|
||||
using FileTime.Avalonia.Application;
|
||||
using System.Threading;
|
||||
using FileTime.Core.Services;
|
||||
using FileTime.Core.Search;
|
||||
|
||||
namespace FileTime.Avalonia.ViewModels
|
||||
{
|
||||
@@ -29,6 +30,9 @@ namespace FileTime.Avalonia.ViewModels
|
||||
[Property]
|
||||
private IContainer _container;
|
||||
|
||||
[Property]
|
||||
private IContainer _baseContainer;
|
||||
|
||||
[Property]
|
||||
private bool _isSelected;
|
||||
|
||||
@@ -45,6 +49,7 @@ namespace FileTime.Avalonia.ViewModels
|
||||
private List<Exception> _exceptions;
|
||||
|
||||
public IItem Item => _container;
|
||||
public IItem BaseItem => _baseContainer;
|
||||
|
||||
private ObservableCollection<ContainerViewModel> _containers = new();
|
||||
|
||||
@@ -70,7 +75,7 @@ namespace FileTime.Avalonia.ViewModels
|
||||
_ => ItemViewMode.Default
|
||||
};
|
||||
|
||||
public List<ItemNamePart> DisplayName => ItemNameConverterService.GetDisplayName(Item, AppState.ViewMode == Application.ViewMode.RapidTravel ? AppState.RapidTravelText : null);
|
||||
public List<ItemNamePart> DisplayName => ItemNameConverterService.GetDisplayName(Item.DisplayName, AppState.ViewMode == Application.ViewMode.RapidTravel ? AppState.RapidTravelText : null);
|
||||
|
||||
public Task Containers => GetContainers();
|
||||
public Task Elements => GetElements();
|
||||
@@ -127,6 +132,7 @@ namespace FileTime.Avalonia.ViewModels
|
||||
Parent = parent;
|
||||
|
||||
Container = container;
|
||||
BaseContainer = container is ChildSearchContainer childSearchContainer ? childSearchContainer.BaseContainer : container;
|
||||
Container.Refreshed.Add(Container_Refreshed);
|
||||
Container.LazyLoadingChanged.Add(Container_LazyLoadingChanged);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using FileTime.Avalonia.Application;
|
||||
using FileTime.Core.Services;
|
||||
using FileTime.Core.Search;
|
||||
|
||||
namespace FileTime.Avalonia.ViewModels
|
||||
{
|
||||
@@ -15,10 +16,14 @@ namespace FileTime.Avalonia.ViewModels
|
||||
public partial class ElementViewModel : IItemViewModel
|
||||
{
|
||||
public IItem Item => _element;
|
||||
public IItem BaseItem => _baseElement;
|
||||
|
||||
[Property]
|
||||
private IElement _element;
|
||||
|
||||
[Property]
|
||||
private IElement _baseElement;
|
||||
|
||||
[Property]
|
||||
private bool _isSelected;
|
||||
|
||||
@@ -48,11 +53,12 @@ namespace FileTime.Avalonia.ViewModels
|
||||
_ => ItemViewMode.Default
|
||||
};
|
||||
|
||||
public List<ItemNamePart> DisplayName => ItemNameConverterService.GetDisplayName(Item, AppState.ViewMode == Application.ViewMode.RapidTravel ? AppState.RapidTravelText : null);
|
||||
public List<ItemNamePart> DisplayName => ItemNameConverterService.GetDisplayName(ItemNameConverterService.GetFileName(Item.DisplayName), AppState.ViewMode == Application.ViewMode.RapidTravel ? AppState.RapidTravelText : null);
|
||||
|
||||
public ElementViewModel(IElement element, ContainerViewModel parent, ItemNameConverterService itemNameConverterService, AppState appState) : this(itemNameConverterService, appState)
|
||||
{
|
||||
Element = element;
|
||||
BaseElement = element is ChildSearchElement childSearchElement ? childSearchElement.BaseElement : element;
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace FileTime.Avalonia.ViewModels
|
||||
public interface IItemViewModel
|
||||
{
|
||||
IItem Item { get; }
|
||||
IItem BaseItem { get; }
|
||||
bool IsSelected { get; set; }
|
||||
|
||||
bool IsAlternative { get; set; }
|
||||
|
||||
@@ -23,11 +23,11 @@ namespace FileTime.Avalonia.ViewModels.ItemPreview
|
||||
[Property]
|
||||
private string? _realtiveParentPath;
|
||||
|
||||
public async Task Init(ChildSearchContainer container, IContainer currentLocation)
|
||||
public void Init(ChildSearchContainer container, IContainer currentLocation)
|
||||
{
|
||||
var pathCommonPath = PathHelper.GetCommonPath(currentLocation.FullName!, container.FullName!);
|
||||
RealtiveParentPath = new AbsolutePath(null!, container.FullName!.Substring(pathCommonPath.Length).Trim(Constants.SeparatorChar), AbsolutePathType.Unknown, null).GetParentPath();
|
||||
ItemNameParts = await Task.Run(async () => await Dispatcher.UIThread.InvokeAsync(() => container.SearchDisplayName.Select(p => new ItemNamePartViewModel(p.Text, p.IsSpecial ? TextDecorations.Underline : null)).ToList()));
|
||||
Task.Run(async () => ItemNameParts = await Dispatcher.UIThread.InvokeAsync(() => container.SearchDisplayName.ConvertAll(p => new ItemNamePartViewModel(p.Text, p.IsSpecial ? TextDecorations.Underline : null))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,11 @@ namespace FileTime.Avalonia.ViewModels.ItemPreview
|
||||
[Property]
|
||||
private string? _realtiveParentPath;
|
||||
|
||||
public async Task Init(ChildSearchElement element, IContainer currentLocation)
|
||||
public void Init(ChildSearchElement element, IContainer currentLocation)
|
||||
{
|
||||
var pathCommonPath = PathHelper.GetCommonPath(currentLocation.FullName!, element.FullName!);
|
||||
RealtiveParentPath = new AbsolutePath(null!, element.FullName!.Substring(pathCommonPath.Length).Trim(Constants.SeparatorChar), AbsolutePathType.Unknown, null).GetParentPath();
|
||||
ItemNameParts = await Task.Run(async () => await Dispatcher.UIThread.InvokeAsync(() => element.SearchDisplayName.Select(p => new ItemNamePartViewModel(p.Text, p.IsSpecial ? TextDecorations.Underline : null)).ToList()));
|
||||
Task.Run(async () => ItemNameParts = await Dispatcher.UIThread.InvokeAsync(() => element.SearchDisplayName.ConvertAll(p => new ItemNamePartViewModel(p.Text, p.IsSpecial ? TextDecorations.Underline : null))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,29 +55,28 @@
|
||||
<Grid Grid.Column="2" IsVisible="{Binding ShowAttributes,ElementName=ItemRoot}">
|
||||
<Grid ColumnDefinitions="50,50,90,40,45"
|
||||
HorizontalAlignment="Right"
|
||||
IsVisible="{Binding Converter={StaticResource ItemViewModelIsAttibuteTypeConverter},ConverterParameter={x:Static models:AttibuteType.LocalFile}}">
|
||||
IsVisible="{Binding Converter={StaticResource ItemViewModelIsAttibuteTypeConverter},ConverterParameter={x:Static models:AttibuteType.File}}">
|
||||
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Text="{Binding Item.Name, Converter={StaticResource GetFileExtensionConverter}}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Text="{Binding BaseItem.DisplayName, Converter={StaticResource GetFileExtensionConverter}}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="1" Text="{Binding Size, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="2" Text="{Binding Item.CreatedAt, Converter={StaticResource DateTimeConverter}, ConverterParameter=yyyy-MM-dd}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="3" Text="{Binding Item.CreatedAt, Converter={StaticResource DateTimeConverter}, ConverterParameter=hh:mm}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="4" Text="{Binding Item.Attributes}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="2" Text="{Binding BaseItem.CreatedAt, Converter={StaticResource DateTimeConverter}, ConverterParameter=yyyy-MM-dd}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="3" Text="{Binding BaseItem.CreatedAt, Converter={StaticResource DateTimeConverter}, ConverterParameter=hh:mm}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="4" Text="{Binding BaseItem.Attributes}"/>
|
||||
</Grid>
|
||||
<Grid ColumnDefinitions="90,40,45"
|
||||
HorizontalAlignment="Right"
|
||||
IsVisible="{Binding Converter={StaticResource ItemViewModelIsAttibuteTypeConverter},ConverterParameter={x:Static models:AttibuteType.Container}}">
|
||||
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Text="{Binding Item.CreatedAt, Converter={StaticResource DateTimeConverter}, ConverterParameter=yyyy-MM-dd}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="1" Text="{Binding Item.CreatedAt, Converter={StaticResource DateTimeConverter}, ConverterParameter=hh:mm}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="2" Text="{Binding Item.Attributes}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="1" Text="{Binding BaseItem.CreatedAt, Converter={StaticResource DateTimeConverter}, ConverterParameter=hh:mm}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="2" Text="{Binding BaseItem.Attributes}"/>
|
||||
</Grid>
|
||||
<Grid ColumnDefinitions="90,40,45"
|
||||
<Grid ColumnDefinitions="50,50"
|
||||
HorizontalAlignment="Right"
|
||||
IsVisible="{Binding Converter={StaticResource ItemViewModelIsAttibuteTypeConverter},ConverterParameter={x:Static models:AttibuteType.Element}}">
|
||||
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Text="{Binding Item.CreatedAt, Converter={StaticResource DateTimeConverter}, ConverterParameter=yyyy-MM-dd}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="1" Text="{Binding Item.CreatedAt, Converter={StaticResource DateTimeConverter}, ConverterParameter=hh:mm}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="2" Text="{Binding Item.Attributes}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Text="{Binding BaseItem.DisplayName, Converter={StaticResource GetFileExtensionConverter}}"/>
|
||||
<TextBlock HorizontalAlignment="Right" Classes="SmallText" Grid.Column="1" Text="{Binding Size, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -7,7 +7,7 @@ using Mono.Unix;
|
||||
|
||||
namespace FileTime.Providers.Local
|
||||
{
|
||||
public class LocalFile : IElement
|
||||
public class LocalFile : IFile
|
||||
{
|
||||
public FileInfo File { get; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user