MainPageViewModel refactor, keybindings from config
This commit is contained in:
@@ -2,34 +2,58 @@ namespace FileTime.App.Core.Command
|
|||||||
{
|
{
|
||||||
public enum Commands
|
public enum Commands
|
||||||
{
|
{
|
||||||
|
None,
|
||||||
|
|
||||||
|
AutoRefresh,
|
||||||
|
ChangeTimelineMode,
|
||||||
CloseTab,
|
CloseTab,
|
||||||
Copy,
|
Copy,
|
||||||
|
CopyPath,
|
||||||
CreateContainer,
|
CreateContainer,
|
||||||
CreateElement,
|
CreateElement,
|
||||||
Cut,
|
Cut,
|
||||||
EnterRapidTravel,
|
EnterRapidTravel,
|
||||||
GoToHome,
|
GoToHome,
|
||||||
|
GoToPath,
|
||||||
GoToProvider,
|
GoToProvider,
|
||||||
GoToRoot,
|
GoToRoot,
|
||||||
GoUp,
|
GoUp,
|
||||||
Delete,
|
HardDelete,
|
||||||
|
Mark,
|
||||||
MoveCursorDown,
|
MoveCursorDown,
|
||||||
MoveCursorDownPage,
|
MoveCursorDownPage,
|
||||||
MoveCursorUp,
|
MoveCursorUp,
|
||||||
MoveCursorUpPage,
|
MoveCursorUpPage,
|
||||||
MoveToBottom,
|
|
||||||
MoveToFirst,
|
MoveToFirst,
|
||||||
MoveToLast,
|
MoveToLast,
|
||||||
MoveToTop,
|
NextTimelineBlock,
|
||||||
|
NextTimelineCommand,
|
||||||
Open,
|
Open,
|
||||||
|
OpenInFileBrowser,
|
||||||
OpenOrRun,
|
OpenOrRun,
|
||||||
PasteMerge,
|
PasteMerge,
|
||||||
PasteOverwrite,
|
PasteOverwrite,
|
||||||
PasteSkip,
|
PasteSkip,
|
||||||
Select,
|
PreviousTimelineBlock,
|
||||||
ToggleHidden,
|
PreviousTimelineCommand,
|
||||||
Rename,
|
|
||||||
Dummy,
|
|
||||||
Refresh,
|
Refresh,
|
||||||
|
Rename,
|
||||||
|
RunCommand,
|
||||||
|
ShowAllShotcut,
|
||||||
|
SoftDelete,
|
||||||
|
SwitchToLastTab,
|
||||||
|
SwitchToTab1,
|
||||||
|
SwitchToTab2,
|
||||||
|
SwitchToTab3,
|
||||||
|
SwitchToTab4,
|
||||||
|
SwitchToTab5,
|
||||||
|
SwitchToTab6,
|
||||||
|
SwitchToTab7,
|
||||||
|
SwitchToTab8,
|
||||||
|
TimelinePause,
|
||||||
|
TimelineRefresh,
|
||||||
|
TimelineStart,
|
||||||
|
ToggleAdvancedIcons,
|
||||||
|
ToggleHidden,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ namespace FileTime.ConsoleUI.App
|
|||||||
new CommandBinding("open", Commands.Open, new[] { new ConsoleKeyInfo('→', ConsoleKey.RightArrow, false, false, false) }, Open),
|
new CommandBinding("open", Commands.Open, new[] { new ConsoleKeyInfo('→', ConsoleKey.RightArrow, false, false, false) }, Open),
|
||||||
new CommandBinding(
|
new CommandBinding(
|
||||||
"go to top",
|
"go to top",
|
||||||
Commands.MoveToTop,
|
Commands.MoveToFirst,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new ConsoleKeyInfo('g', ConsoleKey.G, false, false, false),
|
new ConsoleKeyInfo('g', ConsoleKey.G, false, false, false),
|
||||||
@@ -99,7 +99,7 @@ namespace FileTime.ConsoleUI.App
|
|||||||
MoveCursorToTop),
|
MoveCursorToTop),
|
||||||
new CommandBinding(
|
new CommandBinding(
|
||||||
"go to bottom",
|
"go to bottom",
|
||||||
Commands.MoveToBottom,
|
Commands.MoveToLast,
|
||||||
new[]
|
new[]
|
||||||
{
|
{
|
||||||
new ConsoleKeyInfo('G', ConsoleKey.G, true, false, false)
|
new ConsoleKeyInfo('G', ConsoleKey.G, true, false, false)
|
||||||
@@ -114,7 +114,7 @@ namespace FileTime.ConsoleUI.App
|
|||||||
new ConsoleKeyInfo('h', ConsoleKey.H, false, false, false)
|
new ConsoleKeyInfo('h', ConsoleKey.H, false, false, false)
|
||||||
},
|
},
|
||||||
ToggleHidden),
|
ToggleHidden),
|
||||||
new CommandBinding("select", Commands.Select, new[] { new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false) }, Select),
|
new CommandBinding("select", Commands.Mark, new[] { new ConsoleKeyInfo(' ', ConsoleKey.Spacebar, false, false, false) }, Select),
|
||||||
new CommandBinding(
|
new CommandBinding(
|
||||||
"copy",
|
"copy",
|
||||||
Commands.Copy,
|
Commands.Copy,
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
<converters:ItemViewModelIsAttibuteTypeConverter x:Key="ItemViewModelIsAttibuteTypeConverter"/>
|
<converters:ItemViewModelIsAttibuteTypeConverter x:Key="ItemViewModelIsAttibuteTypeConverter"/>
|
||||||
<converters:ItemViewModelIsAttibuteTypeConverter x:Key="ItemViewModelIsNotAttibuteTypeConverter" Invert="true"/>
|
<converters:ItemViewModelIsAttibuteTypeConverter x:Key="ItemViewModelIsNotAttibuteTypeConverter" Invert="true"/>
|
||||||
<converters:GetFileExtensionConverter x:Key="GetFileExtensionConverter"/>
|
<converters:GetFileExtensionConverter x:Key="GetFileExtensionConverter"/>
|
||||||
|
<converters:CommandToCommandNameConverter x:Key="CommandToCommandNameConverter"/>
|
||||||
|
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
@@ -186,15 +187,5 @@
|
|||||||
<Style Selector="Border.SelectedTimelineCommand">
|
<Style Selector="Border.SelectedTimelineCommand">
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource ForegroundBrush}"/>
|
<Setter Property="BorderBrush" Value="{DynamicResource ForegroundBrush}"/>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
<!--Style Selector="MenuItem">
|
|
||||||
<Setter Property="Template">
|
|
||||||
<DataTemplate>
|
|
||||||
<Grid ColumnDefinitions="20,*">
|
|
||||||
<TextBlock Grid.Column="1" Text="{Binding Header}" />
|
|
||||||
</Grid>
|
|
||||||
</DataTemplate>
|
|
||||||
</Setter>
|
|
||||||
</Style-->
|
|
||||||
</Application.Styles>
|
</Application.Styles>
|
||||||
</Application>
|
</Application>
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ using FileTime.App.Core.Tab;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using FileTime.Avalonia.Configuration;
|
||||||
|
using FileTime.Avalonia.Misc;
|
||||||
|
using FileTime.Core.Extensions;
|
||||||
|
using FileTime.Avalonia.ViewModels;
|
||||||
|
|
||||||
namespace FileTime.Avalonia.Application
|
namespace FileTime.Avalonia.Application
|
||||||
{
|
{
|
||||||
@@ -26,6 +30,28 @@ namespace FileTime.Avalonia.Application
|
|||||||
[Property]
|
[Property]
|
||||||
private string _rapidTravelText = "";
|
private string _rapidTravelText = "";
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private List<CommandBindingConfiguration> _possibleCommands = new();
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private List<InputElementWrapper> _inputs;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private string _messageBoxText;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private ObservableCollection<string> _popupTexts = new();
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private bool _isAllShortcutVisible;
|
||||||
|
|
||||||
|
[Property]
|
||||||
|
private bool _noCommandFound;
|
||||||
|
|
||||||
|
public List<KeyConfig> PreviousKeys { get; } = new();
|
||||||
|
|
||||||
|
public ObservableCollection<ParallelCommandsViewModel> TimelineCommands { get; } = new();
|
||||||
|
|
||||||
partial void OnInitialize()
|
partial void OnInitialize()
|
||||||
{
|
{
|
||||||
_tabs.CollectionChanged += TabsChanged;
|
_tabs.CollectionChanged += TabsChanged;
|
||||||
@@ -99,5 +125,16 @@ namespace FileTime.Avalonia.Application
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task ExitRapidTravelMode()
|
||||||
|
{
|
||||||
|
ViewMode = ViewMode.Default;
|
||||||
|
|
||||||
|
PreviousKeys.Clear();
|
||||||
|
PossibleCommands = new();
|
||||||
|
RapidTravelText = "";
|
||||||
|
|
||||||
|
await SelectedTab.OpenContainer(await SelectedTab.CurrentLocation.Container.WithoutVirtualContainer(MainPageViewModel.RAPIDTRAVEL));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using FileTime.App.Core.Command;
|
/* using FileTime.App.Core.Command;
|
||||||
using FileTime.Avalonia.Misc;
|
using FileTime.Avalonia.Misc;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -14,11 +14,11 @@ namespace FileTime.Avalonia.Command
|
|||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public Commands? Command { get; }
|
public Commands? Command { get; }
|
||||||
public KeyWithModifiers[] Keys { get; }
|
public KeyConfig[] Keys { get; }
|
||||||
|
|
||||||
public string KeysDisplayText => GetKeysDisplayText();
|
public string KeysDisplayText => GetKeysDisplayText();
|
||||||
|
|
||||||
public CommandBinding(string name, Commands? command, KeyWithModifiers[] keys, Func<Task> commandHandler)
|
public CommandBinding(string name, Commands? command, KeyConfig[] keys, Func<Task> commandHandler)
|
||||||
{
|
{
|
||||||
_commandHandler = commandHandler;
|
_commandHandler = commandHandler;
|
||||||
Name = name;
|
Name = name;
|
||||||
@@ -48,7 +48,7 @@ namespace FileTime.Avalonia.Command
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string AddKeyWithCtrlOrAlt(KeyWithModifiers key, string currentText, Func<KeyWithModifiers, string, bool, string> keyProcessor)
|
private static string AddKeyWithCtrlOrAlt(KeyConfig key, string currentText, Func<KeyConfig, string, bool, string> keyProcessor)
|
||||||
{
|
{
|
||||||
var s = "";
|
var s = "";
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ namespace FileTime.Avalonia.Command
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string AddSpecialKey(KeyWithModifiers key, string currentText, bool wasCtrlOrAlt)
|
private static string AddSpecialKey(KeyConfig key, string currentText, bool wasCtrlOrAlt)
|
||||||
{
|
{
|
||||||
var s = "";
|
var s = "";
|
||||||
|
|
||||||
@@ -77,3 +77,4 @@ namespace FileTime.Avalonia.Command
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using FileTime.App.Core.Command;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Configuration
|
||||||
|
{
|
||||||
|
public class CommandBindingConfiguration
|
||||||
|
{
|
||||||
|
public List<KeyConfig> Keys { get; set; } = new List<KeyConfig>();
|
||||||
|
|
||||||
|
public Commands Command { get; set; } = Commands.None;
|
||||||
|
|
||||||
|
public string KeysDisplayText => GetKeysDisplayText();
|
||||||
|
|
||||||
|
public CommandBindingConfiguration() { }
|
||||||
|
|
||||||
|
public CommandBindingConfiguration(Commands command, IEnumerable<KeyConfig> keys)
|
||||||
|
{
|
||||||
|
Keys = new List<KeyConfig>(keys);
|
||||||
|
Command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBindingConfiguration(Commands command, KeyConfig key)
|
||||||
|
{
|
||||||
|
Keys = new List<KeyConfig>() { key };
|
||||||
|
Command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBindingConfiguration(Commands command, IEnumerable<Key> keys)
|
||||||
|
{
|
||||||
|
Keys = keys.Select(k => new KeyConfig(k)).ToList();
|
||||||
|
Command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandBindingConfiguration(Commands command, Key key)
|
||||||
|
{
|
||||||
|
Keys = new List<KeyConfig>() { new KeyConfig(key) };
|
||||||
|
Command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetKeysDisplayText()
|
||||||
|
{
|
||||||
|
var s = "";
|
||||||
|
|
||||||
|
foreach (var k in Keys)
|
||||||
|
{
|
||||||
|
var keyString = k.Key.ToString();
|
||||||
|
|
||||||
|
if (keyString.Length == 1)
|
||||||
|
{
|
||||||
|
s += AddKeyWithCtrlOrAlt(k, s, (_, _, _) => k.Shift ? keyString.ToUpper() : keyString.ToLower());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s += AddKeyWithCtrlOrAlt(k, s, AddSpecialKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string AddKeyWithCtrlOrAlt(KeyConfig key, string currentText, Func<KeyConfig, string, bool, string> keyProcessor)
|
||||||
|
{
|
||||||
|
var s = "";
|
||||||
|
|
||||||
|
bool ctrlOrAlt = key.Ctrl || key.Alt;
|
||||||
|
|
||||||
|
if (ctrlOrAlt && currentText.Length > 0 && currentText.Last() != ' ') s += " ";
|
||||||
|
|
||||||
|
if (key.Ctrl) s += "CTRL+";
|
||||||
|
if (key.Alt) s += "ALT+";
|
||||||
|
s += keyProcessor(key, currentText, ctrlOrAlt);
|
||||||
|
|
||||||
|
if (ctrlOrAlt) s += " ";
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string AddSpecialKey(KeyConfig key, string currentText, bool wasCtrlOrAlt)
|
||||||
|
{
|
||||||
|
var s = "";
|
||||||
|
|
||||||
|
if (currentText.Length > 0 && currentText.Last() != ' ' && !wasCtrlOrAlt) s += " ";
|
||||||
|
s += key.Key.ToString();
|
||||||
|
if (!wasCtrlOrAlt) s += " ";
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Configuration
|
||||||
|
{
|
||||||
|
public class KeyBindingConfiguration
|
||||||
|
{
|
||||||
|
public bool UseDefaultBindings { get; set; } = true;
|
||||||
|
public List<CommandBindingConfiguration> DefaultKeyBindings { get; set; } = new();
|
||||||
|
public List<CommandBindingConfiguration> KeyBindings { get; set; } = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/GuiApp/FileTime.Avalonia/Configuration/KeyConfig.cs
Normal file
22
src/GuiApp/FileTime.Avalonia/Configuration/KeyConfig.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using Avalonia.Input;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Configuration
|
||||||
|
{
|
||||||
|
public class KeyConfig
|
||||||
|
{
|
||||||
|
public Key Key { get; set; }
|
||||||
|
public bool Shift { get; set; }
|
||||||
|
public bool Alt { get; set; }
|
||||||
|
public bool Ctrl { get; set; }
|
||||||
|
|
||||||
|
public KeyConfig() { }
|
||||||
|
|
||||||
|
public KeyConfig(Key key, bool shift = false, bool alt = false, bool ctrl = false)
|
||||||
|
{
|
||||||
|
Key = key;
|
||||||
|
Shift = shift;
|
||||||
|
Alt = alt;
|
||||||
|
Ctrl = ctrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,101 @@
|
|||||||
|
using Avalonia.Input;
|
||||||
|
using FileTime.App.Core.Command;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace FileTime.Avalonia.Configuration
|
namespace FileTime.Avalonia.Configuration
|
||||||
{
|
{
|
||||||
public static class MainConfiguration
|
public static class MainConfiguration
|
||||||
{
|
{
|
||||||
public static readonly Dictionary<string, string> Configuration = new();
|
private static readonly Lazy<List<CommandBindingConfiguration>> _defaultKeybindings = new(InitDefaultKeyBindings);
|
||||||
|
internal const string KeybindingBaseConfigKey = "KeyBindings";
|
||||||
|
|
||||||
|
public static Dictionary<string, string> Configuration { get; }
|
||||||
|
|
||||||
|
static MainConfiguration()
|
||||||
|
{
|
||||||
|
Configuration = new();
|
||||||
|
PopulateDefaultKeyBindings(Configuration, _defaultKeybindings.Value, KeybindingBaseConfigKey + ":" + nameof(KeyBindingConfiguration.DefaultKeyBindings));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PopulateDefaultKeyBindings(Dictionary<string, string> keybindings, List<CommandBindingConfiguration> commandBindingConfigs, string basePath)
|
||||||
|
{
|
||||||
|
for (var i = 0; i < commandBindingConfigs.Count; i++)
|
||||||
|
{
|
||||||
|
var baseKey = basePath + $":[{i}]:";
|
||||||
|
var commandBindingConfig = commandBindingConfigs[i];
|
||||||
|
keybindings.Add(baseKey + nameof(CommandBindingConfiguration.Command), commandBindingConfig.Command.ToString());
|
||||||
|
|
||||||
|
for (var j = 0; j < commandBindingConfig.Keys.Count; j++)
|
||||||
|
{
|
||||||
|
var key = commandBindingConfig.Keys[j];
|
||||||
|
var keyBaseKey = baseKey + $"keys:[{j}]:";
|
||||||
|
keybindings.Add(keyBaseKey + nameof(KeyConfig.Key), key.Key.ToString());
|
||||||
|
keybindings.Add(keyBaseKey + nameof(KeyConfig.Shift), key.Shift.ToString());
|
||||||
|
keybindings.Add(keyBaseKey + nameof(KeyConfig.Alt), key.Alt.ToString());
|
||||||
|
keybindings.Add(keyBaseKey + nameof(KeyConfig.Ctrl), key.Ctrl.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<CommandBindingConfiguration> InitDefaultKeyBindings()
|
||||||
|
{
|
||||||
|
return new List<CommandBindingConfiguration>()
|
||||||
|
{
|
||||||
|
new CommandBindingConfiguration(Commands.AutoRefresh, new KeyConfig(Key.R, shift: true)),
|
||||||
|
new CommandBindingConfiguration(Commands.ChangeTimelineMode, new[] { Key.T, Key.M }),
|
||||||
|
new CommandBindingConfiguration(Commands.CloseTab, Key.Q),
|
||||||
|
new CommandBindingConfiguration(Commands.Copy, new[] { Key.Y, Key.Y }),
|
||||||
|
new CommandBindingConfiguration(Commands.CopyPath, new[] { Key.C, Key.P }),
|
||||||
|
new CommandBindingConfiguration(Commands.CreateContainer, Key.F7),
|
||||||
|
new CommandBindingConfiguration(Commands.CreateContainer, new[] { Key.C, Key.C }),
|
||||||
|
new CommandBindingConfiguration(Commands.CreateElement, new[] { Key.C, Key.E }),
|
||||||
|
new CommandBindingConfiguration(Commands.Cut, new[] { Key.D, Key.D }),
|
||||||
|
new CommandBindingConfiguration(Commands.EnterRapidTravel, new KeyConfig(Key.OemComma, shift: true)),
|
||||||
|
new CommandBindingConfiguration(Commands.GoToHome, new[] { Key.G, Key.H }),
|
||||||
|
new CommandBindingConfiguration(Commands.GoToPath, new KeyConfig(Key.OemComma, ctrl: true)),
|
||||||
|
new CommandBindingConfiguration(Commands.GoToPath, new[] { Key.G, Key.P }),
|
||||||
|
new CommandBindingConfiguration(Commands.GoToProvider, new[] { Key.G, Key.T }),
|
||||||
|
new CommandBindingConfiguration(Commands.GoToRoot, new[] { Key.G, Key.R }),
|
||||||
|
new CommandBindingConfiguration(Commands.HardDelete, new[] { new KeyConfig(Key.D,shift: true), new KeyConfig(Key.D, shift: true) }),
|
||||||
|
new CommandBindingConfiguration(Commands.Mark, Key.Space),
|
||||||
|
new CommandBindingConfiguration(Commands.MoveToLast, new KeyConfig(Key.G, shift: true)),
|
||||||
|
new CommandBindingConfiguration(Commands.MoveToFirst, new[] { Key.G, Key.G }),
|
||||||
|
new CommandBindingConfiguration(Commands.NextTimelineBlock, Key.L ),
|
||||||
|
new CommandBindingConfiguration(Commands.NextTimelineCommand, Key.J ),
|
||||||
|
new CommandBindingConfiguration(Commands.OpenInFileBrowser, new[] { Key.O, Key.E }),
|
||||||
|
new CommandBindingConfiguration(Commands.PasteMerge, new[] { Key.P, Key.P }),
|
||||||
|
new CommandBindingConfiguration(Commands.PasteOverwrite, new[] { Key.P, Key.O }),
|
||||||
|
new CommandBindingConfiguration(Commands.PasteSkip, new[] { Key.P, Key.S }),
|
||||||
|
new CommandBindingConfiguration(Commands.PreviousTimelineBlock, Key.H ),
|
||||||
|
new CommandBindingConfiguration(Commands.PreviousTimelineCommand, Key.K ),
|
||||||
|
new CommandBindingConfiguration(Commands.Refresh, Key.R),
|
||||||
|
new CommandBindingConfiguration(Commands.Rename, Key.F2),
|
||||||
|
new CommandBindingConfiguration(Commands.Rename, new[] { Key.C, Key.W }),
|
||||||
|
new CommandBindingConfiguration(Commands.RunCommand, new KeyConfig(Key.D4, shift: true)),
|
||||||
|
new CommandBindingConfiguration(Commands.ShowAllShotcut, Key.F1),
|
||||||
|
new CommandBindingConfiguration(Commands.SoftDelete, new[] { new KeyConfig(Key.D), new KeyConfig(Key.D, shift: true) }),
|
||||||
|
new CommandBindingConfiguration(Commands.SwitchToLastTab, Key.D9),
|
||||||
|
new CommandBindingConfiguration(Commands.SwitchToTab1, Key.D1),
|
||||||
|
new CommandBindingConfiguration(Commands.SwitchToTab2, Key.D2),
|
||||||
|
new CommandBindingConfiguration(Commands.SwitchToTab3, Key.D3),
|
||||||
|
new CommandBindingConfiguration(Commands.SwitchToTab4, Key.D4),
|
||||||
|
new CommandBindingConfiguration(Commands.SwitchToTab5, Key.D5),
|
||||||
|
new CommandBindingConfiguration(Commands.SwitchToTab6, Key.D6),
|
||||||
|
new CommandBindingConfiguration(Commands.SwitchToTab7, Key.D7),
|
||||||
|
new CommandBindingConfiguration(Commands.SwitchToTab8, Key.D8),
|
||||||
|
new CommandBindingConfiguration(Commands.TimelinePause, new[] { Key.T, Key.P }),
|
||||||
|
new CommandBindingConfiguration(Commands.TimelineRefresh, new[] { Key.T, Key.R }),
|
||||||
|
new CommandBindingConfiguration(Commands.TimelineStart, new[] { Key.T, Key.S }),
|
||||||
|
new CommandBindingConfiguration(Commands.ToggleAdvancedIcons, new[] { Key.Z, Key.I }),
|
||||||
|
new CommandBindingConfiguration(Commands.GoUp, Key.Left),
|
||||||
|
new CommandBindingConfiguration(Commands.Open, Key.Right),
|
||||||
|
new CommandBindingConfiguration(Commands.OpenOrRun, Key.Enter),
|
||||||
|
new CommandBindingConfiguration(Commands.MoveCursorUp, Key.Up),
|
||||||
|
new CommandBindingConfiguration(Commands.MoveCursorDown, Key.Down),
|
||||||
|
new CommandBindingConfiguration(Commands.MoveCursorUpPage, Key.PageUp),
|
||||||
|
new CommandBindingConfiguration(Commands.MoveCursorDownPage, Key.PageDown),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using Avalonia.Data.Converters;
|
||||||
|
using FileTime.App.Core.Command;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Converters
|
||||||
|
{
|
||||||
|
public class CommandToCommandNameConverter : IValueConverter
|
||||||
|
{
|
||||||
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if(value is not Commands command) return value;
|
||||||
|
|
||||||
|
//TODO: implement
|
||||||
|
return command.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using Avalonia.Input;
|
|
||||||
|
|
||||||
namespace FileTime.Avalonia.Misc
|
|
||||||
{
|
|
||||||
public class KeyWithModifiers
|
|
||||||
{
|
|
||||||
public Key Key { get; }
|
|
||||||
|
|
||||||
public bool? Alt { get; }
|
|
||||||
public bool? Shift { get; }
|
|
||||||
public bool? Ctrl { get; }
|
|
||||||
|
|
||||||
public KeyWithModifiers(Key key, bool alt = false, bool shift = false, bool ctrl = false)
|
|
||||||
{
|
|
||||||
Key = key;
|
|
||||||
Alt = alt;
|
|
||||||
Shift = shift;
|
|
||||||
Ctrl = ctrl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
783
src/GuiApp/FileTime.Avalonia/Services/CommandHandlerService.cs
Normal file
783
src/GuiApp/FileTime.Avalonia/Services/CommandHandlerService.cs
Normal file
@@ -0,0 +1,783 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using FileTime.App.Core.Clipboard;
|
||||||
|
using FileTime.App.Core.Command;
|
||||||
|
using FileTime.Avalonia.Application;
|
||||||
|
using FileTime.Avalonia.IconProviders;
|
||||||
|
using FileTime.Avalonia.Misc;
|
||||||
|
using FileTime.Avalonia.ViewModels;
|
||||||
|
using FileTime.Core.Command;
|
||||||
|
using FileTime.Core.Components;
|
||||||
|
using FileTime.Core.Interactions;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Providers;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
using FileTime.Providers.Local;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Services
|
||||||
|
{
|
||||||
|
public class CommandHandlerService
|
||||||
|
{
|
||||||
|
private bool _addCommandToNextBatch;
|
||||||
|
|
||||||
|
private readonly AppState _appState;
|
||||||
|
private readonly LocalContentProvider _localContentProvider;
|
||||||
|
private readonly ItemNameConverterService _itemNameConverterService;
|
||||||
|
private readonly DialogService _dialogService;
|
||||||
|
private readonly IClipboard _clipboard;
|
||||||
|
private readonly TimeRunner _timeRunner;
|
||||||
|
private readonly IIconProvider _iconProvider;
|
||||||
|
private readonly IEnumerable<IContentProvider> _contentProviders;
|
||||||
|
private readonly Dictionary<Commands, Func<Task>> _commandHandlers;
|
||||||
|
|
||||||
|
public CommandHandlerService(
|
||||||
|
AppState appState,
|
||||||
|
LocalContentProvider localContentProvider,
|
||||||
|
ItemNameConverterService itemNameConverterService,
|
||||||
|
DialogService dialogService,
|
||||||
|
IClipboard clipboard,
|
||||||
|
TimeRunner timeRunner,
|
||||||
|
IIconProvider iconProvider,
|
||||||
|
IEnumerable<IContentProvider> contentProviders)
|
||||||
|
{
|
||||||
|
_appState = appState;
|
||||||
|
_localContentProvider = localContentProvider;
|
||||||
|
_itemNameConverterService = itemNameConverterService;
|
||||||
|
_dialogService = dialogService;
|
||||||
|
_clipboard = clipboard;
|
||||||
|
_timeRunner = timeRunner;
|
||||||
|
_iconProvider = iconProvider;
|
||||||
|
_contentProviders = contentProviders;
|
||||||
|
|
||||||
|
_commandHandlers = new Dictionary<Commands, Func<Task>>
|
||||||
|
{
|
||||||
|
{Commands.AutoRefresh, ToggleAutoRefresh},
|
||||||
|
{Commands.ChangeTimelineMode, ChangeTimelineMode},
|
||||||
|
{Commands.CloseTab, CloseTab},
|
||||||
|
{Commands.Copy, Copy},
|
||||||
|
{Commands.CopyPath, CopyPath},
|
||||||
|
{Commands.CreateContainer, CreateContainer},
|
||||||
|
{Commands.CreateElement, CreateElement},
|
||||||
|
{Commands.Cut, Cut},
|
||||||
|
{Commands.EnterRapidTravel, EnterRapidTravelMode},
|
||||||
|
{Commands.GoToHome, GotToHome},
|
||||||
|
{Commands.GoToPath, GoToContainer},
|
||||||
|
{Commands.GoToProvider, GotToProvider},
|
||||||
|
{Commands.GoToRoot, GotToRoot},
|
||||||
|
{Commands.GoUp, GoUp},
|
||||||
|
{Commands.HardDelete, HardDelete},
|
||||||
|
{Commands.Mark, MarkCurrentItem},
|
||||||
|
{Commands.MoveCursorDown, MoveCursorDown},
|
||||||
|
{Commands.MoveCursorDownPage, MoveCursorDownPage},
|
||||||
|
{Commands.MoveCursorUp, MoveCursorUp},
|
||||||
|
{Commands.MoveCursorUpPage, MoveCursorUpPage},
|
||||||
|
{Commands.MoveToFirst, MoveToFirst},
|
||||||
|
{Commands.MoveToLast, MoveToLast},
|
||||||
|
{Commands.NextTimelineBlock, SelectNextTimelineBlock},
|
||||||
|
{Commands.NextTimelineCommand, SelectNextTimelineCommand},
|
||||||
|
{Commands.Open, OpenContainer},
|
||||||
|
{Commands.OpenInFileBrowser, OpenInDefaultFileExplorer},
|
||||||
|
{Commands.OpenOrRun, OpenOrRun},
|
||||||
|
{Commands.PasteMerge, PasteMerge},
|
||||||
|
{Commands.PasteOverwrite, PasteOverwrite},
|
||||||
|
{Commands.PasteSkip, PasteSkip},
|
||||||
|
{Commands.PreviousTimelineBlock, SelectPreviousTimelineBlock},
|
||||||
|
{Commands.PreviousTimelineCommand, SelectPreviousTimelineCommand},
|
||||||
|
{Commands.Refresh, RefreshCurrentLocation},
|
||||||
|
{Commands.Rename, Rename},
|
||||||
|
{Commands.RunCommand, RunCommandInContainer},
|
||||||
|
{Commands.ShowAllShotcut, ShowAllShortcut},
|
||||||
|
{Commands.SoftDelete, SoftDelete},
|
||||||
|
{Commands.SwitchToLastTab, async() => await SwitchToTab(-1)},
|
||||||
|
{Commands.SwitchToTab1, async() => await SwitchToTab(1)},
|
||||||
|
{Commands.SwitchToTab2, async() => await SwitchToTab(2)},
|
||||||
|
{Commands.SwitchToTab3, async() => await SwitchToTab(3)},
|
||||||
|
{Commands.SwitchToTab4, async() => await SwitchToTab(4)},
|
||||||
|
{Commands.SwitchToTab5, async() => await SwitchToTab(5)},
|
||||||
|
{Commands.SwitchToTab6, async() => await SwitchToTab(6)},
|
||||||
|
{Commands.SwitchToTab7, async() => await SwitchToTab(7)},
|
||||||
|
{Commands.SwitchToTab8, async() => await SwitchToTab(8)},
|
||||||
|
{Commands.TimelinePause, PauseTimeline},
|
||||||
|
{Commands.TimelineRefresh, RefreshTimeline},
|
||||||
|
{Commands.TimelineStart, ContinueTimeline},
|
||||||
|
{Commands.ToggleAdvancedIcons, ToggleAdvancedIcons},
|
||||||
|
{Commands.ToggleHidden, ToggleHidden},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task HandleCommandAsync(Commands command) =>
|
||||||
|
await _commandHandlers[command].Invoke();
|
||||||
|
|
||||||
|
private async Task OpenContainer()
|
||||||
|
{
|
||||||
|
_appState.RapidTravelText = "";
|
||||||
|
await _appState.SelectedTab.Open();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OpenContainer(IContainer container)
|
||||||
|
{
|
||||||
|
_appState.RapidTravelText = "";
|
||||||
|
await _appState.SelectedTab.OpenContainer(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OpenOrRun()
|
||||||
|
{
|
||||||
|
if (_appState.SelectedTab.SelectedItem is ContainerViewModel)
|
||||||
|
{
|
||||||
|
await OpenContainer();
|
||||||
|
}
|
||||||
|
else if (_appState.SelectedTab.SelectedItem is ElementViewModel elementViewModel && elementViewModel.Element is LocalFile localFile)
|
||||||
|
{
|
||||||
|
Process.Start(new ProcessStartInfo(localFile.File.FullName) { UseShellExecute = true });
|
||||||
|
|
||||||
|
if (_appState.ViewMode == ViewMode.RapidTravel)
|
||||||
|
{
|
||||||
|
await _appState.ExitRapidTravelMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GoUp()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.GoUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task MoveCursorUp()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.MoveCursorUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task MoveCursorDown()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.MoveCursorDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task MoveCursorUpPage()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.MoveCursorUpPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task MoveCursorDownPage()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.MoveCursorDownPage();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task MoveToFirst()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.MoveCursorToFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task MoveToLast()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.MoveCursorToLast();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GotToProvider()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.GotToProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GotToRoot()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.GotToRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GotToHome()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.GotToHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task EnterRapidTravelMode()
|
||||||
|
{
|
||||||
|
_appState.ViewMode = ViewMode.RapidTravel;
|
||||||
|
|
||||||
|
_appState.PreviousKeys.Clear();
|
||||||
|
_appState.PossibleCommands = new();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SwitchToTab(int number)
|
||||||
|
{
|
||||||
|
var tabContainer = _appState.Tabs.FirstOrDefault(t => t.TabNumber == number);
|
||||||
|
|
||||||
|
if (number == -1)
|
||||||
|
{
|
||||||
|
var greatestNumber = _appState.Tabs.Max(t => t.TabNumber);
|
||||||
|
tabContainer = _appState.Tabs.FirstOrDefault(t => t.TabNumber == greatestNumber);
|
||||||
|
}
|
||||||
|
else if (tabContainer == null)
|
||||||
|
{
|
||||||
|
var newContainer = await _appState.SelectedTab.CurrentLocation.Container.Clone();
|
||||||
|
|
||||||
|
var newTab = new Tab();
|
||||||
|
await newTab.Init(newContainer);
|
||||||
|
|
||||||
|
tabContainer = new TabContainer(newTab, _localContentProvider, _itemNameConverterService);
|
||||||
|
await tabContainer.Init(number);
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
for (i = 0; i < _appState.Tabs.Count; i++)
|
||||||
|
{
|
||||||
|
if (_appState.Tabs[i].TabNumber > number) break;
|
||||||
|
}
|
||||||
|
_appState.Tabs.Insert(i, tabContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_appState.ViewMode == ViewMode.RapidTravel)
|
||||||
|
{
|
||||||
|
await _appState.ExitRapidTravelMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
_appState.SelectedTab = tabContainer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CloseTab()
|
||||||
|
{
|
||||||
|
var tabs = _appState.Tabs;
|
||||||
|
if (tabs.Count > 1)
|
||||||
|
{
|
||||||
|
var currentTab = tabs.FirstOrDefault(t => t == _appState.SelectedTab);
|
||||||
|
|
||||||
|
if (currentTab != null)
|
||||||
|
{
|
||||||
|
tabs.Remove(currentTab);
|
||||||
|
var tabNumber = tabs[0].TabNumber;
|
||||||
|
for (var i = 0; i < tabs.Count; i++)
|
||||||
|
{
|
||||||
|
tabNumber = tabs[i].TabNumber;
|
||||||
|
if (tabs[i].TabNumber > currentTab.TabNumber) break;
|
||||||
|
}
|
||||||
|
await SwitchToTab(tabNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task CreateContainer()
|
||||||
|
{
|
||||||
|
var handler = async (List<InputElementWrapper> inputs) =>
|
||||||
|
{
|
||||||
|
var container = _appState.SelectedTab.CurrentLocation.Container;
|
||||||
|
var createContainerCommand = new CreateContainerCommand(new AbsolutePath(container), inputs[0].Value);
|
||||||
|
await AddCommand(createContainerCommand);
|
||||||
|
};
|
||||||
|
|
||||||
|
_dialogService.ReadInputs(new List<InputElement>() { new InputElement("Container name", InputType.Text) }, handler);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task CreateElement()
|
||||||
|
{
|
||||||
|
var handler = async (List<InputElementWrapper> inputs) =>
|
||||||
|
{
|
||||||
|
var container = _appState.SelectedTab.CurrentLocation.Container;
|
||||||
|
var createElementCommand = new CreateElementCommand(new AbsolutePath(container), inputs[0].Value);
|
||||||
|
await AddCommand(createElementCommand);
|
||||||
|
};
|
||||||
|
|
||||||
|
_dialogService.ReadInputs(new List<InputElement>() { new InputElement("Element name", InputType.Text) }, handler);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task MarkCurrentItem()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.MarkCurrentItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Copy()
|
||||||
|
{
|
||||||
|
_clipboard.Clear();
|
||||||
|
_clipboard.SetCommand<CopyCommand>();
|
||||||
|
|
||||||
|
var currentSelectedItems = await _appState.SelectedTab.TabState.GetCurrentMarkedItems();
|
||||||
|
if (currentSelectedItems.Count > 0)
|
||||||
|
{
|
||||||
|
foreach (var selectedItem in currentSelectedItems)
|
||||||
|
{
|
||||||
|
_clipboard.AddContent(selectedItem);
|
||||||
|
}
|
||||||
|
await _appState.SelectedTab.TabState.ClearCurrentMarkedItems();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var currentSelectedItem = _appState.SelectedTab.SelectedItem?.Item;
|
||||||
|
if (currentSelectedItem != null)
|
||||||
|
{
|
||||||
|
_clipboard.AddContent(new AbsolutePath(currentSelectedItem));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Cut()
|
||||||
|
{
|
||||||
|
_clipboard.Clear();
|
||||||
|
_clipboard.SetCommand<MoveCommand>();
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SoftDelete() => await Delete(false);
|
||||||
|
|
||||||
|
private async Task HardDelete() => await Delete(true);
|
||||||
|
|
||||||
|
public async Task Delete(bool hardDelete = false)
|
||||||
|
{
|
||||||
|
IList<AbsolutePath>? itemsToDelete = null;
|
||||||
|
var askForDelete = false;
|
||||||
|
var questionText = "";
|
||||||
|
var shouldDelete = false;
|
||||||
|
var shouldClearMarkedItems = false;
|
||||||
|
|
||||||
|
var currentSelectedItems = await _appState.SelectedTab.TabState.GetCurrentMarkedItems();
|
||||||
|
var currentSelectedItem = _appState.SelectedTab.SelectedItem?.Item;
|
||||||
|
if (currentSelectedItems.Count > 0)
|
||||||
|
{
|
||||||
|
itemsToDelete = new List<AbsolutePath>(currentSelectedItems);
|
||||||
|
shouldClearMarkedItems = true;
|
||||||
|
|
||||||
|
//FIXME: check 'is Container'
|
||||||
|
if (currentSelectedItems.Count == 1)
|
||||||
|
{
|
||||||
|
if ((await currentSelectedItems[0].Resolve()) is IContainer container
|
||||||
|
&& (await container.GetItems())?.Count > 0)
|
||||||
|
{
|
||||||
|
askForDelete = true;
|
||||||
|
questionText = $"The container '{container.Name}' is not empty. Proceed with delete?";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shouldDelete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
askForDelete = true;
|
||||||
|
questionText = $"Are you sure you want to delete {itemsToDelete.Count} item?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (currentSelectedItem != null)
|
||||||
|
{
|
||||||
|
itemsToDelete = new List<AbsolutePath>()
|
||||||
|
{
|
||||||
|
new AbsolutePath(currentSelectedItem)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (currentSelectedItem is IContainer container && (await container.GetItems())?.Count > 0)
|
||||||
|
{
|
||||||
|
askForDelete = true;
|
||||||
|
questionText = $"The container '{container.Name}' is not empty. Proceed with delete?";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shouldDelete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemsToDelete?.Count > 0)
|
||||||
|
{
|
||||||
|
if (askForDelete)
|
||||||
|
{
|
||||||
|
_dialogService.ShowMessageBox(questionText, HandleDelete);
|
||||||
|
}
|
||||||
|
else if (shouldDelete)
|
||||||
|
{
|
||||||
|
await HandleDelete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task HandleDelete()
|
||||||
|
{
|
||||||
|
var deleteCommand = new DeleteCommand
|
||||||
|
{
|
||||||
|
HardDelete = hardDelete
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var itemToDelete in itemsToDelete!)
|
||||||
|
{
|
||||||
|
deleteCommand.ItemsToDelete.Add(itemToDelete);
|
||||||
|
}
|
||||||
|
|
||||||
|
await AddCommand(deleteCommand);
|
||||||
|
_clipboard.Clear();
|
||||||
|
if (shouldClearMarkedItems)
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.TabState.ClearCurrentMarkedItems();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PasteMerge()
|
||||||
|
{
|
||||||
|
await Paste(TransportMode.Merge);
|
||||||
|
}
|
||||||
|
private async Task PasteOverwrite()
|
||||||
|
{
|
||||||
|
await Paste(TransportMode.Overwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task PasteSkip()
|
||||||
|
{
|
||||||
|
await Paste(TransportMode.Skip);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Paste(TransportMode transportMode)
|
||||||
|
{
|
||||||
|
if (_clipboard.CommandType != null)
|
||||||
|
{
|
||||||
|
var command = (ITransportationCommand)Activator.CreateInstance(_clipboard.CommandType!)!;
|
||||||
|
command.TransportMode = transportMode;
|
||||||
|
|
||||||
|
command.Sources.Clear();
|
||||||
|
|
||||||
|
foreach (var item in _clipboard.Content)
|
||||||
|
{
|
||||||
|
command.Sources.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentLocation = _appState.SelectedTab.CurrentLocation.Container;
|
||||||
|
command.Target = currentLocation is VirtualContainer virtualContainer
|
||||||
|
? virtualContainer.BaseContainer
|
||||||
|
: currentLocation;
|
||||||
|
|
||||||
|
await AddCommand(command);
|
||||||
|
|
||||||
|
_clipboard.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task Rename()
|
||||||
|
{
|
||||||
|
var selectedItem = _appState.SelectedTab.SelectedItem?.Item;
|
||||||
|
if (selectedItem != null)
|
||||||
|
{
|
||||||
|
var handler = async (List<InputElementWrapper> inputs) =>
|
||||||
|
{
|
||||||
|
var renameCommand = new RenameCommand(new AbsolutePath(selectedItem), inputs[0].Value);
|
||||||
|
await AddCommand(renameCommand);
|
||||||
|
};
|
||||||
|
|
||||||
|
_dialogService.ReadInputs(new List<InputElement>() { new InputElement("New name", InputType.Text, selectedItem.Name) }, handler);
|
||||||
|
}
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RefreshCurrentLocation()
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.CurrentLocation.Container.RefreshAsync();
|
||||||
|
await _appState.SelectedTab.UpdateCurrentSelectedItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task PauseTimeline()
|
||||||
|
{
|
||||||
|
_timeRunner.EnableRunning = false;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ContinueTimeline()
|
||||||
|
{
|
||||||
|
_timeRunner.EnableRunning = true;
|
||||||
|
await _timeRunner.TryStartCommandRunner();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RefreshTimeline()
|
||||||
|
{
|
||||||
|
await _timeRunner.Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task ChangeTimelineMode()
|
||||||
|
{
|
||||||
|
_addCommandToNextBatch = !_addCommandToNextBatch;
|
||||||
|
_dialogService.ShowToastMessage("Timeline mode: " + (_addCommandToNextBatch ? "Continuous" : "Parallel"));
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task GoToContainer()
|
||||||
|
{
|
||||||
|
var handler = async (List<InputElementWrapper> inputs) =>
|
||||||
|
{
|
||||||
|
var path = inputs[0].Value;
|
||||||
|
foreach (var contentProvider in _contentProviders)
|
||||||
|
{
|
||||||
|
if (contentProvider.CanHandlePath(path))
|
||||||
|
{
|
||||||
|
var possibleContainer = await contentProvider.GetByPath(path);
|
||||||
|
if (possibleContainer is IContainer container)
|
||||||
|
{
|
||||||
|
await _appState.SelectedTab.OpenContainer(container);
|
||||||
|
}
|
||||||
|
//TODO: multiple possible content provider handler
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_dialogService.ReadInputs(new List<InputElement>() { new InputElement("Path", InputType.Text) }, handler);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task ToggleAdvancedIcons()
|
||||||
|
{
|
||||||
|
_iconProvider.EnableAdvancedIcons = !_iconProvider.EnableAdvancedIcons;
|
||||||
|
_dialogService.ShowToastMessage("Advanced icons are: " + (_iconProvider.EnableAdvancedIcons ? "ON" : "OFF"));
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task ToggleHidden()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task OpenInDefaultFileExplorer()
|
||||||
|
{
|
||||||
|
if (_appState.SelectedTab.CurrentLocation.Container is LocalFolder localFolder)
|
||||||
|
{
|
||||||
|
var path = localFolder.Directory.FullName;
|
||||||
|
if (path != null)
|
||||||
|
{
|
||||||
|
Process.Start("explorer.exe", "\"" + path + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task CopyPath()
|
||||||
|
{
|
||||||
|
string? textToCopy = null;
|
||||||
|
if (_appState.SelectedTab.CurrentLocation.Container is LocalFolder localFolder)
|
||||||
|
{
|
||||||
|
textToCopy = localFolder.Directory.FullName;
|
||||||
|
}
|
||||||
|
if (_appState.SelectedTab.CurrentLocation.Container is LocalFile localFile)
|
||||||
|
{
|
||||||
|
textToCopy = localFile.File.FullName;
|
||||||
|
}
|
||||||
|
else if (_appState.SelectedTab.CurrentLocation.Container.FullName is string fullName)
|
||||||
|
{
|
||||||
|
textToCopy = fullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textToCopy != null && global::Avalonia.Application.Current?.Clipboard is not null)
|
||||||
|
{
|
||||||
|
await global::Avalonia.Application.Current.Clipboard.SetTextAsync(textToCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task ShowAllShortcut()
|
||||||
|
{
|
||||||
|
_appState.IsAllShortcutVisible = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task RunCommandInContainer()
|
||||||
|
{
|
||||||
|
var handler = (List<InputElementWrapper> inputs) =>
|
||||||
|
{
|
||||||
|
var input = inputs[0].Value;
|
||||||
|
string? path = null;
|
||||||
|
string? arguments = null;
|
||||||
|
|
||||||
|
if (input.StartsWith("\""))
|
||||||
|
{
|
||||||
|
var pathEnd = input.IndexOf('\"', 1);
|
||||||
|
|
||||||
|
path = input.Substring(1, pathEnd);
|
||||||
|
arguments = input.Substring(pathEnd + 1).Trim();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var inputParts = input.Split(' ');
|
||||||
|
path = inputParts[0];
|
||||||
|
arguments = inputParts.Length > 1 ? string.Join(' ', inputParts[1..]).Trim() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(path))
|
||||||
|
{
|
||||||
|
using var process = new Process();
|
||||||
|
process.StartInfo.FileName = path;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(arguments))
|
||||||
|
{
|
||||||
|
process.StartInfo.Arguments = arguments;
|
||||||
|
}
|
||||||
|
if (_appState.SelectedTab.CurrentLocation.Container is LocalFolder localFolder)
|
||||||
|
{
|
||||||
|
process.StartInfo.WorkingDirectory = localFolder.Directory.FullName;
|
||||||
|
}
|
||||||
|
process.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
};
|
||||||
|
|
||||||
|
_dialogService.ReadInputs(new List<InputElement>() { new InputElement("Command", InputType.Text) }, handler);
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task SelectPreviousTimelineBlock()
|
||||||
|
{
|
||||||
|
var currentSelected = GetSelectedTimelineCommandOrSelectFirst();
|
||||||
|
if (currentSelected == null) return Task.CompletedTask;
|
||||||
|
|
||||||
|
ParallelCommandsViewModel? newBlockVM = null;
|
||||||
|
ParallelCommandsViewModel? previousBlockVM = null;
|
||||||
|
|
||||||
|
foreach (var timelineBlock in _appState.TimelineCommands)
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach (var command in timelineBlock.ParallelCommands)
|
||||||
|
{
|
||||||
|
if (command.IsSelected)
|
||||||
|
{
|
||||||
|
newBlockVM = previousBlockVM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previousBlockVM = timelineBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newBlockVM == null) return Task.CompletedTask;
|
||||||
|
|
||||||
|
foreach (var val in _appState.TimelineCommands.Select(t => t.ParallelCommands.Select((c, i) => (ParalellCommandVM: t, CommandVM: c, Index: i))).SelectMany(t => t))
|
||||||
|
{
|
||||||
|
val.CommandVM.IsSelected = val.ParalellCommandVM == newBlockVM && val.Index == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task SelectNextTimelineCommand()
|
||||||
|
{
|
||||||
|
var currentSelected = GetSelectedTimelineCommandOrSelectFirst();
|
||||||
|
if (currentSelected == null) return Task.CompletedTask;
|
||||||
|
|
||||||
|
ParallelCommandViewModel? lastCommand = null;
|
||||||
|
var any = false;
|
||||||
|
foreach (var command in _appState.TimelineCommands.SelectMany(t => t.ParallelCommands))
|
||||||
|
{
|
||||||
|
var isSelected = lastCommand == currentSelected;
|
||||||
|
command.IsSelected = isSelected;
|
||||||
|
any = any || isSelected;
|
||||||
|
lastCommand = command;
|
||||||
|
}
|
||||||
|
if (!any && lastCommand != null) lastCommand.IsSelected = true;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task SelectPreviousTimelineCommand()
|
||||||
|
{
|
||||||
|
var currentSelected = GetSelectedTimelineCommandOrSelectFirst();
|
||||||
|
if (currentSelected == null) return Task.CompletedTask;
|
||||||
|
|
||||||
|
ParallelCommandViewModel? lastCommand = null;
|
||||||
|
foreach (var command in _appState.TimelineCommands.SelectMany(t => t.ParallelCommands))
|
||||||
|
{
|
||||||
|
if (lastCommand != null)
|
||||||
|
{
|
||||||
|
lastCommand.IsSelected = command == currentSelected;
|
||||||
|
}
|
||||||
|
lastCommand = command;
|
||||||
|
}
|
||||||
|
if (lastCommand != null) lastCommand.IsSelected = false;
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task SelectNextTimelineBlock()
|
||||||
|
{
|
||||||
|
var currentSelected = GetSelectedTimelineCommandOrSelectFirst();
|
||||||
|
if (currentSelected == null) return Task.CompletedTask;
|
||||||
|
|
||||||
|
ParallelCommandsViewModel? newBlockVM = null;
|
||||||
|
var select = false;
|
||||||
|
foreach (var timelineBlock in _appState.TimelineCommands)
|
||||||
|
{
|
||||||
|
if (select)
|
||||||
|
{
|
||||||
|
newBlockVM = timelineBlock;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
foreach (var command in timelineBlock.ParallelCommands)
|
||||||
|
{
|
||||||
|
if (command.IsSelected)
|
||||||
|
{
|
||||||
|
select = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newBlockVM == null) return Task.CompletedTask;
|
||||||
|
|
||||||
|
foreach (var val in _appState.TimelineCommands.Select(t => t.ParallelCommands.Select((c, i) => (ParalellCommandVM: t, CommandVM: c, Index: i))).SelectMany(t => t))
|
||||||
|
{
|
||||||
|
val.CommandVM.IsSelected = val.ParalellCommandVM == newBlockVM && val.Index == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ParallelCommandViewModel? GetSelectedTimelineCommandOrSelectFirst()
|
||||||
|
{
|
||||||
|
var currentSelected = _appState.TimelineCommands.SelectMany(t => t.ParallelCommands).FirstOrDefault(c => c.IsSelected);
|
||||||
|
if (currentSelected != null) return currentSelected;
|
||||||
|
|
||||||
|
var firstCommand = _appState.TimelineCommands.SelectMany(t => t.ParallelCommands).FirstOrDefault();
|
||||||
|
if (firstCommand != null)
|
||||||
|
{
|
||||||
|
firstCommand.IsSelected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AddCommand(ICommand command)
|
||||||
|
{
|
||||||
|
if (_addCommandToNextBatch)
|
||||||
|
{
|
||||||
|
await _timeRunner.AddCommand(command, toNewBatch: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ParallelCommandsViewModel? batchToAdd = null;
|
||||||
|
foreach (var val in _appState.TimelineCommands.Select(t => t.ParallelCommands.Select(c => (ParalellCommandVM: t, CommandVM: c))).SelectMany(t => t))
|
||||||
|
{
|
||||||
|
if (val.CommandVM.IsSelected)
|
||||||
|
{
|
||||||
|
batchToAdd = val.ParalellCommandVM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (batchToAdd != null)
|
||||||
|
{
|
||||||
|
await _timeRunner.AddCommand(command, batchToAdd.Id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _timeRunner.AddCommand(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Task ToggleAutoRefresh()
|
||||||
|
{
|
||||||
|
var tab = _appState.SelectedTab.TabState.Tab;
|
||||||
|
tab.AutoRefresh = !tab.AutoRefresh;
|
||||||
|
|
||||||
|
_dialogService.ShowToastMessage("Auto refresh is: " + (tab.AutoRefresh ? "ON" : "OFF"));
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
105
src/GuiApp/FileTime.Avalonia/Services/DialogService.cs
Normal file
105
src/GuiApp/FileTime.Avalonia/Services/DialogService.cs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using FileTime.Avalonia.Application;
|
||||||
|
using FileTime.Avalonia.Misc;
|
||||||
|
using FileTime.Core.Interactions;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Services
|
||||||
|
{
|
||||||
|
public class DialogService
|
||||||
|
{
|
||||||
|
private readonly AppState _appState;
|
||||||
|
|
||||||
|
private Func<List<InputElementWrapper>, Task>? _inputHandler;
|
||||||
|
|
||||||
|
public DialogService(AppState appState)
|
||||||
|
{
|
||||||
|
_appState = appState;
|
||||||
|
}
|
||||||
|
public void ReadInputs(List<InputElement> inputs, Action<List<InputElementWrapper>> inputHandler) =>
|
||||||
|
ReadInputs(inputs, (inputs) => { inputHandler(inputs); return Task.CompletedTask; });
|
||||||
|
|
||||||
|
public void ReadInputs(List<InputElement> inputs, Func<List<InputElementWrapper>, Task> inputHandler)
|
||||||
|
{
|
||||||
|
_appState.Inputs = inputs.ConvertAll(i => new InputElementWrapper(i, i.DefaultValue));
|
||||||
|
_inputHandler = inputHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string?[]> ReadInputs(IEnumerable<InputElement> fields)
|
||||||
|
{
|
||||||
|
var waiting = true;
|
||||||
|
var result = Array.Empty<string>();
|
||||||
|
ReadInputs(fields.ToList(), (inputs) =>
|
||||||
|
{
|
||||||
|
if (inputs != null)
|
||||||
|
{
|
||||||
|
result = inputs.Select(i => i.Value).ToArray();
|
||||||
|
}
|
||||||
|
waiting = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
while (waiting) await Task.Delay(100);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearInputs()
|
||||||
|
{
|
||||||
|
_appState.Inputs = null;
|
||||||
|
_inputHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ProcessInputs()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (_inputHandler != null)
|
||||||
|
{
|
||||||
|
await _inputHandler.Invoke(_appState.Inputs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
ClearInputs();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelInputs()
|
||||||
|
{
|
||||||
|
ClearInputs();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowMessageBox(string text, Func<Task> inputHandler)
|
||||||
|
{
|
||||||
|
_appState.MessageBoxText = text;
|
||||||
|
_inputHandler = async (_) => await inputHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProcessMessageBox()
|
||||||
|
{
|
||||||
|
_inputHandler?.Invoke(null!);
|
||||||
|
|
||||||
|
_appState.MessageBoxText = null;
|
||||||
|
_inputHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CancelMessageBox()
|
||||||
|
{
|
||||||
|
_appState.MessageBoxText = null;
|
||||||
|
_inputHandler = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowToastMessage(string text)
|
||||||
|
{
|
||||||
|
_appState.PopupTexts.Add(text);
|
||||||
|
|
||||||
|
Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await Task.Delay(5000);
|
||||||
|
await Dispatcher.UIThread.InvokeAsync(() => _appState.PopupTexts.Remove(text));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
215
src/GuiApp/FileTime.Avalonia/Services/KeyInputHandlerService.cs
Normal file
215
src/GuiApp/FileTime.Avalonia/Services/KeyInputHandlerService.cs
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using FileTime.Avalonia.Application;
|
||||||
|
using FileTime.Avalonia.Configuration;
|
||||||
|
using FileTime.Avalonia.ViewModels;
|
||||||
|
using FileTime.Core.Extensions;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Services
|
||||||
|
{
|
||||||
|
public class KeyInputHandlerService
|
||||||
|
{
|
||||||
|
private readonly List<KeyConfig[]> _keysToSkip = new();
|
||||||
|
private readonly AppState _appState;
|
||||||
|
private readonly KeyboardConfigurationService _keyboardConfigurationService;
|
||||||
|
private readonly CommandHandlerService _commandHandlerService;
|
||||||
|
private readonly DialogService _dialogService;
|
||||||
|
|
||||||
|
public KeyInputHandlerService(
|
||||||
|
AppState appState,
|
||||||
|
KeyboardConfigurationService keyboardConfigurationService,
|
||||||
|
CommandHandlerService commandHandlerService,
|
||||||
|
DialogService dialogService)
|
||||||
|
{
|
||||||
|
_appState = appState;
|
||||||
|
_keyboardConfigurationService = keyboardConfigurationService;
|
||||||
|
_commandHandlerService = commandHandlerService;
|
||||||
|
_dialogService = dialogService;
|
||||||
|
|
||||||
|
_keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.Up) });
|
||||||
|
_keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.Down) });
|
||||||
|
_keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.Tab) });
|
||||||
|
_keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.PageDown) });
|
||||||
|
_keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.PageUp) });
|
||||||
|
_keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.F4, alt: true) });
|
||||||
|
_keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.LWin) });
|
||||||
|
_keysToSkip.Add(new KeyConfig[] { new KeyConfig(Key.RWin) });
|
||||||
|
}
|
||||||
|
public async Task ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action<bool> setHandled)
|
||||||
|
{
|
||||||
|
if (key == Key.LeftAlt
|
||||||
|
|| key == Key.RightAlt
|
||||||
|
|| key == Key.LeftShift
|
||||||
|
|| key == Key.RightShift
|
||||||
|
|| key == Key.LeftCtrl
|
||||||
|
|| key == Key.RightCtrl) return;
|
||||||
|
|
||||||
|
_appState.NoCommandFound = false;
|
||||||
|
|
||||||
|
var isAltPressed = (keyModifiers & KeyModifiers.Alt) == KeyModifiers.Alt;
|
||||||
|
var isShiftPressed = (keyModifiers & KeyModifiers.Shift) == KeyModifiers.Shift;
|
||||||
|
var isCtrlPressed = (keyModifiers & KeyModifiers.Control) == KeyModifiers.Control;
|
||||||
|
|
||||||
|
if (_appState.ViewMode == ViewMode.Default)
|
||||||
|
{
|
||||||
|
var keyWithModifiers = new KeyConfig(key, shift: isShiftPressed, alt: isAltPressed, ctrl: isCtrlPressed);
|
||||||
|
_appState.PreviousKeys.Add(keyWithModifiers);
|
||||||
|
|
||||||
|
var selectedCommandBinding = _keyboardConfigurationService.UniversalCommandBindings.FirstOrDefault(c => AreKeysEqual(c.Keys, _appState.PreviousKeys));
|
||||||
|
selectedCommandBinding ??= _keyboardConfigurationService.CommandBindings.FirstOrDefault(c => AreKeysEqual(c.Keys, _appState.PreviousKeys));
|
||||||
|
|
||||||
|
if (key == Key.Escape)
|
||||||
|
{
|
||||||
|
_appState.IsAllShortcutVisible = false;
|
||||||
|
_appState.MessageBoxText = null;
|
||||||
|
_appState.PreviousKeys.Clear();
|
||||||
|
_appState.PossibleCommands = new();
|
||||||
|
setHandled(true);
|
||||||
|
}
|
||||||
|
else if (key == Key.Enter
|
||||||
|
&& _appState.MessageBoxText != null)
|
||||||
|
{
|
||||||
|
_appState.PreviousKeys.Clear();
|
||||||
|
_dialogService.ProcessMessageBox();
|
||||||
|
setHandled(true);
|
||||||
|
}
|
||||||
|
else if (selectedCommandBinding != null)
|
||||||
|
{
|
||||||
|
setHandled(true);
|
||||||
|
await _commandHandlerService.HandleCommandAsync(selectedCommandBinding.Command);
|
||||||
|
_appState.PreviousKeys.Clear();
|
||||||
|
_appState.PossibleCommands = new();
|
||||||
|
}
|
||||||
|
else if (_keysToSkip.Any(k => AreKeysEqual(k, _appState.PreviousKeys)))
|
||||||
|
{
|
||||||
|
_appState.PreviousKeys.Clear();
|
||||||
|
_appState.PossibleCommands = new();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (_appState.PreviousKeys.Count == 2)
|
||||||
|
{
|
||||||
|
setHandled(true);
|
||||||
|
_appState.NoCommandFound = true;
|
||||||
|
_appState.PreviousKeys.Clear();
|
||||||
|
_appState.PossibleCommands = new();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var possibleCommands = _keyboardConfigurationService.AllShortcut.Where(c => AreKeysEqual(c.Keys[0], keyWithModifiers)).ToList();
|
||||||
|
|
||||||
|
if (possibleCommands.Count == 0)
|
||||||
|
{
|
||||||
|
_appState.NoCommandFound = true;
|
||||||
|
_appState.PreviousKeys.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_appState.PossibleCommands = possibleCommands;
|
||||||
|
}
|
||||||
|
setHandled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var keyString = key.ToString();
|
||||||
|
var updateRapidTravelFilter = false;
|
||||||
|
|
||||||
|
if (key == Key.Escape)
|
||||||
|
{
|
||||||
|
setHandled(true);
|
||||||
|
if (_appState.IsAllShortcutVisible)
|
||||||
|
{
|
||||||
|
_appState.IsAllShortcutVisible = false;
|
||||||
|
}
|
||||||
|
else if (_appState.MessageBoxText != null)
|
||||||
|
{
|
||||||
|
_appState.MessageBoxText = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _appState.ExitRapidTravelMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (key == Key.Back)
|
||||||
|
{
|
||||||
|
if (_appState.RapidTravelText.Length > 0)
|
||||||
|
{
|
||||||
|
setHandled(true);
|
||||||
|
_appState.RapidTravelText = _appState.RapidTravelText.Substring(0, _appState.RapidTravelText.Length - 1);
|
||||||
|
updateRapidTravelFilter = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (keyString.Length == 1)
|
||||||
|
{
|
||||||
|
setHandled(true);
|
||||||
|
_appState.RapidTravelText += keyString.ToLower();
|
||||||
|
updateRapidTravelFilter = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var currentKeyAsList = new List<KeyConfig>() { new KeyConfig(key) };
|
||||||
|
var selectedCommandBinding = _keyboardConfigurationService.UniversalCommandBindings.FirstOrDefault(c => AreKeysEqual(c.Keys, currentKeyAsList));
|
||||||
|
if (selectedCommandBinding != null)
|
||||||
|
{
|
||||||
|
setHandled(true);
|
||||||
|
await _commandHandlerService.HandleCommandAsync(selectedCommandBinding.Command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateRapidTravelFilter)
|
||||||
|
{
|
||||||
|
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 static bool AreKeysEqual(IReadOnlyList<KeyConfig> collection1, IReadOnlyList<KeyConfig> collection2)
|
||||||
|
{
|
||||||
|
if (collection1.Count != collection2.Count) return false;
|
||||||
|
|
||||||
|
for (var i = 0; i < collection1.Count; i++)
|
||||||
|
{
|
||||||
|
if (!AreKeysEqual(collection1[i], collection2[i])) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool AreKeysEqual(KeyConfig key1, KeyConfig key2) =>
|
||||||
|
key1.Key == key2.Key
|
||||||
|
&& key1.Alt == key2.Alt
|
||||||
|
&& key1.Shift == key2.Shift
|
||||||
|
&& key1.Ctrl == key2.Ctrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using FileTime.Avalonia.Configuration;
|
||||||
|
using FileTime.App.Core.Command;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Services
|
||||||
|
{
|
||||||
|
public class KeyboardConfigurationService
|
||||||
|
{
|
||||||
|
public IReadOnlyList<CommandBindingConfiguration> CommandBindings { get; }
|
||||||
|
public IReadOnlyList<CommandBindingConfiguration> UniversalCommandBindings { get; }
|
||||||
|
public IReadOnlyList<CommandBindingConfiguration> AllShortcut { get; }
|
||||||
|
|
||||||
|
public KeyboardConfigurationService(IOptions<KeyBindingConfiguration> keyBindingConfiguration)
|
||||||
|
{
|
||||||
|
List<CommandBindingConfiguration> commandBindings = new();
|
||||||
|
List<CommandBindingConfiguration> universalCommandBindings = new();
|
||||||
|
IEnumerable<CommandBindingConfiguration> keyBindings = keyBindingConfiguration.Value.KeyBindings;
|
||||||
|
|
||||||
|
if (keyBindingConfiguration.Value.UseDefaultBindings)
|
||||||
|
{
|
||||||
|
keyBindings = keyBindings.Concat(keyBindingConfiguration.Value.DefaultKeyBindings);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var keyBinding in keyBindings)
|
||||||
|
{
|
||||||
|
if (keyBinding.Command == Commands.None)
|
||||||
|
{
|
||||||
|
throw new FormatException($"No command is set in keybinding for keys '{keyBinding.KeysDisplayText}'");
|
||||||
|
}
|
||||||
|
else if (keyBinding.Keys.Count == 0)
|
||||||
|
{
|
||||||
|
throw new FormatException($"No keys set in keybinding for command '{keyBinding.Command}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsUniversal(keyBinding))
|
||||||
|
{
|
||||||
|
universalCommandBindings.Add(keyBinding);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commandBindings.Add(keyBinding);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CommandBindings = commandBindings.AsReadOnly();
|
||||||
|
UniversalCommandBindings = universalCommandBindings.AsReadOnly();
|
||||||
|
AllShortcut = new List<CommandBindingConfiguration>(CommandBindings.Concat(UniversalCommandBindings)).AsReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsUniversal(CommandBindingConfiguration keyMapping)
|
||||||
|
{
|
||||||
|
return keyMapping.Command == Commands.GoUp
|
||||||
|
|| keyMapping.Command == Commands.Open
|
||||||
|
|| keyMapping.Command == Commands.OpenOrRun
|
||||||
|
|| keyMapping.Command == Commands.MoveCursorUp
|
||||||
|
|| keyMapping.Command == Commands.MoveCursorUpPage
|
||||||
|
|| keyMapping.Command == Commands.MoveCursorDownPage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,10 @@ namespace FileTime.Avalonia
|
|||||||
serviceCollection = serviceCollection
|
serviceCollection = serviceCollection
|
||||||
.AddSingleton<ItemNameConverterService>()
|
.AddSingleton<ItemNameConverterService>()
|
||||||
.AddSingleton<StatePersistenceService>()
|
.AddSingleton<StatePersistenceService>()
|
||||||
|
.AddSingleton<CommandHandlerService>()
|
||||||
|
.AddSingleton<KeyboardConfigurationService>()
|
||||||
|
.AddSingleton<KeyInputHandlerService>()
|
||||||
|
.AddSingleton<DialogService>()
|
||||||
.AddSingleton<IIconProvider, MaterialIconProvider>();
|
.AddSingleton<IIconProvider, MaterialIconProvider>();
|
||||||
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
@@ -66,14 +70,15 @@ namespace FileTime.Avalonia
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return serviceCollection
|
return serviceCollection
|
||||||
//.Configure<SzopiAPIConfig>(configuration.GetSection("server"))
|
.Configure<KeyBindingConfiguration>(configuration.GetSection(MainConfiguration.KeybindingBaseConfigKey))
|
||||||
.AddSingleton<IConfiguration>(configuration);
|
.AddSingleton<IConfiguration>(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IServiceCollection InitSerilog(this IServiceCollection serviceCollection)
|
internal static IServiceCollection InitSerilog(this IServiceCollection serviceCollection)
|
||||||
{
|
{
|
||||||
|
using var serviceProvider = serviceCollection.BuildServiceProvider();
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
.ReadFrom.Configuration(serviceCollection.BuildServiceProvider().GetService<IConfiguration>())
|
.ReadFrom.Configuration(serviceProvider.GetService<IConfiguration>())
|
||||||
.Enrich.FromLogContext()
|
.Enrich.FromLogContext()
|
||||||
.WriteTo.File(
|
.WriteTo.File(
|
||||||
Path.Combine(Program.AppDataRoot, "logs", "appLog.log"),
|
Path.Combine(Program.AppDataRoot, "logs", "appLog.log"),
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,8 @@
|
|||||||
ExtendClientAreaToDecorationsHint="True"
|
ExtendClientAreaToDecorationsHint="True"
|
||||||
Opened="OnWindowOpened"
|
Opened="OnWindowOpened"
|
||||||
Closed="OnWindowClosed"
|
Closed="OnWindowClosed"
|
||||||
|
x:DataType="vm:MainPageViewModel"
|
||||||
|
x:CompileBindings="True"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<Grid Background="{DynamicResource AppBackgroundBrush}">
|
<Grid Background="{DynamicResource AppBackgroundBrush}">
|
||||||
@@ -149,7 +151,7 @@
|
|||||||
|
|
||||||
<Grid Grid.Column="1" Grid.Row="1" RowDefinitions="Auto,40,*,Auto">
|
<Grid Grid.Column="1" Grid.Row="1" RowDefinitions="Auto,40,*,Auto">
|
||||||
<Grid>
|
<Grid>
|
||||||
<ItemsControl Items="{Binding TimelineCommands}">
|
<ItemsControl Items="{Binding AppState.TimelineCommands}">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<StackPanel Orientation="Horizontal" />
|
<StackPanel Orientation="Horizontal" />
|
||||||
@@ -335,7 +337,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<ItemsRepeater Items="{Binding PopupTexts}" Margin="0,0,0,20" HorizontalAlignment="Center" VerticalAlignment="Bottom" IsVisible="{Binding PopupTexts.Count,Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
<ItemsRepeater Items="{Binding AppState.PopupTexts}" Margin="0,0,0,20" HorizontalAlignment="Center" VerticalAlignment="Bottom" IsVisible="{Binding AppState.PopupTexts.Count,Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
||||||
<ItemsRepeater.Styles>
|
<ItemsRepeater.Styles>
|
||||||
<Style Selector="TextBlock">
|
<Style Selector="TextBlock">
|
||||||
<Style.Animations>
|
<Style.Animations>
|
||||||
@@ -387,7 +389,7 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid IsVisible="{Binding NoCommandFound}">
|
<Grid IsVisible="{Binding AppState.NoCommandFound}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="1" />
|
<RowDefinition Height="1" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@@ -408,7 +410,7 @@
|
|||||||
Text="No command found" />
|
Text="No command found" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid IsVisible="{Binding PossibleCommands.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
<Grid IsVisible="{Binding AppState.PossibleCommands.Count, Converter={StaticResource NotEqualsConverter}, ConverterParameter=0}">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="1" />
|
<RowDefinition Height="1" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@@ -423,7 +425,7 @@
|
|||||||
|
|
||||||
<ItemsRepeater
|
<ItemsRepeater
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Items="{Binding PossibleCommands}">
|
Items="{Binding AppState.PossibleCommands}">
|
||||||
<ItemsRepeater.ItemTemplate>
|
<ItemsRepeater.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Grid>
|
<Grid>
|
||||||
@@ -433,7 +435,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<TextBlock Text="{Binding KeysDisplayText}" />
|
<TextBlock Text="{Binding KeysDisplayText}" />
|
||||||
<TextBlock Grid.Column="1" Text="{Binding Name}" />
|
<TextBlock Grid.Column="1" Text="{Binding Command, Converter={StaticResource CommandToCommandNameConverter}}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsRepeater.ItemTemplate>
|
</ItemsRepeater.ItemTemplate>
|
||||||
@@ -447,7 +449,7 @@
|
|||||||
Background="{DynamicResource BarelyTransparentBackgroundColor}"
|
Background="{DynamicResource BarelyTransparentBackgroundColor}"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
IsVisible="{Binding Inputs, Converter={StaticResource IsNotNullConverter}}">
|
IsVisible="{Binding AppState.Inputs, Converter={StaticResource IsNotNullConverter}}">
|
||||||
<Border
|
<Border
|
||||||
Background="{DynamicResource ContainerBackgroundBrush}"
|
Background="{DynamicResource ContainerBackgroundBrush}"
|
||||||
Padding="20"
|
Padding="20"
|
||||||
@@ -457,7 +459,7 @@
|
|||||||
|
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
x:Name="InputList"
|
x:Name="InputList"
|
||||||
Items="{Binding Inputs}">
|
Items="{Binding AppState.Inputs}">
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Grid MinWidth="500" ColumnDefinitions="250,*" Margin="10,5">
|
<Grid MinWidth="500" ColumnDefinitions="250,*" Margin="10,5">
|
||||||
@@ -502,7 +504,7 @@
|
|||||||
Background="{DynamicResource BarelyTransparentBackgroundColor}"
|
Background="{DynamicResource BarelyTransparentBackgroundColor}"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
IsVisible="{Binding MessageBoxText, Converter={StaticResource IsNotNullConverter}}">
|
IsVisible="{Binding AppState.MessageBoxText, Converter={StaticResource IsNotNullConverter}}">
|
||||||
<Border
|
<Border
|
||||||
Background="{DynamicResource ContainerBackgroundBrush}"
|
Background="{DynamicResource ContainerBackgroundBrush}"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
@@ -510,7 +512,7 @@
|
|||||||
Padding="20">
|
Padding="20">
|
||||||
<Grid RowDefinitions="Auto,Auto">
|
<Grid RowDefinitions="Auto,Auto">
|
||||||
|
|
||||||
<TextBlock Text="{Binding MessageBoxText}"/>
|
<TextBlock Text="{Binding AppState.MessageBoxText}"/>
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
@@ -535,14 +537,14 @@
|
|||||||
Background="{DynamicResource TransparentContainerBackgroundBrush}"
|
Background="{DynamicResource TransparentContainerBackgroundBrush}"
|
||||||
Margin="20"
|
Margin="20"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
IsVisible="{Binding IsAllShortcutVisible}">
|
IsVisible="{Binding AppState.IsAllShortcutVisible}">
|
||||||
<Grid RowDefinitions="Auto, *" Margin="30,10">
|
<Grid RowDefinitions="Auto, *" Margin="30,10">
|
||||||
<TextBlock Text="Shortcuts" Margin="0,0,0,20"/>
|
<TextBlock Text="Shortcuts" Margin="0,0,0,20"/>
|
||||||
<ScrollViewer
|
<ScrollViewer
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
HorizontalScrollBarVisibility="Disabled">
|
HorizontalScrollBarVisibility="Disabled">
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
Items="{Binding AllShortcut}">
|
Items="{Binding KeyboardConfigurationService.AllShortcut}">
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Grid Margin="0,5,10,5">
|
<Grid Margin="0,5,10,5">
|
||||||
@@ -552,7 +554,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<TextBlock Text="{Binding KeysDisplayText}" />
|
<TextBlock Text="{Binding KeysDisplayText}" />
|
||||||
<TextBlock Grid.Column="1" Text="{Binding Name}" />
|
<TextBlock Grid.Column="1" Text="{Binding Command, Converter={StaticResource CommandToCommandNameConverter}}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
|
|||||||
@@ -55,13 +55,13 @@ namespace FileTime.Avalonia.Views
|
|||||||
|
|
||||||
private void InputText_KeyDown(object sender, KeyEventArgs e)
|
private void InputText_KeyDown(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Key == Key.Enter && _inputElementWrapper == ViewModel!.Inputs.Last())
|
if (e.Key == Key.Enter && _inputElementWrapper == ViewModel!.AppState.Inputs.Last())
|
||||||
{
|
{
|
||||||
ViewModel.ProcessInputs();
|
ViewModel.ProcessInputs();
|
||||||
_inputElementWrapper = null;
|
_inputElementWrapper = null;
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
else if (e.Key == Key.Escape && _inputElementWrapper == ViewModel!.Inputs.Last())
|
else if (e.Key == Key.Escape && _inputElementWrapper == ViewModel!.AppState.Inputs.Last())
|
||||||
{
|
{
|
||||||
ViewModel.CancelInputs();
|
ViewModel.CancelInputs();
|
||||||
_inputElementWrapper = null;
|
_inputElementWrapper = null;
|
||||||
@@ -87,7 +87,7 @@ namespace FileTime.Avalonia.Views
|
|||||||
|
|
||||||
private void InputText_AttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
|
private void InputText_AttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is TextBox inputText && inputText.DataContext is InputElementWrapper inputElementWrapper && inputElementWrapper == ViewModel!.Inputs.First())
|
if (sender is TextBox inputText && inputText.DataContext is InputElementWrapper inputElementWrapper && inputElementWrapper == ViewModel!.AppState.Inputs.First())
|
||||||
{
|
{
|
||||||
inputText.Focus();
|
inputText.Focus();
|
||||||
}
|
}
|
||||||
@@ -101,7 +101,7 @@ namespace FileTime.Avalonia.Views
|
|||||||
&& sender is StyledElement control
|
&& sender is StyledElement control
|
||||||
&& control.DataContext is PlaceInfo placeInfo)
|
&& control.DataContext is PlaceInfo placeInfo)
|
||||||
{
|
{
|
||||||
ViewModel.OpenContainer(placeInfo.Container);
|
ViewModel.CommandHandlerService.OpenContainer(placeInfo.Container);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ namespace FileTime.Avalonia.Views
|
|||||||
&& sender is StyledElement control
|
&& sender is StyledElement control
|
||||||
&& control.DataContext is RootDriveInfo rootDriveInfo)
|
&& control.DataContext is RootDriveInfo rootDriveInfo)
|
||||||
{
|
{
|
||||||
ViewModel.OpenContainer(rootDriveInfo.Container);
|
ViewModel.CommandHandlerService.OpenContainer(rootDriveInfo.Container);
|
||||||
e.Handled = true;
|
e.Handled = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user