diff --git a/src/AppCommon/FileTime.App.Core/Command/Commands.cs b/src/AppCommon/FileTime.App.Core/Command/Commands.cs
index f12fff2..fe66263 100644
--- a/src/AppCommon/FileTime.App.Core/Command/Commands.cs
+++ b/src/AppCommon/FileTime.App.Core/Command/Commands.cs
@@ -2,34 +2,58 @@ namespace FileTime.App.Core.Command
{
public enum Commands
{
+ None,
+
+ AutoRefresh,
+ ChangeTimelineMode,
CloseTab,
Copy,
+ CopyPath,
CreateContainer,
CreateElement,
Cut,
EnterRapidTravel,
GoToHome,
+ GoToPath,
GoToProvider,
GoToRoot,
GoUp,
- Delete,
+ HardDelete,
+ Mark,
MoveCursorDown,
MoveCursorDownPage,
MoveCursorUp,
MoveCursorUpPage,
- MoveToBottom,
MoveToFirst,
MoveToLast,
- MoveToTop,
+ NextTimelineBlock,
+ NextTimelineCommand,
Open,
+ OpenInFileBrowser,
OpenOrRun,
PasteMerge,
PasteOverwrite,
PasteSkip,
- Select,
- ToggleHidden,
- Rename,
- Dummy,
+ PreviousTimelineBlock,
+ PreviousTimelineCommand,
Refresh,
+ Rename,
+ RunCommand,
+ ShowAllShotcut,
+ SoftDelete,
+ SwitchToLastTab,
+ SwitchToTab1,
+ SwitchToTab2,
+ SwitchToTab3,
+ SwitchToTab4,
+ SwitchToTab5,
+ SwitchToTab6,
+ SwitchToTab7,
+ SwitchToTab8,
+ TimelinePause,
+ TimelineRefresh,
+ TimelineStart,
+ ToggleAdvancedIcons,
+ ToggleHidden,
}
}
\ No newline at end of file
diff --git a/src/ConsoleApp/FileTime.ConsoleUI.App/Application.cs b/src/ConsoleApp/FileTime.ConsoleUI.App/Application.cs
index dcccbd9..e787f76 100644
--- a/src/ConsoleApp/FileTime.ConsoleUI.App/Application.cs
+++ b/src/ConsoleApp/FileTime.ConsoleUI.App/Application.cs
@@ -90,7 +90,7 @@ namespace FileTime.ConsoleUI.App
new CommandBinding("open", Commands.Open, new[] { new ConsoleKeyInfo('→', ConsoleKey.RightArrow, false, false, false) }, Open),
new CommandBinding(
"go to top",
- Commands.MoveToTop,
+ Commands.MoveToFirst,
new[]
{
new ConsoleKeyInfo('g', ConsoleKey.G, false, false, false),
@@ -99,7 +99,7 @@ namespace FileTime.ConsoleUI.App
MoveCursorToTop),
new CommandBinding(
"go to bottom",
- Commands.MoveToBottom,
+ Commands.MoveToLast,
new[]
{
new ConsoleKeyInfo('G', ConsoleKey.G, true, false, false)
@@ -114,7 +114,7 @@ namespace FileTime.ConsoleUI.App
new ConsoleKeyInfo('h', ConsoleKey.H, false, false, false)
},
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(
"copy",
Commands.Copy,
diff --git a/src/GuiApp/FileTime.Avalonia/App.axaml b/src/GuiApp/FileTime.Avalonia/App.axaml
index ae519f3..5043341 100644
--- a/src/GuiApp/FileTime.Avalonia/App.axaml
+++ b/src/GuiApp/FileTime.Avalonia/App.axaml
@@ -134,6 +134,7 @@
+
@@ -186,15 +187,5 @@
-
-
diff --git a/src/GuiApp/FileTime.Avalonia/Application/AppState.cs b/src/GuiApp/FileTime.Avalonia/Application/AppState.cs
index 5ed418d..68accd5 100644
--- a/src/GuiApp/FileTime.Avalonia/Application/AppState.cs
+++ b/src/GuiApp/FileTime.Avalonia/Application/AppState.cs
@@ -7,6 +7,10 @@ using FileTime.App.Core.Tab;
using System.Threading.Tasks;
using FileTime.Core.Models;
using System.Threading;
+using FileTime.Avalonia.Configuration;
+using FileTime.Avalonia.Misc;
+using FileTime.Core.Extensions;
+using FileTime.Avalonia.ViewModels;
namespace FileTime.Avalonia.Application
{
@@ -26,6 +30,28 @@ namespace FileTime.Avalonia.Application
[Property]
private string _rapidTravelText = "";
+ [Property]
+ private List _possibleCommands = new();
+
+ [Property]
+ private List _inputs;
+
+ [Property]
+ private string _messageBoxText;
+
+ [Property]
+ private ObservableCollection _popupTexts = new();
+
+ [Property]
+ private bool _isAllShortcutVisible;
+
+ [Property]
+ private bool _noCommandFound;
+
+ public List PreviousKeys { get; } = new();
+
+ public ObservableCollection TimelineCommands { get; } = new();
+
partial void OnInitialize()
{
_tabs.CollectionChanged += TabsChanged;
@@ -66,7 +92,7 @@ namespace FileTime.Avalonia.Application
private void SelectedTabChanged()
{
- foreach(var tab in Tabs)
+ foreach (var tab in Tabs)
{
tab.IsSelected = tab == SelectedTab;
}
@@ -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));
+ }
}
}
diff --git a/src/GuiApp/FileTime.Avalonia/Command/CommandBinding.cs b/src/GuiApp/FileTime.Avalonia/Command/CommandBinding.cs
index 5db1521..ccbcb23 100644
--- a/src/GuiApp/FileTime.Avalonia/Command/CommandBinding.cs
+++ b/src/GuiApp/FileTime.Avalonia/Command/CommandBinding.cs
@@ -1,4 +1,4 @@
-using FileTime.App.Core.Command;
+/* using FileTime.App.Core.Command;
using FileTime.Avalonia.Misc;
using System;
using System.Collections.Generic;
@@ -14,11 +14,11 @@ namespace FileTime.Avalonia.Command
public string Name { get; }
public Commands? Command { get; }
- public KeyWithModifiers[] Keys { get; }
+ public KeyConfig[] Keys { get; }
public string KeysDisplayText => GetKeysDisplayText();
- public CommandBinding(string name, Commands? command, KeyWithModifiers[] keys, Func commandHandler)
+ public CommandBinding(string name, Commands? command, KeyConfig[] keys, Func commandHandler)
{
_commandHandler = commandHandler;
Name = name;
@@ -48,7 +48,7 @@ namespace FileTime.Avalonia.Command
return s;
}
- private static string AddKeyWithCtrlOrAlt(KeyWithModifiers key, string currentText, Func keyProcessor)
+ private static string AddKeyWithCtrlOrAlt(KeyConfig key, string currentText, Func keyProcessor)
{
var s = "";
@@ -65,7 +65,7 @@ namespace FileTime.Avalonia.Command
return s;
}
- private static string AddSpecialKey(KeyWithModifiers key, string currentText, bool wasCtrlOrAlt)
+ private static string AddSpecialKey(KeyConfig key, string currentText, bool wasCtrlOrAlt)
{
var s = "";
@@ -77,3 +77,4 @@ namespace FileTime.Avalonia.Command
}
}
}
+ */
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Configuration/CommandBindingConfiguration.cs b/src/GuiApp/FileTime.Avalonia/Configuration/CommandBindingConfiguration.cs
new file mode 100644
index 0000000..3f92661
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/Configuration/CommandBindingConfiguration.cs
@@ -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 Keys { get; set; } = new List();
+
+ public Commands Command { get; set; } = Commands.None;
+
+ public string KeysDisplayText => GetKeysDisplayText();
+
+ public CommandBindingConfiguration() { }
+
+ public CommandBindingConfiguration(Commands command, IEnumerable keys)
+ {
+ Keys = new List(keys);
+ Command = command;
+ }
+
+ public CommandBindingConfiguration(Commands command, KeyConfig key)
+ {
+ Keys = new List() { key };
+ Command = command;
+ }
+
+ public CommandBindingConfiguration(Commands command, IEnumerable keys)
+ {
+ Keys = keys.Select(k => new KeyConfig(k)).ToList();
+ Command = command;
+ }
+
+ public CommandBindingConfiguration(Commands command, Key key)
+ {
+ Keys = new List() { 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 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Configuration/KeyBindingConfiguration.cs b/src/GuiApp/FileTime.Avalonia/Configuration/KeyBindingConfiguration.cs
new file mode 100644
index 0000000..40fd876
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/Configuration/KeyBindingConfiguration.cs
@@ -0,0 +1,11 @@
+using System.Collections.Generic;
+
+namespace FileTime.Avalonia.Configuration
+{
+ public class KeyBindingConfiguration
+ {
+ public bool UseDefaultBindings { get; set; } = true;
+ public List DefaultKeyBindings { get; set; } = new();
+ public List KeyBindings { get; set; } = new();
+ }
+}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Configuration/KeyConfig.cs b/src/GuiApp/FileTime.Avalonia/Configuration/KeyConfig.cs
new file mode 100644
index 0000000..524d8d0
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/Configuration/KeyConfig.cs
@@ -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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Configuration/MainConfiguration.cs b/src/GuiApp/FileTime.Avalonia/Configuration/MainConfiguration.cs
index 2897136..048e379 100644
--- a/src/GuiApp/FileTime.Avalonia/Configuration/MainConfiguration.cs
+++ b/src/GuiApp/FileTime.Avalonia/Configuration/MainConfiguration.cs
@@ -1,9 +1,101 @@
+using Avalonia.Input;
+using FileTime.App.Core.Command;
+using System;
using System.Collections.Generic;
namespace FileTime.Avalonia.Configuration
{
public static class MainConfiguration
{
- public static readonly Dictionary Configuration = new();
+ private static readonly Lazy> _defaultKeybindings = new(InitDefaultKeyBindings);
+ internal const string KeybindingBaseConfigKey = "KeyBindings";
+
+ public static Dictionary Configuration { get; }
+
+ static MainConfiguration()
+ {
+ Configuration = new();
+ PopulateDefaultKeyBindings(Configuration, _defaultKeybindings.Value, KeybindingBaseConfigKey + ":" + nameof(KeyBindingConfiguration.DefaultKeyBindings));
+ }
+
+ private static void PopulateDefaultKeyBindings(Dictionary keybindings, List 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 InitDefaultKeyBindings()
+ {
+ return new List()
+ {
+ 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),
+ };
+ }
}
}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Converters/CommandToCommandNameConverter.cs b/src/GuiApp/FileTime.Avalonia/Converters/CommandToCommandNameConverter.cs
new file mode 100644
index 0000000..304c86a
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/Converters/CommandToCommandNameConverter.cs
@@ -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();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Misc/KeyWithModifiers.cs b/src/GuiApp/FileTime.Avalonia/Misc/KeyWithModifiers.cs
deleted file mode 100644
index 257a8d2..0000000
--- a/src/GuiApp/FileTime.Avalonia/Misc/KeyWithModifiers.cs
+++ /dev/null
@@ -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;
- }
- }
-}
diff --git a/src/GuiApp/FileTime.Avalonia/Services/CommandHandlerService.cs b/src/GuiApp/FileTime.Avalonia/Services/CommandHandlerService.cs
new file mode 100644
index 0000000..5006458
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/Services/CommandHandlerService.cs
@@ -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 _contentProviders;
+ private readonly Dictionary> _commandHandlers;
+
+ public CommandHandlerService(
+ AppState appState,
+ LocalContentProvider localContentProvider,
+ ItemNameConverterService itemNameConverterService,
+ DialogService dialogService,
+ IClipboard clipboard,
+ TimeRunner timeRunner,
+ IIconProvider iconProvider,
+ IEnumerable contentProviders)
+ {
+ _appState = appState;
+ _localContentProvider = localContentProvider;
+ _itemNameConverterService = itemNameConverterService;
+ _dialogService = dialogService;
+ _clipboard = clipboard;
+ _timeRunner = timeRunner;
+ _iconProvider = iconProvider;
+ _contentProviders = contentProviders;
+
+ _commandHandlers = new Dictionary>
+ {
+ {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 inputs) =>
+ {
+ var container = _appState.SelectedTab.CurrentLocation.Container;
+ var createContainerCommand = new CreateContainerCommand(new AbsolutePath(container), inputs[0].Value);
+ await AddCommand(createContainerCommand);
+ };
+
+ _dialogService.ReadInputs(new List() { new InputElement("Container name", InputType.Text) }, handler);
+
+ return Task.CompletedTask;
+ }
+
+ private Task CreateElement()
+ {
+ var handler = async (List inputs) =>
+ {
+ var container = _appState.SelectedTab.CurrentLocation.Container;
+ var createElementCommand = new CreateElementCommand(new AbsolutePath(container), inputs[0].Value);
+ await AddCommand(createElementCommand);
+ };
+
+ _dialogService.ReadInputs(new List() { 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();
+
+ 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();
+
+ 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? 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(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()
+ {
+ 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 inputs) =>
+ {
+ var renameCommand = new RenameCommand(new AbsolutePath(selectedItem), inputs[0].Value);
+ await AddCommand(renameCommand);
+ };
+
+ _dialogService.ReadInputs(new List() { 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 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() { 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 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() { 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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Services/DialogService.cs b/src/GuiApp/FileTime.Avalonia/Services/DialogService.cs
new file mode 100644
index 0000000..303d2fd
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/Services/DialogService.cs
@@ -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, Task>? _inputHandler;
+
+ public DialogService(AppState appState)
+ {
+ _appState = appState;
+ }
+ public void ReadInputs(List inputs, Action> inputHandler) =>
+ ReadInputs(inputs, (inputs) => { inputHandler(inputs); return Task.CompletedTask; });
+
+ public void ReadInputs(List inputs, Func, Task> inputHandler)
+ {
+ _appState.Inputs = inputs.ConvertAll(i => new InputElementWrapper(i, i.DefaultValue));
+ _inputHandler = inputHandler;
+ }
+
+ public async Task ReadInputs(IEnumerable fields)
+ {
+ var waiting = true;
+ var result = Array.Empty();
+ 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 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));
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Services/KeyInputHandlerService.cs b/src/GuiApp/FileTime.Avalonia/Services/KeyInputHandlerService.cs
new file mode 100644
index 0000000..4f7662a
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/Services/KeyInputHandlerService.cs
@@ -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 _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 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() { 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, IEnumerable>>()
+ {
+ container => container.Where(c => c.Name.ToLower().Contains(_appState.RapidTravelText))
+ },
+ new List, IEnumerable>>()
+ {
+ 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 collection1, IReadOnlyList 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;
+ }
+}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Services/KeyboardConfigurationService.cs b/src/GuiApp/FileTime.Avalonia/Services/KeyboardConfigurationService.cs
new file mode 100644
index 0000000..4428a0a
--- /dev/null
+++ b/src/GuiApp/FileTime.Avalonia/Services/KeyboardConfigurationService.cs
@@ -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 CommandBindings { get; }
+ public IReadOnlyList UniversalCommandBindings { get; }
+ public IReadOnlyList AllShortcut { get; }
+
+ public KeyboardConfigurationService(IOptions keyBindingConfiguration)
+ {
+ List commandBindings = new();
+ List universalCommandBindings = new();
+ IEnumerable 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(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;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/GuiApp/FileTime.Avalonia/Startup.cs b/src/GuiApp/FileTime.Avalonia/Startup.cs
index e5457af..3ff725a 100644
--- a/src/GuiApp/FileTime.Avalonia/Startup.cs
+++ b/src/GuiApp/FileTime.Avalonia/Startup.cs
@@ -27,6 +27,10 @@ namespace FileTime.Avalonia
serviceCollection = serviceCollection
.AddSingleton()
.AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
+ .AddSingleton()
.AddSingleton();
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@@ -66,19 +70,20 @@ namespace FileTime.Avalonia
.Build();
return serviceCollection
- //.Configure(configuration.GetSection("server"))
+ .Configure(configuration.GetSection(MainConfiguration.KeybindingBaseConfigKey))
.AddSingleton(configuration);
}
internal static IServiceCollection InitSerilog(this IServiceCollection serviceCollection)
{
+ using var serviceProvider = serviceCollection.BuildServiceProvider();
Log.Logger = new LoggerConfiguration()
- .ReadFrom.Configuration(serviceCollection.BuildServiceProvider().GetService())
+ .ReadFrom.Configuration(serviceProvider.GetService())
.Enrich.FromLogContext()
.WriteTo.File(
- Path.Combine(Program.AppDataRoot, "logs", "appLog.log"),
- fileSizeLimitBytes: 10*1024*1024,
- rollOnFileSizeLimit: true,
+ Path.Combine(Program.AppDataRoot, "logs", "appLog.log"),
+ fileSizeLimitBytes: 10 * 1024 * 1024,
+ rollOnFileSizeLimit: true,
rollingInterval: RollingInterval.Day)
.CreateLogger();
diff --git a/src/GuiApp/FileTime.Avalonia/ViewModels/MainPageViewModel.cs b/src/GuiApp/FileTime.Avalonia/ViewModels/MainPageViewModel.cs
index a553135..78525ea 100644
--- a/src/GuiApp/FileTime.Avalonia/ViewModels/MainPageViewModel.cs
+++ b/src/GuiApp/FileTime.Avalonia/ViewModels/MainPageViewModel.cs
@@ -1,34 +1,26 @@
using FileTime.Core.Components;
-using FileTime.Core.Extensions;
using FileTime.Core.Interactions;
using FileTime.Core.Models;
using FileTime.Providers.Local;
using FileTime.Avalonia.Application;
-using FileTime.Avalonia.Command;
using FileTime.Avalonia.Misc;
using FileTime.Avalonia.Models;
using FileTime.Avalonia.Services;
using MvvmGen;
using System;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
-using Avalonia.Input;
-using FileTime.App.Core.Clipboard;
using Microsoft.Extensions.DependencyInjection;
-using FileTime.Core.Command;
using FileTime.Core.Timeline;
using FileTime.Core.Providers;
using Syroot.Windows.IO;
using FileTime.Avalonia.IconProviders;
-using Avalonia.Threading;
using Microsoft.Extensions.Logging;
-using AsyncEvent;
using System.Threading;
+using Avalonia.Input;
namespace FileTime.Avalonia.ViewModels
{
@@ -38,83 +30,38 @@ namespace FileTime.Avalonia.ViewModels
[Inject(typeof(StatePersistenceService), PropertyName = "StatePersistence", PropertyAccessModifier = AccessModifier.Public)]
[Inject(typeof(ItemNameConverterService))]
[Inject(typeof(ILogger), PropertyName = "_logger")]
+ [Inject(typeof(KeyboardConfigurationService))]
+ [Inject(typeof(CommandHandlerService), PropertyAccessModifier = AccessModifier.Public)]
+ [Inject(typeof(DialogService))]
+ [Inject(typeof(KeyInputHandlerService))]
public partial class MainPageViewModel : IMainPageViewModelBase
{
- const string RAPIDTRAVEL = "rapidTravel";
+ public const string RAPIDTRAVEL = "rapidTravel";
- private readonly List _previousKeys = new();
- private readonly List _keysToSkip = new();
- private readonly List _commandBindings = new();
- private readonly List _universalCommandBindings = new();
-
- private IClipboard _clipboard;
private TimeRunner _timeRunner;
- private IEnumerable _contentProviders;
- private IIconProvider _iconProvider;
- private bool _addCommandToNextBatch;
-
- private Func? _inputHandler;
[Property]
private string _text;
- [Property]
- private bool _noCommandFound;
-
- [Property]
- private List _possibleCommands = new();
-
- [Property]
- private List _inputs;
-
[Property]
private List _rootDriveInfos;
[Property]
private List _places;
- [Property]
- private string _messageBoxText;
-
- [Property]
- private ObservableCollection _popupTexts = new();
-
- [Property]
- private bool _isAllShortcutVisible;
-
- [Property]
- private List _allShortcut;
-
[Property]
private bool _loading = true;
- public ObservableCollection TimelineCommands { get; } = new();
-
async partial void OnInitialize()
{
_logger?.LogInformation($"Starting {nameof(MainPageViewModel)} initialization...");
- _clipboard = App.ServiceProvider.GetService()!;
_timeRunner = App.ServiceProvider.GetService()!;
- _contentProviders = App.ServiceProvider.GetService>()!;
- _iconProvider = App.ServiceProvider.GetService()!;
var inputInterface = (BasicInputHandler)App.ServiceProvider.GetService()!;
- inputInterface.InputHandler = ReadInputs;
+ inputInterface.InputHandler = DialogService.ReadInputs;
App.ServiceProvider.GetService();
await StatePersistence.LoadStatesAsync();
_timeRunner.CommandsChangedAsync.Add(UpdateParallelCommands);
- InitCommandBindings();
-
- _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.Up) });
- _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.Down) });
- _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.Tab) });
- _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.PageDown) });
- _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.PageUp) });
- _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.F4, alt: true) });
- _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.LWin) });
- _keysToSkip.Add(new KeyWithModifiers[] { new KeyWithModifiers(Key.RWin) });
-
- AllShortcut = _commandBindings.Concat(_universalCommandBindings).ToList();
if (AppState.Tabs.Count == 0)
{
@@ -220,13 +167,13 @@ namespace FileTime.Avalonia.ViewModels
{
foreach (var parallelCommand in parallelCommands)
{
- if (!TimelineCommands.Any(c => c.Id == parallelCommand.Id))
+ if (!AppState.TimelineCommands.Any(c => c.Id == parallelCommand.Id))
{
- TimelineCommands.Add(new ParallelCommandsViewModel(parallelCommand));
+ AppState.TimelineCommands.Add(new ParallelCommandsViewModel(parallelCommand));
}
}
var itemsToRemove = new List();
- foreach (var parallelCommandVm in TimelineCommands)
+ foreach (var parallelCommandVm in AppState.TimelineCommands)
{
if (!parallelCommands.Any(c => c.Id == parallelCommandVm.Id))
{
@@ -237,12 +184,12 @@ namespace FileTime.Avalonia.ViewModels
for (var i = 0; i < itemsToRemove.Count; i++)
{
itemsToRemove[i].Destroy();
- TimelineCommands.Remove(itemsToRemove[i]);
+ AppState.TimelineCommands.Remove(itemsToRemove[i]);
}
foreach (var parallelCommand in parallelCommands)
{
- var parallelCommandsVM = TimelineCommands.First(t => t.Id == parallelCommand.Id);
+ var parallelCommandsVM = AppState.TimelineCommands.First(t => t.Id == parallelCommand.Id);
foreach (var command in parallelCommand.Commands)
{
if (!parallelCommandsVM.ParallelCommands.Any(c => c.CommandTimeState.Command == command.Command))
@@ -280,1207 +227,33 @@ namespace FileTime.Avalonia.ViewModels
return await LocalContentProvider.GetByPath(drive.Name) as IContainer;
}
- 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 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;
-
- _previousKeys.Clear();
- PossibleCommands = new();
-
- return Task.CompletedTask;
- }
-
- private async Task ExitRapidTravelMode()
- {
- AppState.ViewMode = ViewMode.Default;
-
- _previousKeys.Clear();
- PossibleCommands = new();
- AppState.RapidTravelText = "";
-
- await AppState.SelectedTab.OpenContainer(await AppState.SelectedTab.CurrentLocation.Container.WithoutVirtualContainer(RAPIDTRAVEL));
- }
-
- private async Task SwitchToTab(int number)
- {
- var tabContainer = AppState.Tabs.FirstOrDefault(t => t.TabNumber == number);
-
- if (number == -1)
- {
- var greatestNumber = AppState.Tabs.Select(t => t.TabNumber).Max();
- 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 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 () =>
- {
- if (Inputs != null)
- {
- var container = AppState.SelectedTab.CurrentLocation.Container;
- var createContainerCommand = new CreateContainerCommand(new Core.Models.AbsolutePath(container), Inputs[0].Value);
- await AddCommand(createContainerCommand);
- Inputs = null;
- }
- };
-
- ReadInputs(new List() { new Core.Interactions.InputElement("Container name", InputType.Text) }, handler);
-
- return Task.CompletedTask;
- }
-
- private Task CreateElement()
- {
- var handler = async () =>
- {
- if (Inputs != null)
- {
- var container = AppState.SelectedTab.CurrentLocation.Container;
- var createElementCommand = new CreateElementCommand(new Core.Models.AbsolutePath(container), Inputs[0].Value);
- await AddCommand(createElementCommand);
- Inputs = null;
- }
- };
-
- ReadInputs(new List() { new Core.Interactions.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();
-
- 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();
-
- 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? 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(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()
- {
- 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)
- {
- 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 () =>
- {
- if (Inputs != null)
- {
- var renameCommand = new RenameCommand(new Core.Models.AbsolutePath(selectedItem), Inputs[0].Value);
- await AddCommand(renameCommand);
- }
- };
-
- ReadInputs(new List() { new Core.Interactions.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;
- var text = "Timeline mode: " + (_addCommandToNextBatch ? "Continuous" : "Parallel");
- _popupTexts.Add(text);
-
- Task.Run(async () =>
- {
- await Task.Delay(5000);
- await Dispatcher.UIThread.InvokeAsync(() => _popupTexts.Remove(text));
- });
-
- return Task.CompletedTask;
- }
-
- private Task GoToContainer()
- {
- var handler = async () =>
- {
- if (Inputs != null)
- {
- 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;
- }
- }
- }
- };
-
- ReadInputs(new List() { new Core.Interactions.InputElement("Path", InputType.Text) }, handler);
-
- return Task.CompletedTask;
- }
-
- private Task ToggleAdvancedIcons()
- {
- _iconProvider.EnableAdvancedIcons = !_iconProvider.EnableAdvancedIcons;
- var text = "Advanced icons are: " + (_iconProvider.EnableAdvancedIcons ? "ON" : "OFF");
- _popupTexts.Add(text);
-
- Task.Run(async () =>
- {
- await Task.Delay(5000);
- await Dispatcher.UIThread.InvokeAsync(() => _popupTexts.Remove(text));
- });
- return Task.CompletedTask;
- }
-
- 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()
- {
- IsAllShortcutVisible = true;
- return Task.CompletedTask;
- }
-
- private Task RunCommandInContainer()
- {
- var handler = () =>
- {
- if (Inputs != null)
- {
- 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))
- {
- 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;
- };
-
- ReadInputs(new List() { new Core.Interactions.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 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 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 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 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 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 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 = TimelineCommands.SelectMany(t => t.ParallelCommands).FirstOrDefault(c => c.IsSelected);
- if (currentSelected != null) return currentSelected;
-
- var firstCommand = 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 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;
-
- var text = "Auto refresh is: " + (tab.AutoRefresh ? "ON" : "OFF");
- _popupTexts.Add(text);
-
- Task.Run(async () =>
- {
- await Task.Delay(5000);
- await Dispatcher.UIThread.InvokeAsync(() => _popupTexts.Remove(text));
- });
- return Task.CompletedTask;
- }
-
[Command]
public async void ProcessInputs()
{
- if (_inputHandler != null)
- {
- await _inputHandler.Invoke();
- }
-
- Inputs = null;
- _inputHandler = null;
+ await DialogService.ProcessInputs();
}
[Command]
public void CancelInputs()
{
- Inputs = null;
- _inputHandler = null;
+ DialogService.CancelInputs();
}
[Command]
public void ProcessMessageBox()
{
- _inputHandler?.Invoke();
-
- MessageBoxText = null;
- _inputHandler = null;
+ DialogService.ProcessMessageBox();
}
[Command]
public void CancelMessageBox()
{
- MessageBoxText = null;
- _inputHandler = null;
+ DialogService.CancelMessageBox();
}
- public async void ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action setHandled)
+ public void ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action setHandled)
{
- if (key == Key.LeftAlt
- || key == Key.RightAlt
- || key == Key.LeftShift
- || key == Key.RightShift
- || key == Key.LeftCtrl
- || key == Key.RightCtrl) return;
-
- 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 KeyWithModifiers(key, isAltPressed, isShiftPressed, isCtrlPressed);
- _previousKeys.Add(keyWithModifiers);
-
- var selectedCommandBinding = _universalCommandBindings.Find(c => AreKeysEqual(c.Keys, _previousKeys));
- selectedCommandBinding ??= _commandBindings.Find(c => AreKeysEqual(c.Keys, _previousKeys));
-
- if (key == Key.Escape)
- {
- IsAllShortcutVisible = false;
- MessageBoxText = null;
- _previousKeys.Clear();
- PossibleCommands = new();
- setHandled(true);
- }
- else if (key == Key.Enter
- && MessageBoxText != null)
- {
- _previousKeys.Clear();
- ProcessMessageBox();
- setHandled(true);
- }
- else if (selectedCommandBinding != null)
- {
- setHandled(true);
- await selectedCommandBinding.InvokeAsync();
- _previousKeys.Clear();
- PossibleCommands = new();
- }
- else if (_keysToSkip.Any(k => AreKeysEqual(k, _previousKeys)))
- {
- _previousKeys.Clear();
- PossibleCommands = new();
- return;
- }
- else if (_previousKeys.Count == 2)
- {
- setHandled(true);
- NoCommandFound = true;
- _previousKeys.Clear();
- PossibleCommands = new();
- }
- else
- {
- var possibleCommands = _universalCommandBindings.Concat(_commandBindings).Where(c => AreKeysEqual(c.Keys[0], keyWithModifiers)).ToList();
-
- if (possibleCommands.Count == 0)
- {
- NoCommandFound = true;
- _previousKeys.Clear();
- }
- else
- {
- PossibleCommands = possibleCommands;
- }
- setHandled(true);
- }
- }
- else
- {
- var keyString = key.ToString();
- var updateRapidTravelFilter = false;
-
- if (key == Key.Escape)
- {
- setHandled(true);
- if (IsAllShortcutVisible)
- {
- IsAllShortcutVisible = false;
- }
- else if (MessageBoxText != null)
- {
- MessageBoxText = null;
- }
- else
- {
- await 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.ToString().ToLower();
- updateRapidTravelFilter = true;
- }
- else
- {
- var currentKeyAsList = new List() { new KeyWithModifiers(key) };
- var selectedCommandBinding = _universalCommandBindings.Find(c => AreKeysEqual(c.Keys, currentKeyAsList));
- if (selectedCommandBinding != null)
- {
- setHandled(true);
- await selectedCommandBinding.InvokeAsync();
- }
- }
-
- if (updateRapidTravelFilter)
- {
- var currentLocation = await AppState.SelectedTab.CurrentLocation.Container.WithoutVirtualContainer(RAPIDTRAVEL);
- var newLocation = new VirtualContainer(
- currentLocation,
- new List, IEnumerable>>()
- {
- container => container.Where(c => c.Name.ToLower().Contains(AppState.RapidTravelText))
- },
- new List, IEnumerable>>()
- {
- element => element.Where(e => e.Name.ToLower().Contains(AppState.RapidTravelText))
- },
- virtualContainerName: 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 void ReadInputs(List inputs, Action inputHandler)
- {
- ReadInputs(inputs, () => { inputHandler(); return Task.CompletedTask; });
- }
- private void ReadInputs(List inputs, Func inputHandler)
- {
- Inputs = inputs.ConvertAll(i => new InputElementWrapper(i, i.DefaultValue));
- _inputHandler = inputHandler;
- }
-
- public async Task ReadInputs(IEnumerable fields)
- {
- var waiting = true;
- var result = new string[0];
- ReadInputs(fields.ToList(), () =>
- {
- if (Inputs != null)
- {
- result = Inputs.Select(i => i.Value).ToArray();
- }
- waiting = false;
- });
-
- while (waiting) await Task.Delay(100);
-
- return result;
- }
-
- private void ShowMessageBox(string text, Func inputHandler)
- {
- MessageBoxText = text;
- _inputHandler = inputHandler;
- }
-
- private static bool AreKeysEqual(IReadOnlyList collection1, IReadOnlyList 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(KeyWithModifiers key1, KeyWithModifiers key2) =>
- key1.Key == key2.Key
- && key1.Alt == key2.Alt
- && key1.Shift == key2.Shift
- && key1.Ctrl == key2.Ctrl;
-
- private void InitCommandBindings()
- {
- var commandBindings = new List()
- {
- new CommandBinding(
- "enter rapid travel mode",
- FileTime.App.Core.Command.Commands.EnterRapidTravel,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.OemComma, shift: true)},
- EnterRapidTravelMode),
- new CommandBinding(
- "create container",
- FileTime.App.Core.Command.Commands.CreateContainer,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.C),new KeyWithModifiers(Key.C)},
- CreateContainer),
- new CommandBinding(
- "create container",
- FileTime.App.Core.Command.Commands.CreateContainer,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.F7)},
- CreateContainer),
- new CommandBinding(
- "create element",
- FileTime.App.Core.Command.Commands.CreateElement,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.C),new KeyWithModifiers(Key.E)},
- CreateElement),
- new CommandBinding(
- "move to first",
- FileTime.App.Core.Command.Commands.MoveToTop,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.G),new KeyWithModifiers(Key.G)},
- MoveToFirst),
- new CommandBinding(
- "move to last",
- FileTime.App.Core.Command.Commands.MoveToBottom,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.G, shift: true)},
- MoveToLast),
- new CommandBinding(
- "go to provider",
- FileTime.App.Core.Command.Commands.GoToProvider,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.G),new KeyWithModifiers(Key.T)},
- GotToProvider),
- new CommandBinding(
- "go to root",
- FileTime.App.Core.Command.Commands.GoToRoot,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.G),new KeyWithModifiers(Key.R)},
- GotToRoot),
- new CommandBinding(
- "go to home",
- FileTime.App.Core.Command.Commands.GoToHome,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.G),new KeyWithModifiers(Key.H)},
- GotToHome),
- new CommandBinding(
- "switch to tab 1",
- FileTime.App.Core.Command.Commands.GoToHome,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D1)},
- async() => await SwitchToTab(1)),
- new CommandBinding(
- "switch to tab 2",
- FileTime.App.Core.Command.Commands.GoToHome,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D2)},
- async() => await SwitchToTab(2)),
- new CommandBinding(
- "switch to tab 3",
- FileTime.App.Core.Command.Commands.GoToHome,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D3)},
- async() => await SwitchToTab(3)),
- new CommandBinding(
- "switch to tab 4",
- FileTime.App.Core.Command.Commands.GoToHome,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D4)},
- async() => await SwitchToTab(4)),
- new CommandBinding(
- "switch to tab 5",
- FileTime.App.Core.Command.Commands.GoToHome,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D5)},
- async() => await SwitchToTab(5)),
- new CommandBinding(
- "switch to tab 6",
- FileTime.App.Core.Command.Commands.GoToHome,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D6)},
- async() => await SwitchToTab(6)),
- new CommandBinding(
- "switch to tab 7",
- FileTime.App.Core.Command.Commands.GoToHome,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D7)},
- async() => await SwitchToTab(7)),
- new CommandBinding(
- "switch to tab 8",
- FileTime.App.Core.Command.Commands.GoToHome,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D8)},
- async() => await SwitchToTab(8)),
- new CommandBinding(
- "switch to last tab",
- FileTime.App.Core.Command.Commands.GoToHome,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D9)},
- async() => await SwitchToTab(-1)),
- new CommandBinding(
- "close tab",
- FileTime.App.Core.Command.Commands.GoToHome,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.Q)},
- CloseTab),
- new CommandBinding(
- "select",
- FileTime.App.Core.Command.Commands.Select,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.Space)},
- MarkCurrentItem),
- new CommandBinding(
- "copy",
- FileTime.App.Core.Command.Commands.Copy,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.Y),new KeyWithModifiers(Key.Y)},
- Copy),
- new CommandBinding(
- "cut",
- FileTime.App.Core.Command.Commands.Cut,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D),new KeyWithModifiers(Key.D)},
- Cut),
- new CommandBinding(
- "delete",
- FileTime.App.Core.Command.Commands.Delete,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D),new KeyWithModifiers(Key.D, shift: true)},
- SoftDelete),
- new CommandBinding(
- "hard delete",
- FileTime.App.Core.Command.Commands.Delete,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.D, shift: true),new KeyWithModifiers(Key.D, shift: true)},
- HardDelete),
- new CommandBinding(
- "paste merge",
- FileTime.App.Core.Command.Commands.PasteMerge,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.P),new KeyWithModifiers(Key.P)},
- PasteMerge),
- new CommandBinding(
- "paste (overwrite)",
- FileTime.App.Core.Command.Commands.PasteOverwrite,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.P),new KeyWithModifiers(Key.O)},
- PasteOverwrite),
- new CommandBinding(
- "paste (skip)",
- FileTime.App.Core.Command.Commands.PasteSkip,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.P),new KeyWithModifiers(Key.S)},
- PasteSkip),
- new CommandBinding(
- "rename",
- FileTime.App.Core.Command.Commands.Rename,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.C),new KeyWithModifiers(Key.W)},
- Rename),
- new CommandBinding(
- "rename",
- FileTime.App.Core.Command.Commands.Rename,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.F2)},
- Rename),
- new CommandBinding(
- "timeline pause",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.T),new KeyWithModifiers(Key.P)},
- PauseTimeline),
- new CommandBinding(
- "timeline start",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.T),new KeyWithModifiers(Key.S)},
- ContinueTimeline),
- new CommandBinding(
- "refresh timeline",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.T),new KeyWithModifiers(Key.R)},
- RefreshTimeline),
- new CommandBinding(
- "refresh",
- FileTime.App.Core.Command.Commands.Refresh,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.R)},
- RefreshCurrentLocation),
- new CommandBinding(
- "refresh",
- FileTime.App.Core.Command.Commands.Refresh,
- new KeyWithModifiers[]{new KeyWithModifiers(Key.F5)},
- RefreshCurrentLocation),
- new CommandBinding(
- "go to",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.L, ctrl: true) },
- GoToContainer),
- new CommandBinding(
- "toggle advanced icons",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.Z), new KeyWithModifiers(Key.I) },
- ToggleAdvancedIcons),
- new CommandBinding(
- "show all shortcut",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.F1) },
- ShowAllShortcut),
- new CommandBinding(
- "run command",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.D4, shift: true) },
- RunCommandInContainer),
- new CommandBinding(
- "copy path",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.C), new KeyWithModifiers(Key.P) },
- CopyPath),
- new CommandBinding(
- "select previous timeline block",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.H) },
- SelectPreviousTimelineBlock),
- new CommandBinding(
- "select next timeline command",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.J) },
- SelectNextTimelineCommand),
- new CommandBinding(
- "select previous timeline command",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.K) },
- SelectPreviousTimelineCommand),
- new CommandBinding(
- "select next timeline block",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.L) },
- SelectNextTimelineBlock),
- new CommandBinding(
- "command running mode",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.T), new KeyWithModifiers(Key.M) },
- ChangeTimelineMode),
- new CommandBinding(
- "toggle auto refresh",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.R, shift: true) },
- ToggleAutoRefresh),
- //TODO REMOVE
- new CommandBinding(
- "open in default file browser",
- FileTime.App.Core.Command.Commands.Dummy,
- new KeyWithModifiers[] { new KeyWithModifiers(Key.O), new KeyWithModifiers(Key.E) },
- OpenInDefaultFileExplorer),
- };
- var universalCommandBindings = new List()
- {
- new CommandBinding("go up", FileTime.App.Core.Command.Commands.GoUp, new KeyWithModifiers[]{new KeyWithModifiers(Key.Left)}, GoUp),
- new CommandBinding("open", FileTime.App.Core.Command.Commands.Open, new KeyWithModifiers[]{new KeyWithModifiers(Key.Right)}, OpenContainer),
- new CommandBinding("open or run", FileTime.App.Core.Command.Commands.OpenOrRun, new KeyWithModifiers[]{new KeyWithModifiers(Key.Enter)}, OpenOrRun),
- new CommandBinding("cursor up", FileTime.App.Core.Command.Commands.MoveCursorUp, new KeyWithModifiers[]{new KeyWithModifiers(Key.Up)}, MoveCursorUp),
- new CommandBinding("cursor down", FileTime.App.Core.Command.Commands.MoveCursorDown, new KeyWithModifiers[]{new KeyWithModifiers(Key.Down)}, MoveCursorDown),
- new CommandBinding("cursor page up", FileTime.App.Core.Command.Commands.MoveCursorUpPage, new KeyWithModifiers[]{new KeyWithModifiers(Key.PageUp)}, MoveCursorUpPage),
- new CommandBinding("cursor page down", FileTime.App.Core.Command.Commands.MoveCursorDownPage, new KeyWithModifiers[]{new KeyWithModifiers(Key.PageDown)}, MoveCursorDownPage),
- };
-
- _commandBindings.AddRange(commandBindings);
- _universalCommandBindings.AddRange(universalCommandBindings);
+ KeyInputHandlerService.ProcessKeyDown(key, keyModifiers, setHandled);
}
}
}
diff --git a/src/GuiApp/FileTime.Avalonia/Views/MainWindow.axaml b/src/GuiApp/FileTime.Avalonia/Views/MainWindow.axaml
index 49ef781..8d30dda 100644
--- a/src/GuiApp/FileTime.Avalonia/Views/MainWindow.axaml
+++ b/src/GuiApp/FileTime.Avalonia/Views/MainWindow.axaml
@@ -17,6 +17,8 @@
ExtendClientAreaToDecorationsHint="True"
Opened="OnWindowOpened"
Closed="OnWindowClosed"
+ x:DataType="vm:MainPageViewModel"
+ x:CompileBindings="True"
mc:Ignorable="d">
@@ -149,7 +151,7 @@
-
+
@@ -335,7 +337,7 @@
-
+