RapidTravel impr, GoBack/Forward, header navigation

This commit is contained in:
2023-08-03 20:00:55 +02:00
parent 754496625e
commit d6c4f16fc2
22 changed files with 1034 additions and 81 deletions

View File

@@ -63,9 +63,9 @@ public static class MainConfiguration
//new CommandBindingConfiguration(ConfigCommand.Edit, new KeyConfig(Key.F4)),
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Key.OemComma, shift: true)),
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Key.OemQuestion, shift: true)),
//new CommandBindingConfiguration(ConfigCommand.FindByName, new[] { Key.F, Key.N }),
//new CommandBindingConfiguration(ConfigCommand.FindByNameRegex, new[] { Key.F, Key.R }),
new(GoBackCommand.CommandName, new KeyConfig(Key.Left, alt: true)),
new(GoByFrequencyCommand.CommandName, Key.Z),
new(GoForwardCommand.CommandName, new KeyConfig(Key.Right, alt: true)),
new(GoToHomeCommand.CommandName, new[] {Key.G, Key.H}),
new(GoToPathCommand.CommandName, new KeyConfig(Key.L, ctrl: true)),
new(GoToPathCommand.CommandName, new[] {Key.G, Key.P}),

View File

@@ -1,6 +1,7 @@
using System.Globalization;
using Avalonia.Data.Converters;
using Avalonia.Media;
using Avalonia.Threading;
using FileTime.Core.Models;
using FileTime.GuiApp.App.ViewModels;
@@ -9,6 +10,7 @@ namespace FileTime.GuiApp.App.Converters;
public class NamePartShrinkerConverter : IMultiValueConverter
{
private const int PixelPerChar = 8;
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
{
if (values.Count > 0 && values[0] is IList<ItemNamePart> nameParts)
@@ -20,8 +22,13 @@ public class NamePartShrinkerConverter : IMultiValueConverter
newNameParts = GetNamePartsForWidth(nameParts, width - attributeWidth);
}
return newNameParts.Select(p => new ItemNamePartViewModel(p.Text, p.IsSpecial ? TextDecorations.Underline : null)).ToList();
var result = /* Dispatcher.UIThread.Invoke(() => */
newNameParts.Select(p => new ItemNamePartViewModel(p.Text, p.IsSpecial ? TextDecorations.Underline : null)).ToList();
/* ); */
return result;
}
return null;
}
@@ -75,6 +82,7 @@ public class NamePartShrinkerConverter : IMultiValueConverter
proposedText = proposedText[0..^1];
trimmed = true;
}
newNameParts[trimmedIndex] = new ItemNamePart(proposedText + (trimmed ? "..." : ""));
if (trimmed) break;
}
@@ -100,6 +108,7 @@ public class NamePartShrinkerConverter : IMultiValueConverter
if (!string.IsNullOrWhiteSpace(proposedText)) newNameParts.Add(new ItemNamePart(proposedText, namePart.IsSpecial));
if (trimmed) break;
}
if (newNameParts.Last().IsSpecial)
{
newNameParts.Add(new ItemNamePart("..."));
@@ -109,6 +118,7 @@ public class NamePartShrinkerConverter : IMultiValueConverter
var last = newNameParts.Last();
newNameParts[^1] = new ItemNamePart(last.Text + "...");
}
return newNameParts;
}
}

View File

@@ -67,6 +67,11 @@
<Setter Property="Background" Value="{DynamicResource AppBackgroundColor}" />
</Style>
<Style Selector="TextBlock.PathPresenterItem:pointerover">
<Setter Property="TextDecorations" Value="Underline" />
<Setter Property="Cursor" Value="Hand" />
</Style>
<Style Selector="Border.SelectedTimelineCommand">
<Setter Property="BorderBrush" Value="{DynamicResource ForegroundBrush}" />
</Style>

View File

@@ -43,12 +43,22 @@ public class RapidTravelModeKeyInputHandler : IRapidTravelModeKeyInputHandler
_appState.SelectedTab.Subscribe(t => _selectedTab = t);
_openModals = modalService.OpenModals.ToBindedCollection();
_appState.RapidTravelTextDebounced.Subscribe((v, _) =>
{
if (_selectedTab?.Tab is not { } tab) return Task.CompletedTask;
tab.RemoveItemFilter(RapidTravelFilterName);
if (v is null) return Task.CompletedTask;
tab.AddItemFilter(new ItemFilter(RapidTravelFilterName, i => i.Name.ToLower().Contains(v)));
return Task.CompletedTask;
});
}
public async Task HandleInputKey(Key key, SpecialKeysStatus specialKeysStatus, Action<bool> setHandled)
{
var keyString = key.ToString();
var updateRapidTravelFilter = false;
if (key == Key.Escape)
{
@@ -70,7 +80,6 @@ public class RapidTravelModeKeyInputHandler : IRapidTravelModeKeyInputHandler
await _appState.RapidTravelText.SetValue(
_appState.RapidTravelText.Value![..^1]
);
updateRapidTravelFilter = true;
}
}
else if (keyString.Length == 1)
@@ -79,11 +88,10 @@ public class RapidTravelModeKeyInputHandler : IRapidTravelModeKeyInputHandler
await _appState.RapidTravelText.SetValue(
_appState.RapidTravelText.Value + keyString.ToLower()
);
updateRapidTravelFilter = true;
}
else
{
var currentKeyAsList = new List<KeyConfig>() { new KeyConfig(key) };
var currentKeyAsList = new List<KeyConfig>() {new KeyConfig(key)};
var selectedCommandBinding = _keyboardConfigurationService.UniversalCommandBindings.FirstOrDefault(c => c.Keys.AreKeysEqual(currentKeyAsList));
if (selectedCommandBinding != null)
{
@@ -91,42 +99,6 @@ public class RapidTravelModeKeyInputHandler : IRapidTravelModeKeyInputHandler
await CallCommandAsync(_identifiableUserCommandService.GetCommand(selectedCommandBinding.Command));
}
}
if (updateRapidTravelFilter)
{
if (_selectedTab?.Tab is not ITab tab) return;
tab.RemoveItemFilter(RapidTravelFilterName);
tab.AddItemFilter(new ItemFilter(RapidTravelFilterName, i => i.Name.ToLower().Contains(_appState.RapidTravelText.Value!)));
/*var currentLocation = await _appState.SelectedTab.CurrentLocation.Container.WithoutVirtualContainer(MainPageViewModel.RAPIDTRAVEL);
var newLocation = new VirtualContainer(
currentLocation,
new List<Func<IEnumerable<IContainer>, IEnumerable<IContainer>>>()
{
container => container.Where(c => c.Name.ToLower().Contains(_appState.RapidTravelText))
},
new List<Func<IEnumerable<IElement>, IEnumerable<IElement>>>()
{
element => element.Where(e => e.Name.ToLower().Contains(_appState.RapidTravelText))
},
virtualContainerName: MainPageViewModel.RAPIDTRAVEL
);
await newLocation.Init();
await _appState.SelectedTab.OpenContainer(newLocation);
var selectedItemName = _appState.SelectedTab.SelectedItem?.Item.Name;
var currentLocationItems = await _appState.SelectedTab.CurrentLocation.GetItems();
if (currentLocationItems.FirstOrDefault(i => string.Equals(i.Item.Name, _appState.RapidTravelText, StringComparison.OrdinalIgnoreCase)) 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();
}*/
}
}
private async Task CallCommandAsync(IUserCommand command)

View File

@@ -1,4 +1,5 @@
using FileTime.App.CommandPalette.Services;
using DeclarativeProperty;
using FileTime.App.CommandPalette.Services;
using FileTime.App.Core.Services;
using FileTime.App.Core.ViewModels;
using FileTime.App.FrequencyNavigation.Services;

View File

@@ -1,13 +1,13 @@
<UserControl
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d"
x:Class="FileTime.GuiApp.App.Views.PathPresenter"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:coremodels="using:FileTime.Core.Models"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ItemsControl ItemsSource="{Binding Converter={StaticResource SplitStringConverter}, ConverterParameter={x:Static coremodels:Constants.SeparatorChar}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
@@ -17,10 +17,13 @@
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<TextBlock
Margin="5,0,5,0"
Classes="PathPresenterItem"
PointerPressed="InputElement_OnPointerPressed"
Text="{Binding}" />
<TextBlock
Foreground="{DynamicResource LightForegroundBrush}"
Margin="5,0,5,0"
Text="/" />
</StackPanel>
</DataTemplate>

View File

@@ -1,11 +1,53 @@
using Avalonia.Controls;
using Avalonia.Input;
using FileTime.App.Core.Services;
using FileTime.App.Core.UserCommand;
using FileTime.Core.Enums;
using FileTime.Core.Models;
using FileTime.Core.Timeline;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace FileTime.GuiApp.App.Views;
public partial class PathPresenter : UserControl
{
private readonly Lazy<ILogger<PathPresenter>> _logger;
public PathPresenter()
{
InitializeComponent();
_logger = new Lazy<ILogger<PathPresenter>>(
() => DI.ServiceProvider.GetRequiredService<ILogger<PathPresenter>>()
);
}
private async void InputElement_OnPointerPressed(object? sender, PointerPressedEventArgs e)
{
try
{
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed
&& DataContext is string fullPath
&& sender is TextBlock textBlock)
{
var pathPart = textBlock.Text;
var path = fullPath[..(fullPath.IndexOf(pathPart) + pathPart.Length)];
var timelessContentProvider = DI.ServiceProvider.GetRequiredService<ITimelessContentProvider>();
var userCommandHandlerService = DI.ServiceProvider.GetRequiredService<IUserCommandHandlerService>();
await userCommandHandlerService.HandleCommandAsync(
new OpenContainerCommand(
new AbsolutePath(
timelessContentProvider,
PointInTime.Present,
new FullName(path),
AbsolutePathType.Container)
)
);
}
}
catch (Exception exception)
{
_logger.Value.LogError(exception, "Failed to open container");
}
}
}