Rename GuiApp.App <-> GuiApp

This commit is contained in:
2023-08-03 13:34:14 +02:00
parent 259f8f7ba3
commit 28c1f30d6f
877 changed files with 245 additions and 245 deletions

View File

@@ -0,0 +1,91 @@
using Avalonia.Input;
namespace FileTime.GuiApp.App.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<Key> keys)
{
Keys = keys.Select(k => new KeyConfig(k)).ToList();
Command = command;
}
public CommandBindingConfiguration(string command, Key key)
{
Keys = new List<KeyConfig>() { new KeyConfig(key) };
Command = command;
}
public string GetKeysDisplayText()
{
var s = "";
foreach (var k in Keys)
{
var keyString = k.Key.ToString();
if (keyString.Length == 1)
{
s += AddKeyWithCtrlOrAlt(k, s, (_, _, _) => k.Shift ? keyString.ToUpper() : keyString.ToLower());
}
else
{
s += AddKeyWithCtrlOrAlt(k, s, AddSpecialKey);
}
}
return s;
}
private static string AddKeyWithCtrlOrAlt(KeyConfig key, string currentText, Func<KeyConfig, string, bool, string> keyProcessor)
{
var s = "";
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;
}
}

View File

@@ -0,0 +1,8 @@
namespace FileTime.GuiApp.App.Configuration;
public class KeyBindingConfiguration
{
public bool UseDefaultBindings { get; set; } = true;
public List<CommandBindingConfiguration> DefaultKeyBindings { get; set; } = new();
public List<CommandBindingConfiguration> KeyBindings { get; set; } = new();
}

View File

@@ -0,0 +1,31 @@
using Avalonia.Input;
namespace FileTime.GuiApp.App.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;
}
public bool AreEquals(KeyConfig otherKeyConfig) =>
Key == otherKeyConfig.Key
&& Alt == otherKeyConfig.Alt
&& Shift == otherKeyConfig.Shift
&& Ctrl == otherKeyConfig.Ctrl;
}

View File

@@ -0,0 +1,144 @@
using Avalonia.Input;
using FileTime.App.Core.UserCommand;
using FileTime.Providers.LocalAdmin;
namespace FileTime.GuiApp.App.Configuration;
public static 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.ToString());
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(Key.R, shift: true)),
//new CommandBindingConfiguration(ConfigCommand.ChangeTimelineMode, new[] { Key.T, Key.M }),
new(CloseTabCommand.CommandName, Key.Q),
//new CommandBindingConfiguration(ConfigCommand.Compress, new[] { Key.Y, Key.C }),
new(CopyBase64Command.CommandName, new[] {Key.C, Key.B}),
new(CopyCommand.CommandName, new[] {Key.Y, Key.Y}),
//new CommandBindingConfiguration(ConfigCommand.CopyHash, new[] { Key.C, Key.H }),
new(CopyNativePathCommand.CommandName, new[] {Key.C, Key.P}),
new(CopyFilesToClipboardCommand.CommandName, new[] {Key.Y, Key.C}),
new(CreateContainer.CommandName, Key.F7),
new(CreateContainer.CommandName, new[] {Key.C, Key.C}),
new(CreateElementCommand.CommandName, new[] {Key.C, Key.E}),
//new CommandBindingConfiguration(ConfigCommand.Cut, new[] { Key.D, Key.D }),
//new CommandBindingConfiguration(ConfigCommand.Edit, new KeyConfig(Key.F4)),
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Key.OemComma, shift: true)),
new(EnterRapidTravelCommand.CommandName, new KeyConfig(Key.OemQuestion, shift: true)),
//new CommandBindingConfiguration(ConfigCommand.FindByName, new[] { Key.F, Key.N }),
//new CommandBindingConfiguration(ConfigCommand.FindByNameRegex, new[] { Key.F, Key.R }),
new(GoByFrequencyCommand.CommandName, Key.Z),
new(GoToHomeCommand.CommandName, new[] {Key.G, Key.H}),
new(GoToPathCommand.CommandName, new KeyConfig(Key.L, ctrl: true)),
new(GoToPathCommand.CommandName, new[] {Key.G, Key.P}),
new(GoToProviderCommand.CommandName, new[] {Key.G, Key.T}),
new(GoToRootCommand.CommandName, new[] {Key.G, Key.R}),
new(GoUpCommand.CommandName, Key.Left),
new(DeleteCommand.HardDeleteCommandName, new[] {new KeyConfig(Key.D, shift: true), new KeyConfig(Key.D, shift: true)}),
new(MarkCommand.CommandName, Key.Space),
new(MoveCursorToLastCommand.CommandName, new KeyConfig(Key.G, shift: true)),
new(MoveCursorToFirstCommand.CommandName, new[] {Key.G, Key.G}),
new(MoveCursorUpCommand.CommandName, Key.Up),
new(MoveCursorDownCommand.CommandName, Key.Down),
new(MoveCursorUpPageCommand.CommandName, Key.PageUp),
new(MoveCursorDownPageCommand.CommandName, Key.PageDown),
//new CommandBindingConfiguration(ConfigCommand.NextTimelineBlock, Key.L ),
//new CommandBindingConfiguration(ConfigCommand.NextTimelineCommand, Key.J ),
new(OpenSelectedCommand.CommandName, Key.Right),
new(OpenCommandPaletteCommand.CommandName, new[] {Key.F1}),
new(OpenCommandPaletteCommand.CommandName, new[] {new KeyConfig(Key.P, ctrl: true, shift: true)}),
new(OpenInDefaultFileExplorerCommand.CommandName, new[] {Key.O, Key.E}),
new(PasteCommand.PasteMergeCommandName, new[] {Key.P, Key.P}),
new(PasteCommand.PasteOverwriteCommandName, new[] {Key.P, Key.O}),
new(PasteCommand.PasteSkipCommandName, new[] {Key.P, Key.S}),
new(PasteFilesFromClipboardCommand.PasteMergeCommandName, new[] {new KeyConfig(Key.V, ctrl: true)}),
new(PasteFilesFromClipboardCommand.PasteOverwriteCommandName, new[] {new KeyConfig(Key.V, ctrl: true, shift: true)}),
//new CommandBindingConfiguration(ConfigCommand.PinFavorite, new[] { Key.F, Key.P }),
//new CommandBindingConfiguration(ConfigCommand.PreviousTimelineBlock, Key.H ),
//new CommandBindingConfiguration(ConfigCommand.PreviousTimelineCommand, Key.K ),
new(RefreshCommand.CommandName, Key.R),
new(RenameCommand.CommandName, Key.F2),
new(RenameCommand.CommandName, new[] {Key.C, Key.W}),
new(IdentifiableRunOrOpenCommand.CommandName, Key.Enter),
//new CommandBindingConfiguration(ConfigCommand.RunCommand, new KeyConfig(Key.D4, shift: true)),
//new CommandBindingConfiguration(ConfigCommand.ScanContainerSize, new[] { Key.C, Key.S }),
//new CommandBindingConfiguration(ConfigCommand.ShowAllShortcut, Key.F1),
new(DeleteCommand.SoftDeleteCommandName, new[] {new KeyConfig(Key.D), new KeyConfig(Key.D, shift: true)}),
new(IdentifiableSearchCommand.SearchByNameContainsCommandName, new[] {Key.S, Key.N}),
new(SwitchToTabCommand.SwitchToLastTabCommandName, new[] {new KeyConfig(Key.D9, alt: true)}),
new(SwitchToTabCommand.SwitchToTab1CommandName, new[] {new KeyConfig(Key.D1, alt: true)}),
new(SwitchToTabCommand.SwitchToTab2CommandName, new[] {new KeyConfig(Key.D2, alt: true)}),
new(SwitchToTabCommand.SwitchToTab3CommandName, new[] {new KeyConfig(Key.D3, alt: true)}),
new(SwitchToTabCommand.SwitchToTab4CommandName, new[] {new KeyConfig(Key.D4, alt: true)}),
new(SwitchToTabCommand.SwitchToTab5CommandName, new[] {new KeyConfig(Key.D5, alt: true)}),
new(SwitchToTabCommand.SwitchToTab6CommandName, new[] {new KeyConfig(Key.D6, alt: true)}),
new(SwitchToTabCommand.SwitchToTab7CommandName, new[] {new KeyConfig(Key.D7, alt: true)}),
new(SwitchToTabCommand.SwitchToTab8CommandName, new[] {new KeyConfig(Key.D8, alt: true)}),
new(PauseCommandSchedulerCommand.CommandName, new[] {Key.T, Key.P}),
//new CommandBindingConfiguration(ConfigCommand.TimelineRefresh, new[] { Key.T, Key.R }),
new(StartCommandSchedulerCommand.CommandName, new[] {Key.T, Key.S}),
//new CommandBindingConfiguration(ConfigCommand.ToggleAdvancedIcons, new[] { Key.Z, Key.I }),
};
private static void PopulateDefaultEditorPrograms(Dictionary<string, string?> configuration)
{
var editorPrograms = new List<ProgramConfiguration>()
{
new ProgramConfiguration(@"c:\Program Files\Notepad++\notepad++.exe"),
new ProgramConfiguration("notepad.exe"),
};
for (var i = 0; i < editorPrograms.Count; i++)
{
if (editorPrograms[i].Path is not string path) continue;
configuration.Add(
$"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Path)}",
path);
if (editorPrograms[i].Arguments is string arguments)
{
configuration.Add(
$"{SectionNames.ProgramsSectionName}:{nameof(ProgramsConfiguration.DefaultEditorPrograms)}:[{i}]:{nameof(ProgramConfiguration.Arguments)}",
arguments);
}
}
}
}

View File

@@ -0,0 +1,15 @@
namespace FileTime.GuiApp.App.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;
}
}

View File

@@ -0,0 +1,7 @@
namespace FileTime.GuiApp.App.Configuration;
public class ProgramsConfiguration
{
public List<ProgramConfiguration> DefaultEditorPrograms { get; set; } = new();
public List<ProgramConfiguration> EditorPrograms { get; set; } = new();
}

View File

@@ -0,0 +1,7 @@
namespace FileTime.GuiApp.App.Configuration;
public static class SectionNames
{
public const string KeybindingSectionName = "KeyBindings";
public const string ProgramsSectionName = "Programs";
}

View File

@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>FileTime.GuiApp.App</RootNamespace>
</PropertyGroup>
<PropertyGroup>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.0.1" />
<PackageReference Include="PropertyChanged.SourceGenerator" Version="1.0.8">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\AppCommon\FileTime.App.Core.Abstraction\FileTime.App.Core.Abstraction.csproj" />
<ProjectReference Include="..\..\..\Core\FileTime.Core.Models\FileTime.Core.Models.csproj" />
<ProjectReference Include="..\..\..\Providers\FileTime.Providers.LocalAdmin.Abstractions\FileTime.Providers.LocalAdmin.Abstractions.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,10 @@
using FileTime.Core.Models;
using FileTime.GuiApp.App.Models;
namespace FileTime.GuiApp.App.IconProviders;
public interface IIconProvider
{
ImagePath GetImage(IItem item);
bool EnableAdvancedIcons { get; set; }
}

View File

@@ -0,0 +1,14 @@
namespace FileTime.GuiApp.App.IconProviders;
public enum SpecialPathType
{
Home,
Downloads,
Music,
Videos,
Desktop,
Documents,
Images,
Templates,
PublicShare
}

View File

@@ -0,0 +1,9 @@
namespace FileTime.GuiApp.App.Models;
public enum GuiPanel
{
FileBrowser,
Timeline,
Drives,
Favorites,
}

View File

@@ -0,0 +1,8 @@
using FileTime.Core.Models;
namespace FileTime.GuiApp.App.Models;
public interface IHaveFullPath
{
FullName Path { get; }
}

View File

@@ -0,0 +1,20 @@
namespace FileTime.GuiApp.App.Models;
public class ImagePath
{
public string? Path { get; }
public ImagePathType Type { get; }
public object? Image { get; }
public ImagePath(ImagePathType type, string path)
{
Path = path;
Type = type;
}
public ImagePath(ImagePathType type, object image)
{
Image = image;
Type = type;
}
}

View File

@@ -0,0 +1,8 @@
namespace FileTime.GuiApp.App.Models;
public enum ImagePathType
{
Asset,
Absolute,
Raw
}

View File

@@ -0,0 +1,3 @@
namespace FileTime.GuiApp.App.Models;
public record SpecialKeysStatus(bool IsAltPressed, bool IsShiftPressed, bool IsCtrlPressed);

View File

@@ -0,0 +1,9 @@
using FileTime.Core.Models;
namespace FileTime.GuiApp.App.Services;
public interface IContextMenuProvider
{
List<object> GetContextMenuForFolder(IContainer container);
List<object> GetContextMenuForFile(IElement element);
}

View File

@@ -0,0 +1,3 @@
namespace FileTime.GuiApp.App.Services;
public interface IDefaultModeKeyInputHandler : IKeyInputHandler { }

View File

@@ -0,0 +1,10 @@
using FileTime.Core.Interactions;
using FileTime.GuiApp.App.ViewModels;
namespace FileTime.GuiApp.App.Services;
public interface IDialogService : IUserCommunicationService
{
IObservable<ReadInputsViewModel?> ReadInput { get; }
IObservable<MessageBoxViewModel?> LastMessageBox { get; }
}

View File

@@ -0,0 +1,9 @@
using Avalonia.Input;
using FileTime.GuiApp.App.Models;
namespace FileTime.GuiApp.App.Services;
public interface IKeyInputHandler
{
Task HandleInputKey(Key key, SpecialKeysStatus specialKeysStatus, Action<bool> setHandled);
}

View File

@@ -0,0 +1,8 @@
using Avalonia.Input;
namespace FileTime.GuiApp.App.Services;
public interface IKeyInputHandlerService
{
Task ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action<bool> setHandled);
}

View File

@@ -0,0 +1,10 @@
using FileTime.GuiApp.App.Configuration;
namespace FileTime.GuiApp.App.Services;
public interface IKeyboardConfigurationService
{
IReadOnlyList<CommandBindingConfiguration> CommandBindings { get; }
IReadOnlyList<CommandBindingConfiguration> UniversalCommandBindings { get; }
IReadOnlyList<CommandBindingConfiguration> AllShortcut { get; }
}

View File

@@ -0,0 +1,9 @@
using FileTime.App.Core.Services;
using FileTime.GuiApp.App.IconProviders;
namespace FileTime.GuiApp.App.Services;
public interface IPlacesService : IStartupHandler
{
Dictionary<string, SpecialPathType> GetSpecialPaths();
}

View File

@@ -0,0 +1,3 @@
namespace FileTime.GuiApp.App.Services;
public interface IRapidTravelModeKeyInputHandler : IKeyInputHandler { }

View File

@@ -0,0 +1,10 @@
using Avalonia.Controls;
namespace FileTime.GuiApp.App.Services;
public interface IUiAccessor
{
public TopLevel? GetTopLevel();
Task InvokeOnUIThread(Func<Task> func);
Task<T> InvokeOnUIThread<T>(Func<Task<T>> func);
}

View File

@@ -0,0 +1,22 @@
using System.Collections.ObjectModel;
using DeclarativeProperty;
using FileTime.App.Core.ViewModels;
using FileTime.Core.Models;
using FileTime.GuiApp.App.Configuration;
using FileTime.GuiApp.App.Models;
namespace FileTime.GuiApp.App.ViewModels;
public interface IGuiAppState : IAppState
{
List<KeyConfig> PreviousKeys { get; }
bool IsAllShortcutVisible { get; set; }
bool NoCommandFound { get; set; }
List<CommandBindingConfiguration> PossibleCommands { get; set; }
ObservableCollection<RootDriveInfo> RootDriveInfos { get; set; }
IReadOnlyList<PlaceInfo> Places { get; set; }
ObservableCollection<string> PopupTexts { get; }
IObservable<GuiPanel> ActivePanel { get; }
void SetActivePanel(GuiPanel newPanel);
}

View File

@@ -0,0 +1,36 @@
using FileTime.App.Core.ViewModels;
using FileTime.Core.Interactions;
using MvvmGen;
namespace FileTime.GuiApp.App.ViewModels;
[ViewModel]
public partial class MessageBoxViewModel : IModalViewModel
{
private readonly Action<MessageBoxViewModel, MessageBoxResult> _handler;
public string Text { get; }
public bool ShowCancel { get; }
public string OkText { get; }
public string CancelText { get; }
public string Name => "MessageBoxViewModel";
public MessageBoxViewModel(
string text,
Action<MessageBoxViewModel, MessageBoxResult> handler,
bool showCancel = true,
string? okText = null,
string? cancelText = null) : this()
{
_handler = handler;
Text = text;
ShowCancel = showCancel;
OkText = okText ?? "Yes";
CancelText = cancelText ?? "No";
}
[Command]
public void Ok() => _handler.Invoke(this, MessageBoxResult.Ok);
[Command]
public void Cancel() => _handler.Invoke(this, MessageBoxResult.Cancel);
}

View File

@@ -0,0 +1,20 @@
using FileTime.Core.Models;
using FileTime.GuiApp.App.Models;
namespace FileTime.GuiApp.App.ViewModels;
public class PlaceInfo : IHaveFullPath
{
public IContainer Container { get; }
public string DisplayName { get; }
public PlaceInfo(IContainer container, string displayName)
{
if (container.FullName is null) throw new ArgumentNullException($"{nameof(container.FullName)} of container can not be null");
Container = container;
DisplayName = displayName;
}
public FullName Path => Container.FullName!;
}

View File

@@ -0,0 +1,33 @@
using System.Collections.ObjectModel;
using FileTime.App.Core.ViewModels;
using FileTime.Core.Interactions;
using PropertyChanged.SourceGenerator;
namespace FileTime.GuiApp.App.ViewModels;
public class ReadInputsViewModel : IModalViewModel
{
public string Name => "ReadInputs";
public required List<IInputElement> Inputs { get; init; }
public required Action<ReadInputsViewModel> SuccessHandler { get; init; }
public required Action<ReadInputsViewModel>? CancelHandler { get; init; }
public ObservableCollection<IPreviewElement> Previews { get; } = new();
public ReadInputsViewModel()
{
}
public ReadInputsViewModel(
List<IInputElement> inputs,
Action<ReadInputsViewModel> successHandler,
Action<ReadInputsViewModel>? cancelHandler = null)
{
Inputs = inputs;
SuccessHandler = successHandler;
CancelHandler = cancelHandler;
}
public void Process() => SuccessHandler.Invoke(this);
public void Cancel() => CancelHandler?.Invoke(this);
}

View File

@@ -0,0 +1,57 @@
using System.ComponentModel;
using System.Runtime.InteropServices;
using FileTime.Core.Models;
using FileTime.GuiApp.App.Models;
using PropertyChanged.SourceGenerator;
using IContainer = FileTime.Core.Models.IContainer;
namespace FileTime.GuiApp.App.ViewModels;
public partial class RootDriveInfo : IHaveFullPath, INotifyPropertyChanged
{
private readonly DriveInfo _driveInfo;
[Notify] private string _name;
[Notify] private string _fullName;
[Notify] private string? _label;
[Notify] private long _size = 0;
[Notify] private long _free = 0;
[Notify] private long _used = 0;
[Notify] public long UsedPercentage => Size == 0 ? 0 : Used * 100 / Size;
public FullName Path { get; }
public RootDriveInfo(DriveInfo driveInfo, IContainer container)
{
_driveInfo = driveInfo;
_name = container.Name;
_fullName = _name;
try
{
_fullName = container.FullName?.Path[(container.Provider.FullName!.Path.Length + 1)..] ?? _fullName;
}
catch
{
}
Path = container.FullName ?? throw new NullReferenceException($"Container does not have a {nameof(FullName)}");
Refresh();
}
private void Refresh()
{
Label = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? _driveInfo.VolumeLabel : null;
Size = _driveInfo.TotalSize;
Free = _driveInfo.AvailableFreeSpace;
Used = _driveInfo.TotalSize - _driveInfo.AvailableFreeSpace;
}
}