Move common things to AppCore from GuiApp
This commit is contained in:
@@ -12,8 +12,4 @@
|
||||
<ProjectReference Include="..\FileTime.App.FuzzyPanel.Abstraction\FileTime.App.FuzzyPanel.Abstraction.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Avalonia.Input;
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.App.FuzzyPanel;
|
||||
|
||||
@@ -8,5 +8,5 @@ public interface ICommandPaletteViewModel : IFuzzyPanelViewModel<ICommandPalette
|
||||
{
|
||||
IObservable<bool> ShowWindow { get; }
|
||||
void Close();
|
||||
Task<bool> HandleKeyUp(KeyEventArgs keyEventArgs);
|
||||
Task<bool> HandleKeyUp(GeneralKeyEventArgs keyEventArgs);
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\GuiApp\Avalonia\FileTime.GuiApp.App.Abstractions\FileTime.GuiApp.App.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.CommandPalette.Abstractions\FileTime.App.CommandPalette.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.FuzzyPanel\FileTime.App.FuzzyPanel.csproj" />
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
using System.Text;
|
||||
using Avalonia.Input;
|
||||
using FileTime.App.CommandPalette.Services;
|
||||
using FileTime.App.Core.Configuration;
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.App.FuzzyPanel;
|
||||
using FileTime.GuiApp.App.Configuration;
|
||||
using FileTime.GuiApp.App.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace FileTime.App.CommandPalette.ViewModels;
|
||||
@@ -89,7 +88,7 @@ public class CommandPaletteViewModel : FuzzyPanelViewModel<ICommandPaletteEntryV
|
||||
.Select(k => k.Keys)
|
||||
.ToList();
|
||||
|
||||
public override async Task<bool> HandleKeyDown(KeyEventArgs keyEventArgs)
|
||||
public override async Task<bool> HandleKeyDown(GeneralKeyEventArgs keyEventArgs)
|
||||
{
|
||||
if (keyEventArgs.Handled) return false;
|
||||
|
||||
@@ -99,7 +98,7 @@ public class CommandPaletteViewModel : FuzzyPanelViewModel<ICommandPaletteEntryV
|
||||
return true;
|
||||
}
|
||||
|
||||
if (keyEventArgs.Key == Key.Escape)
|
||||
if (keyEventArgs.Key == Keys.Escape)
|
||||
{
|
||||
keyEventArgs.Handled = true;
|
||||
Close();
|
||||
@@ -109,11 +108,11 @@ public class CommandPaletteViewModel : FuzzyPanelViewModel<ICommandPaletteEntryV
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> HandleKeyUp(KeyEventArgs keyEventArgs)
|
||||
public async Task<bool> HandleKeyUp(GeneralKeyEventArgs keyEventArgs)
|
||||
{
|
||||
if (keyEventArgs.Handled) return false;
|
||||
|
||||
if (keyEventArgs.Key == Key.Enter)
|
||||
if (keyEventArgs.Key == Keys.Enter)
|
||||
{
|
||||
if (SelectedItem is null) return false;
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
using FileTime.App.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.Configuration;
|
||||
|
||||
public class CommandBindingConfiguration
|
||||
{
|
||||
public List<KeyConfig> Keys { get; set; }
|
||||
|
||||
public string Command { get; set; }
|
||||
|
||||
public string KeysDisplayText => GetKeysDisplayText();
|
||||
|
||||
public CommandBindingConfiguration()
|
||||
{
|
||||
Command = null!;
|
||||
Keys = null!;
|
||||
}
|
||||
|
||||
public CommandBindingConfiguration(string command, IEnumerable<KeyConfig> keys)
|
||||
{
|
||||
Keys = new List<KeyConfig>(keys);
|
||||
Command = command;
|
||||
}
|
||||
|
||||
public CommandBindingConfiguration(string command, KeyConfig key)
|
||||
{
|
||||
Keys = new List<KeyConfig> { key };
|
||||
Command = command;
|
||||
}
|
||||
|
||||
public CommandBindingConfiguration(string command, IEnumerable<Keys> keys)
|
||||
{
|
||||
Keys = keys.Select(k => new KeyConfig(k)).ToList();
|
||||
Command = command;
|
||||
}
|
||||
|
||||
public CommandBindingConfiguration(string command, Keys key)
|
||||
{
|
||||
Keys = new List<KeyConfig>() { new(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 = "";
|
||||
|
||||
var 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,8 @@
|
||||
namespace FileTime.App.Core.Configuration;
|
||||
|
||||
public class KeyBindingConfiguration
|
||||
{
|
||||
public bool UseDefaultBindings { get; set; } = true;
|
||||
public List<CommandBindingConfiguration> DefaultKeyBindings { get; set; } = new();
|
||||
public List<CommandBindingConfiguration> KeyBindings { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using FileTime.App.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.Configuration;
|
||||
|
||||
public class KeyConfig
|
||||
{
|
||||
public Keys Key { get; set; }
|
||||
public bool Shift { get; set; }
|
||||
public bool Alt { get; set; }
|
||||
public bool Ctrl { get; set; }
|
||||
|
||||
public KeyConfig() { }
|
||||
|
||||
public KeyConfig(
|
||||
Keys key,
|
||||
bool shift = false,
|
||||
bool alt = false,
|
||||
bool ctrl = false)
|
||||
{
|
||||
Key = key;
|
||||
Shift = shift;
|
||||
Alt = alt;
|
||||
Ctrl = ctrl;
|
||||
}
|
||||
|
||||
public bool AreEquals(KeyConfig otherKeyConfig) =>
|
||||
Key.Equals(otherKeyConfig.Key)
|
||||
&& Alt == otherKeyConfig.Alt
|
||||
&& Shift == otherKeyConfig.Shift
|
||||
&& Ctrl == otherKeyConfig.Ctrl;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace FileTime.App.Core.Configuration;
|
||||
|
||||
public class ProgramConfiguration
|
||||
{
|
||||
public string? Path { get; set; }
|
||||
public string? Arguments { get; set; }
|
||||
|
||||
public ProgramConfiguration() { }
|
||||
|
||||
public ProgramConfiguration(string? path, string? arguments = null)
|
||||
{
|
||||
Path = path;
|
||||
Arguments = arguments;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FileTime.App.Core.Configuration;
|
||||
|
||||
public class ProgramsConfiguration
|
||||
{
|
||||
public List<ProgramConfiguration> DefaultEditorPrograms { get; set; } = new();
|
||||
public List<ProgramConfiguration> EditorPrograms { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FileTime.App.Core.Configuration;
|
||||
|
||||
public static class SectionNames
|
||||
{
|
||||
public const string KeybindingSectionName = "KeyBindings";
|
||||
public const string ProgramsSectionName = "Programs";
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using FileTime.App.Core.Configuration;
|
||||
|
||||
namespace FileTime.App.Core.Extensions;
|
||||
|
||||
public static class KeyConfigExtensions
|
||||
{
|
||||
public static bool AreKeysEqual(this IReadOnlyList<KeyConfig> collection1, IReadOnlyList<KeyConfig> collection2)
|
||||
=> collection1.Count == collection2.Count && collection1.Zip(collection2).All(t => t.First.AreEquals(t.Second));
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace FileTime.App.Core.Models;
|
||||
|
||||
public class GeneralKeyEventArgs
|
||||
{
|
||||
private readonly Action<bool> _handledChanged;
|
||||
private bool _handled;
|
||||
public required Keys Key { get; init; }
|
||||
|
||||
public bool Handled
|
||||
{
|
||||
get => _handled;
|
||||
set
|
||||
{
|
||||
if (_handled != value)
|
||||
{
|
||||
_handled = value;
|
||||
_handledChanged(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public GeneralKeyEventArgs(Action<bool> handledChanged)
|
||||
{
|
||||
_handledChanged = handledChanged;
|
||||
}
|
||||
}
|
||||
58
src/AppCommon/FileTime.App.Core.Abstraction/Models/Keys.cs
Normal file
58
src/AppCommon/FileTime.App.Core.Abstraction/Models/Keys.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
namespace FileTime.App.Core.Models;
|
||||
|
||||
public enum Keys
|
||||
{
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
D,
|
||||
E,
|
||||
F,
|
||||
G,
|
||||
H,
|
||||
I,
|
||||
J,
|
||||
K,
|
||||
L,
|
||||
M,
|
||||
N,
|
||||
O,
|
||||
P,
|
||||
Q,
|
||||
R,
|
||||
S,
|
||||
T,
|
||||
U,
|
||||
V,
|
||||
W,
|
||||
X,
|
||||
Y,
|
||||
Z,
|
||||
F1,
|
||||
F2,
|
||||
F3,
|
||||
F4,
|
||||
F5,
|
||||
F6,
|
||||
F7,
|
||||
F8,
|
||||
F9,
|
||||
F10,
|
||||
F11,
|
||||
F12,
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
Enter,
|
||||
Escape,
|
||||
Back,
|
||||
Space,
|
||||
PageUp,
|
||||
PageDown,
|
||||
Comma,
|
||||
Question,
|
||||
Tab,
|
||||
LWin,
|
||||
RWin,
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using FileTime.App.Core.Models;
|
||||
|
||||
namespace FileTime.App.Core.Services;
|
||||
|
||||
public interface IAppKeyService<TKey>
|
||||
{
|
||||
Keys? MapKey(TKey key);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using FileTime.App.Core.Configuration;
|
||||
|
||||
namespace FileTime.App.Core.Services;
|
||||
|
||||
public interface IKeyboardConfigurationService
|
||||
{
|
||||
IReadOnlyList<CommandBindingConfiguration> CommandBindings { get; }
|
||||
IReadOnlyList<CommandBindingConfiguration> UniversalCommandBindings { get; }
|
||||
IReadOnlyList<CommandBindingConfiguration> AllShortcut { get; }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace FileTime.App.Core.Services;
|
||||
|
||||
public interface ILifecycleService
|
||||
{
|
||||
Task InitStartupHandlersAsync();
|
||||
Task ExitAsync();
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.UserCommand;
|
||||
using FileTime.Providers.LocalAdmin;
|
||||
|
||||
namespace FileTime.App.Core.Configuration;
|
||||
|
||||
public class MainConfiguration
|
||||
{
|
||||
private static readonly Lazy<List<CommandBindingConfiguration>> _defaultKeybindings = new(InitDefaultKeyBindings);
|
||||
|
||||
public static Dictionary<string, string?> Configuration { get; }
|
||||
|
||||
static MainConfiguration()
|
||||
{
|
||||
Configuration = new()
|
||||
{
|
||||
{AdminElevationConfiguration.SectionName + ":" + nameof(AdminElevationConfiguration.ServerExecutablePath), "FileTime.Server.exe"},
|
||||
};
|
||||
|
||||
PopulateDefaultEditorPrograms(Configuration);
|
||||
PopulateDefaultKeyBindings(Configuration, _defaultKeybindings.Value,
|
||||
SectionNames.KeybindingSectionName + ":" + nameof(KeyBindingConfiguration.DefaultKeyBindings));
|
||||
}
|
||||
|
||||
private static void PopulateDefaultKeyBindings(Dictionary<string, string?> configuration,
|
||||
List<CommandBindingConfiguration> commandBindingConfigs, string basePath)
|
||||
{
|
||||
for (var i = 0; i < commandBindingConfigs.Count; i++)
|
||||
{
|
||||
var baseKey = basePath + $":[{i}]:";
|
||||
var commandBindingConfig = commandBindingConfigs[i];
|
||||
configuration.Add(baseKey + nameof(CommandBindingConfiguration.Command),
|
||||
commandBindingConfig.Command);
|
||||
|
||||
for (var j = 0; j < commandBindingConfig.Keys.Count; j++)
|
||||
{
|
||||
var key = commandBindingConfig.Keys[j];
|
||||
var keyBaseKey = baseKey + $"keys:[{j}]:";
|
||||
configuration.Add(keyBaseKey + nameof(KeyConfig.Key), key.Key.ToString());
|
||||
configuration.Add(keyBaseKey + nameof(KeyConfig.Shift), key.Shift.ToString());
|
||||
configuration.Add(keyBaseKey + nameof(KeyConfig.Alt), key.Alt.ToString());
|
||||
configuration.Add(keyBaseKey + nameof(KeyConfig.Ctrl), key.Ctrl.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<CommandBindingConfiguration> InitDefaultKeyBindings() =>
|
||||
new List<CommandBindingConfiguration>
|
||||
{
|
||||
//new CommandBindingConfiguration(ConfigCommand.AutoRefresh, new KeyConfig(Keys.R, shift: true)),
|
||||
//new CommandBindingConfiguration(ConfigCommand.ChangeTimelineMode, new[] { Keys.T, Keys.M }),
|
||||
new(CloseTabCommand.CommandName, Keys.Q),
|
||||
//new CommandBindingConfiguration(ConfigCommand.Compress, new[] { Keys.Y, Keys.C }),
|
||||
new(CopyBase64Command.CommandName, new[] {Keys.C, Keys.B}),
|
||||
new(CopyCommand.CommandName, new[] {Keys.Y, Keys.Y}),
|
||||
//new CommandBindingConfiguration(ConfigCommand.CopyHash, new[] { Keys.C, Keys.H }),
|
||||
new(CopyNativePathCommand.CommandName, new[] {Keys.C, Keys.P}),
|
||||
new(CopyFilesToClipboardCommand.CommandName, new[] {Keys.Y, Keys.C}),
|
||||
new(CreateContainer.CommandName, Keys.F7),
|
||||
new(CreateContainer.CommandName, new[] {Keys.C, Keys.C}),
|
||||
new(CreateElementCommand.CommandName, new[] {Keys.C, Keys.E}),
|
||||
//new CommandBindingConfiguration(ConfigCommand.Cut, new[] { Keys.D, Keys.D }),
|
||||
//new CommandBindingConfiguration(ConfigCommand.Edit, new KeyConfig(Keys.F4)),
|
||||
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Keys.Comma, shift: true)),
|
||||
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Keys.Question, shift: true)),
|
||||
new(GoBackCommand.CommandName, new KeyConfig(Keys.Left, alt: true)),
|
||||
new(GoByFrequencyCommand.CommandName, Keys.Z),
|
||||
new(GoForwardCommand.CommandName, new KeyConfig(Keys.Right, alt: true)),
|
||||
new(GoToHomeCommand.CommandName, new[] {Keys.G, Keys.H}),
|
||||
new(GoToPathCommand.CommandName, new KeyConfig(Keys.L, ctrl: true)),
|
||||
new(GoToPathCommand.CommandName, new[] {Keys.G, Keys.P}),
|
||||
new(GoToProviderCommand.CommandName, new[] {Keys.G, Keys.T}),
|
||||
new(GoToRootCommand.CommandName, new[] {Keys.G, Keys.R}),
|
||||
new(GoUpCommand.CommandName, Keys.Left),
|
||||
new(DeleteCommand.HardDeleteCommandName, new[] {new KeyConfig(Keys.D, shift: true), new KeyConfig(Keys.D, shift: true)}),
|
||||
new(MarkCommand.CommandName, Keys.Space),
|
||||
new(MoveCursorToLastCommand.CommandName, new KeyConfig(Keys.G, shift: true)),
|
||||
new(MoveCursorToFirstCommand.CommandName, new[] {Keys.G, Keys.G}),
|
||||
new(MoveCursorUpCommand.CommandName, Keys.Up),
|
||||
new(MoveCursorDownCommand.CommandName, Keys.Down),
|
||||
new(MoveCursorUpPageCommand.CommandName, Keys.PageUp),
|
||||
new(MoveCursorDownPageCommand.CommandName, Keys.PageDown),
|
||||
//new CommandBindingConfiguration(ConfigCommand.NextTimelineBlock, Keys.L ),
|
||||
//new CommandBindingConfiguration(ConfigCommand.NextTimelineCommand, Keys.J ),
|
||||
new(OpenSelectedCommand.CommandName, Keys.Right),
|
||||
new(OpenCommandPaletteCommand.CommandName, new[] {Keys.F1}),
|
||||
new(OpenCommandPaletteCommand.CommandName, new[] {new KeyConfig(Keys.P, ctrl: true, shift: true)}),
|
||||
new(OpenInDefaultFileExplorerCommand.CommandName, new[] {Keys.O, Keys.E}),
|
||||
new(PasteCommand.PasteMergeCommandName, new[] {Keys.P, Keys.P}),
|
||||
new(PasteCommand.PasteOverwriteCommandName, new[] {Keys.P, Keys.O}),
|
||||
new(PasteCommand.PasteSkipCommandName, new[] {Keys.P, Keys.S}),
|
||||
new(PasteFilesFromClipboardCommand.PasteMergeCommandName, new[] {new KeyConfig(Keys.V, ctrl: true)}),
|
||||
new(PasteFilesFromClipboardCommand.PasteOverwriteCommandName, new[] {new KeyConfig(Keys.V, ctrl: true, shift: true)}),
|
||||
//new CommandBindingConfiguration(ConfigCommand.PinFavorite, new[] { Keys.F, Keys.P }),
|
||||
//new CommandBindingConfiguration(ConfigCommand.PreviousTimelineBlock, Keys.H ),
|
||||
//new CommandBindingConfiguration(ConfigCommand.PreviousTimelineCommand, Keys.K ),
|
||||
new(RefreshCommand.CommandName, Keys.R),
|
||||
new(RenameCommand.CommandName, Keys.F2),
|
||||
new(RenameCommand.CommandName, new[] {Keys.C, Keys.W}),
|
||||
new(IdentifiableRunOrOpenCommand.CommandName, Keys.Enter),
|
||||
//new CommandBindingConfiguration(ConfigCommand.RunCommand, new KeyConfig(Keys.D4, shift: true)),
|
||||
//new CommandBindingConfiguration(ConfigCommand.ScanContainerSize, new[] { Keys.C, Keys.S }),
|
||||
//new CommandBindingConfiguration(ConfigCommand.ShowAllShortcut, Keys.F1),
|
||||
new(DeleteCommand.SoftDeleteCommandName, new[] {new KeyConfig(Keys.D), new KeyConfig(Keys.D, shift: true)}),
|
||||
new(IdentifiableSearchCommand.SearchByNameContainsCommandName, new[] {Keys.S, Keys.N}),
|
||||
new(SwitchToTabCommand.SwitchToLastTabCommandName, new[] {new KeyConfig(Keys.F9, alt: true)}),
|
||||
new(SwitchToTabCommand.SwitchToTab1CommandName, new[] {new KeyConfig(Keys.F1, alt: true)}),
|
||||
new(SwitchToTabCommand.SwitchToTab2CommandName, new[] {new KeyConfig(Keys.F2, alt: true)}),
|
||||
new(SwitchToTabCommand.SwitchToTab3CommandName, new[] {new KeyConfig(Keys.F3, alt: true)}),
|
||||
new(SwitchToTabCommand.SwitchToTab4CommandName, new[] {new KeyConfig(Keys.F4, alt: true)}),
|
||||
new(SwitchToTabCommand.SwitchToTab5CommandName, new[] {new KeyConfig(Keys.F5, alt: true)}),
|
||||
new(SwitchToTabCommand.SwitchToTab6CommandName, new[] {new KeyConfig(Keys.F6, alt: true)}),
|
||||
new(SwitchToTabCommand.SwitchToTab7CommandName, new[] {new KeyConfig(Keys.F7, alt: true)}),
|
||||
new(SwitchToTabCommand.SwitchToTab8CommandName, new[] {new KeyConfig(Keys.F8, alt: true)}),
|
||||
new(PauseCommandSchedulerCommand.CommandName, new[] {Keys.T, Keys.P}),
|
||||
//new CommandBindingConfiguration(ConfigCommand.TimelineRefresh, new[] { Keys.T, Keys.R }),
|
||||
new(StartCommandSchedulerCommand.CommandName, new[] {Keys.T, Keys.S}),
|
||||
//new CommandBindingConfiguration(ConfigCommand.ToggleAdvancedIcons, new[] { Keys.Z, Keys.I }),
|
||||
};
|
||||
|
||||
private static void PopulateDefaultEditorPrograms(Dictionary<string, string?> configuration)
|
||||
{
|
||||
var editorPrograms = new List<ProgramConfiguration>()
|
||||
{
|
||||
new(@"c:\Program Files\Notepad++\notepad++.exe"),
|
||||
new("notepad.exe"),
|
||||
};
|
||||
|
||||
for (var i = 0; i < editorPrograms.Count; i++)
|
||||
{
|
||||
if (editorPrograms[i].Path is not { } path) continue;
|
||||
configuration.Add(
|
||||
$"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Path)}",
|
||||
path);
|
||||
|
||||
if (editorPrograms[i].Arguments is { } arguments)
|
||||
{
|
||||
configuration.Add(
|
||||
$"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Arguments)}",
|
||||
arguments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.0" />
|
||||
<PackageReference Include="morelinq" Version="3.4.2" />
|
||||
<PackageReference Include="MvvmGen" Version="1.2.1" />
|
||||
<PackageReference Include="ObservableComputations" Version="2.3.0" />
|
||||
@@ -24,6 +25,7 @@
|
||||
<ProjectReference Include="..\..\Core\FileTime.Core.Models\FileTime.Core.Models.csproj" />
|
||||
<ProjectReference Include="..\..\Library\Defer\Defer.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FileTime.Providers.Local.Abstractions\FileTime.Providers.Local.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\Providers\FileTime.Providers.LocalAdmin.Abstractions\FileTime.Providers.LocalAdmin.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\Tools\FileTime.Tools\FileTime.Tools.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.CommandPalette.Abstractions\FileTime.App.CommandPalette.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\FileTime.App.CommandPalette\FileTime.App.CommandPalette.csproj" />
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
using FileTime.App.Core.Configuration;
|
||||
using FileTime.App.Core.UserCommand;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace FileTime.App.Core.Services;
|
||||
|
||||
public class KeyboardConfigurationService : IKeyboardConfigurationService
|
||||
{
|
||||
public IReadOnlyList<CommandBindingConfiguration> CommandBindings { get; }
|
||||
public IReadOnlyList<CommandBindingConfiguration> UniversalCommandBindings { get; }
|
||||
public IReadOnlyList<CommandBindingConfiguration> AllShortcut { get; }
|
||||
|
||||
public KeyboardConfigurationService(IOptions<KeyBindingConfiguration> keyBindingConfiguration)
|
||||
{
|
||||
IEnumerable<CommandBindingConfiguration> keyBindings = keyBindingConfiguration.Value.KeyBindings;
|
||||
|
||||
if (keyBindingConfiguration.Value.UseDefaultBindings)
|
||||
{
|
||||
keyBindings = keyBindings.Concat(keyBindingConfiguration.Value.DefaultKeyBindings);
|
||||
}
|
||||
|
||||
var commandBindings = new List<CommandBindingConfiguration>();
|
||||
var universalCommandBindings = new List<CommandBindingConfiguration>();
|
||||
foreach (var keyBinding in keyBindings)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(keyBinding.Command))
|
||||
{
|
||||
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>(UniversalCommandBindings.Concat(CommandBindings)).AsReadOnly();
|
||||
}
|
||||
|
||||
private static bool IsUniversal(CommandBindingConfiguration keyMapping)
|
||||
=> keyMapping.Command is
|
||||
GoUpCommand.CommandName
|
||||
or OpenSelectedCommand.CommandName
|
||||
or MoveCursorDownCommand.CommandName
|
||||
or MoveCursorDownPageCommand.CommandName
|
||||
or MoveCursorUpCommand.CommandName
|
||||
or MoveCursorUpPageCommand.CommandName
|
||||
or IdentifiableRunOrOpenCommand.CommandName;
|
||||
}
|
||||
65
src/AppCommon/FileTime.App.Core/Services/LifecycleService.cs
Normal file
65
src/AppCommon/FileTime.App.Core/Services/LifecycleService.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using FileTime.Core.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace FileTime.App.Core.Services;
|
||||
|
||||
public class LifecycleService : ILifecycleService
|
||||
{
|
||||
private readonly IEnumerable<IExitHandler> _exitHandlers;
|
||||
private readonly IEnumerable<IStartupHandler> _startupHandlers;
|
||||
private readonly ILogger<LifecycleService> _logger;
|
||||
|
||||
public LifecycleService(
|
||||
IEnumerable<IStartupHandler> startupHandlers,
|
||||
IEnumerable<IExitHandler> exitHandlers,
|
||||
ILogger<LifecycleService> logger)
|
||||
{
|
||||
_exitHandlers = exitHandlers;
|
||||
_startupHandlers = startupHandlers;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task InitStartupHandlersAsync()
|
||||
{
|
||||
foreach (var startupHandler in _startupHandlers)
|
||||
{
|
||||
try
|
||||
{
|
||||
await startupHandler.InitAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error while running startup handler {Handler}", startupHandler?.GetType().FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task ExitAsync()
|
||||
{
|
||||
var exitCancellation = new CancellationTokenSource(TimeSpan.FromSeconds(5));
|
||||
var exitHandlerTasks = _exitHandlers.Select(e =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return e.ExitAsync(exitCancellation.Token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error while running exit handler {Handler}", e.GetType().FullName);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(exitHandlerTasks).TimeoutAfter(10000);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
exitCancellation.Cancel();
|
||||
}
|
||||
}
|
||||
38
src/AppCommon/FileTime.App.Core/Services/ModalService.cs
Normal file
38
src/AppCommon/FileTime.App.Core/Services/ModalService.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using DynamicData;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace FileTime.App.Core.Services;
|
||||
|
||||
public class ModalService : IModalService
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly SourceList<IModalViewModel> _openModals = new();
|
||||
public IObservable<IChangeSet<IModalViewModel>> OpenModals { get; }
|
||||
public event EventHandler? AllModalClosed;
|
||||
|
||||
public ModalService(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
OpenModals = _openModals.Connect().StartWithEmpty();
|
||||
}
|
||||
|
||||
public void OpenModal(IModalViewModel modalToOpen) => _openModals.Add(modalToOpen);
|
||||
|
||||
public void CloseModal(IModalViewModel modalToClose)
|
||||
{
|
||||
_openModals.Remove(modalToClose);
|
||||
if (_openModals.Count == 0)
|
||||
{
|
||||
AllModalClosed?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public T OpenModal<T>() where T : IModalViewModel
|
||||
{
|
||||
var modal = _serviceProvider.GetRequiredService<T>();
|
||||
OpenModal(modal);
|
||||
|
||||
return modal;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,8 @@ public static class Startup
|
||||
serviceCollection.TryAddSingleton<ITimelineViewModel, TimelineViewModel>();
|
||||
serviceCollection.TryAddSingleton<IRefreshSmoothnessCalculator, RefreshSmoothnessCalculator>();
|
||||
serviceCollection.TryAddSingleton<IItemPreviewProvider, ElementPreviewProvider>();
|
||||
serviceCollection.TryAddSingleton<ILifecycleService, LifecycleService>();
|
||||
serviceCollection.TryAddSingleton<IModalService, ModalService>();
|
||||
|
||||
return serviceCollection
|
||||
.AddCommandHandlers()
|
||||
|
||||
@@ -12,8 +12,4 @@
|
||||
<ProjectReference Include="..\FileTime.App.FuzzyPanel.Abstraction\FileTime.App.FuzzyPanel.Abstraction.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Avalonia.Input;
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.App.FuzzyPanel;
|
||||
|
||||
@@ -8,5 +8,5 @@ public interface IFrequencyNavigationViewModel : IFuzzyPanelViewModel<string>, I
|
||||
{
|
||||
IObservable<bool> ShowWindow { get; }
|
||||
void Close();
|
||||
Task<bool> HandleKeyUp(KeyEventArgs keyEventArgs);
|
||||
Task<bool> HandleKeyUp(GeneralKeyEventArgs keyEventArgs);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using Avalonia.Input;
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.App.Core.UserCommand;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
@@ -30,11 +30,11 @@ public class FrequencyNavigationViewModel : FuzzyPanelViewModel<string>, IFreque
|
||||
public void Close()
|
||||
=> _frequencyNavigationService.CloseNavigationWindow();
|
||||
|
||||
public async Task<bool> HandleKeyUp(KeyEventArgs keyEventArgs)
|
||||
public async Task<bool> HandleKeyUp(GeneralKeyEventArgs keyEventArgs)
|
||||
{
|
||||
if (keyEventArgs.Handled) return false;
|
||||
|
||||
if (keyEventArgs.Key == Key.Enter)
|
||||
if (keyEventArgs.Key == Keys.Enter)
|
||||
{
|
||||
keyEventArgs.Handled = true;
|
||||
var targetContainer = await _timelessContentProvider.GetItemByFullNameAsync(new FullName(SelectedItem), PointInTime.Present);
|
||||
@@ -47,14 +47,14 @@ public class FrequencyNavigationViewModel : FuzzyPanelViewModel<string>, IFreque
|
||||
return false;
|
||||
}
|
||||
|
||||
public override async Task<bool> HandleKeyDown(KeyEventArgs keyEventArgs)
|
||||
public override async Task<bool> HandleKeyDown(GeneralKeyEventArgs keyEventArgs)
|
||||
{
|
||||
if (keyEventArgs.Handled) return false;
|
||||
var handled = await base.HandleKeyDown(keyEventArgs);
|
||||
|
||||
if (handled) return true;
|
||||
|
||||
if (keyEventArgs.Key == Key.Escape)
|
||||
if (keyEventArgs.Key == Keys.Escape)
|
||||
{
|
||||
keyEventArgs.Handled = true;
|
||||
Close();
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.0.2" />
|
||||
<ProjectReference Include="..\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Avalonia.Input;
|
||||
using FileTime.App.Core.Models;
|
||||
|
||||
namespace FileTime.App.FuzzyPanel;
|
||||
|
||||
@@ -8,5 +8,5 @@ public interface IFuzzyPanelViewModel<TItem> where TItem : class
|
||||
TItem? SelectedItem { get; }
|
||||
string SearchText { get; set; }
|
||||
void UpdateFilteredMatches();
|
||||
Task<bool> HandleKeyDown(KeyEventArgs keyEventArgs);
|
||||
Task<bool> HandleKeyDown(GeneralKeyEventArgs keyEventArgs);
|
||||
}
|
||||
@@ -7,7 +7,6 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.0.2" />
|
||||
<PackageReference Include="PropertyChanged.SourceGenerator" Version="1.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System.ComponentModel;
|
||||
using Avalonia.Input;
|
||||
using FileTime.App.Core.Models;
|
||||
using PropertyChanged.SourceGenerator;
|
||||
|
||||
namespace FileTime.App.FuzzyPanel;
|
||||
@@ -44,9 +44,9 @@ public abstract partial class FuzzyPanelViewModel<TItem> : IFuzzyPanelViewModel<
|
||||
|
||||
public abstract void UpdateFilteredMatches();
|
||||
|
||||
public virtual Task<bool> HandleKeyDown(KeyEventArgs keyEventArgs)
|
||||
public virtual Task<bool> HandleKeyDown(GeneralKeyEventArgs keyEventArgs)
|
||||
{
|
||||
if (keyEventArgs.Key == Key.Down)
|
||||
if (keyEventArgs.Key == Keys.Down)
|
||||
{
|
||||
var nextItem = SelectedItem is null
|
||||
? FilteredMatches.FirstOrDefault()
|
||||
@@ -60,7 +60,7 @@ public abstract partial class FuzzyPanelViewModel<TItem> : IFuzzyPanelViewModel<
|
||||
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
else if (keyEventArgs.Key == Key.Up)
|
||||
else if (keyEventArgs.Key == Keys.Up)
|
||||
{
|
||||
var previousItem = SelectedItem is null
|
||||
? FilteredMatches.LastOrDefault()
|
||||
|
||||
Reference in New Issue
Block a user