NativePath, Editor, ToastMessageSink
This commit is contained in:
@@ -12,6 +12,7 @@ namespace FileTime.App.Core.Command
|
|||||||
CreateContainer,
|
CreateContainer,
|
||||||
CreateElement,
|
CreateElement,
|
||||||
Cut,
|
Cut,
|
||||||
|
Edit,
|
||||||
EnterRapidTravel,
|
EnterRapidTravel,
|
||||||
GoToHome,
|
GoToHome,
|
||||||
GoToPath,
|
GoToPath,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ namespace FileTime.Core.Models
|
|||||||
{
|
{
|
||||||
string Name { get; }
|
string Name { get; }
|
||||||
string? FullName { get; }
|
string? FullName { get; }
|
||||||
|
string? NativePath { get; }
|
||||||
bool IsHidden { get; }
|
bool IsHidden { get; }
|
||||||
bool IsDestroyed { get; }
|
bool IsDestroyed { get; }
|
||||||
SupportsDelete CanDelete { get; }
|
SupportsDelete CanDelete { get; }
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace FileTime.Core.Models
|
|||||||
public string Name => BaseContainer.Name;
|
public string Name => BaseContainer.Name;
|
||||||
|
|
||||||
public string? FullName => BaseContainer.FullName;
|
public string? FullName => BaseContainer.FullName;
|
||||||
|
public string? NativePath => BaseContainer.NativePath;
|
||||||
|
|
||||||
public bool IsHidden => BaseContainer.IsHidden;
|
public bool IsHidden => BaseContainer.IsHidden;
|
||||||
public bool IsLoaded => BaseContainer.IsLoaded;
|
public bool IsLoaded => BaseContainer.IsLoaded;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace FileTime.Core.Providers
|
|||||||
#pragma warning restore CS8603 // Possible null reference return.
|
#pragma warning restore CS8603 // Possible null reference return.
|
||||||
|
|
||||||
public string? FullName => null;
|
public string? FullName => null;
|
||||||
|
public string? NativePath => null;
|
||||||
|
|
||||||
public bool IsHidden => false;
|
public bool IsHidden => false;
|
||||||
public bool IsLoaded => true;
|
public bool IsLoaded => true;
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ namespace FileTime.Core.Timeline
|
|||||||
|
|
||||||
public bool IsDestroyed { get; private set; }
|
public bool IsDestroyed { get; private set; }
|
||||||
|
|
||||||
|
//FIXME: currently this can be different of the real items NativePath, should be fixed
|
||||||
|
public string? NativePath => FullName;
|
||||||
|
|
||||||
public TimeContainer(string name, IContainer parent, IContentProvider contentProvider, IContentProvider virtualContentProvider, PointInTime pointInTime)
|
public TimeContainer(string name, IContainer parent, IContentProvider contentProvider, IContentProvider virtualContentProvider, PointInTime pointInTime)
|
||||||
{
|
{
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ namespace FileTime.Core.Timeline
|
|||||||
|
|
||||||
public string? FullName { get; }
|
public string? FullName { get; }
|
||||||
|
|
||||||
|
//FIXME: currently this can be different of the real items NativePath, should be fixed
|
||||||
|
public string? NativePath => FullName;
|
||||||
|
|
||||||
public bool IsHidden => false;
|
public bool IsHidden => false;
|
||||||
|
|
||||||
public SupportsDelete CanDelete => SupportsDelete.True;
|
public SupportsDelete CanDelete => SupportsDelete.True;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace FileTime.Core.Timeline
|
|||||||
public string Name => "time";
|
public string Name => "time";
|
||||||
|
|
||||||
public string? FullName => null;
|
public string? FullName => null;
|
||||||
|
public string? NativePath => null;
|
||||||
|
|
||||||
public bool IsHidden => false;
|
public bool IsHidden => false;
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ namespace FileTime.Avalonia
|
|||||||
ServiceProvider ??= DependencyInjection
|
ServiceProvider ??= DependencyInjection
|
||||||
.RegisterDefaultServices()
|
.RegisterDefaultServices()
|
||||||
.AddConfiguration()
|
.AddConfiguration()
|
||||||
.InitSerilog()
|
.AddServices()
|
||||||
.RegisterLogging()
|
.RegisterLogging()
|
||||||
.AddViewModels()
|
.AddViewModels()
|
||||||
.AddServices()
|
|
||||||
.RegisterCommandHandlers()
|
.RegisterCommandHandlers()
|
||||||
.BuildServiceProvider();
|
.BuildServiceProvider()
|
||||||
|
.InitSerilog();
|
||||||
|
|
||||||
var _logger = ServiceProvider.GetService<ILogger<App>>();
|
var _logger = ServiceProvider.GetService<ILogger<App>>();
|
||||||
_logger?.LogInformation("App initialization completed.");
|
_logger?.LogInformation("App initialization completed.");
|
||||||
|
|||||||
@@ -8,32 +8,32 @@ namespace FileTime.Avalonia.Configuration
|
|||||||
public static class MainConfiguration
|
public static class MainConfiguration
|
||||||
{
|
{
|
||||||
private static readonly Lazy<List<CommandBindingConfiguration>> _defaultKeybindings = new(InitDefaultKeyBindings);
|
private static readonly Lazy<List<CommandBindingConfiguration>> _defaultKeybindings = new(InitDefaultKeyBindings);
|
||||||
internal const string KeybindingBaseConfigKey = "KeyBindings";
|
|
||||||
|
|
||||||
public static Dictionary<string, string> Configuration { get; }
|
public static Dictionary<string, string> Configuration { get; }
|
||||||
|
|
||||||
static MainConfiguration()
|
static MainConfiguration()
|
||||||
{
|
{
|
||||||
Configuration = new();
|
Configuration = new();
|
||||||
PopulateDefaultKeyBindings(Configuration, _defaultKeybindings.Value, KeybindingBaseConfigKey + ":" + nameof(KeyBindingConfiguration.DefaultKeyBindings));
|
PopulateDefaultEditorPrograms(Configuration);
|
||||||
|
PopulateDefaultKeyBindings(Configuration, _defaultKeybindings.Value, SectionNames.KeybindingSectionName + ":" + nameof(KeyBindingConfiguration.DefaultKeyBindings));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void PopulateDefaultKeyBindings(Dictionary<string, string> keybindings, List<CommandBindingConfiguration> commandBindingConfigs, string basePath)
|
private static void PopulateDefaultKeyBindings(Dictionary<string, string> configuration, List<CommandBindingConfiguration> commandBindingConfigs, string basePath)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < commandBindingConfigs.Count; i++)
|
for (var i = 0; i < commandBindingConfigs.Count; i++)
|
||||||
{
|
{
|
||||||
var baseKey = basePath + $":[{i}]:";
|
var baseKey = basePath + $":[{i}]:";
|
||||||
var commandBindingConfig = commandBindingConfigs[i];
|
var commandBindingConfig = commandBindingConfigs[i];
|
||||||
keybindings.Add(baseKey + nameof(CommandBindingConfiguration.Command), commandBindingConfig.Command.ToString());
|
configuration.Add(baseKey + nameof(CommandBindingConfiguration.Command), commandBindingConfig.Command.ToString());
|
||||||
|
|
||||||
for (var j = 0; j < commandBindingConfig.Keys.Count; j++)
|
for (var j = 0; j < commandBindingConfig.Keys.Count; j++)
|
||||||
{
|
{
|
||||||
var key = commandBindingConfig.Keys[j];
|
var key = commandBindingConfig.Keys[j];
|
||||||
var keyBaseKey = baseKey + $"keys:[{j}]:";
|
var keyBaseKey = baseKey + $"keys:[{j}]:";
|
||||||
keybindings.Add(keyBaseKey + nameof(KeyConfig.Key), key.Key.ToString());
|
configuration.Add(keyBaseKey + nameof(KeyConfig.Key), key.Key.ToString());
|
||||||
keybindings.Add(keyBaseKey + nameof(KeyConfig.Shift), key.Shift.ToString());
|
configuration.Add(keyBaseKey + nameof(KeyConfig.Shift), key.Shift.ToString());
|
||||||
keybindings.Add(keyBaseKey + nameof(KeyConfig.Alt), key.Alt.ToString());
|
configuration.Add(keyBaseKey + nameof(KeyConfig.Alt), key.Alt.ToString());
|
||||||
keybindings.Add(keyBaseKey + nameof(KeyConfig.Ctrl), key.Ctrl.ToString());
|
configuration.Add(keyBaseKey + nameof(KeyConfig.Ctrl), key.Ctrl.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,6 +51,7 @@ namespace FileTime.Avalonia.Configuration
|
|||||||
new CommandBindingConfiguration(Commands.CreateContainer, new[] { Key.C, Key.C }),
|
new CommandBindingConfiguration(Commands.CreateContainer, new[] { Key.C, Key.C }),
|
||||||
new CommandBindingConfiguration(Commands.CreateElement, new[] { Key.C, Key.E }),
|
new CommandBindingConfiguration(Commands.CreateElement, new[] { Key.C, Key.E }),
|
||||||
new CommandBindingConfiguration(Commands.Cut, new[] { Key.D, Key.D }),
|
new CommandBindingConfiguration(Commands.Cut, new[] { Key.D, Key.D }),
|
||||||
|
new CommandBindingConfiguration(Commands.Edit, new KeyConfig(Key.F4)),
|
||||||
new CommandBindingConfiguration(Commands.EnterRapidTravel, new KeyConfig(Key.OemComma, shift: true)),
|
new CommandBindingConfiguration(Commands.EnterRapidTravel, new KeyConfig(Key.OemComma, shift: true)),
|
||||||
new CommandBindingConfiguration(Commands.GoToHome, new[] { Key.G, Key.H }),
|
new CommandBindingConfiguration(Commands.GoToHome, new[] { Key.G, Key.H }),
|
||||||
new CommandBindingConfiguration(Commands.GoToPath, new KeyConfig(Key.OemComma, ctrl: true)),
|
new CommandBindingConfiguration(Commands.GoToPath, new KeyConfig(Key.OemComma, ctrl: true)),
|
||||||
@@ -97,5 +98,25 @@ namespace FileTime.Avalonia.Configuration
|
|||||||
new CommandBindingConfiguration(Commands.MoveCursorDownPage, Key.PageDown),
|
new CommandBindingConfiguration(Commands.MoveCursorDownPage, Key.PageDown),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void PopulateDefaultEditorPrograms(Dictionary<string, string> configuration)
|
||||||
|
{
|
||||||
|
var editorPrograms = new List<ProgramConfiguration>()
|
||||||
|
{
|
||||||
|
new ProgramConfiguration(@"c:\Program Files\Notepad++\notepad++1.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
namespace FileTime.Avalonia.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,10 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Configuration
|
||||||
|
{
|
||||||
|
public class ProgramsConfiguration
|
||||||
|
{
|
||||||
|
public List<ProgramConfiguration> DefaultEditorPrograms { get; set; } = new();
|
||||||
|
public List<ProgramConfiguration> EditorPrograms { get; set; } = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace FileTime.Avalonia.Configuration
|
||||||
|
{
|
||||||
|
public static class SectionNames
|
||||||
|
{
|
||||||
|
internal const string KeybindingSectionName = "KeyBindings";
|
||||||
|
internal const string ProgramsSectionName = "Programs";
|
||||||
|
}
|
||||||
|
}
|
||||||
25
src/GuiApp/FileTime.Avalonia/Logging/ToastMessageSink.cs
Normal file
25
src/GuiApp/FileTime.Avalonia/Logging/ToastMessageSink.cs
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
using FileTime.Avalonia.Services;
|
||||||
|
using Serilog.Core;
|
||||||
|
using Serilog.Events;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Logging
|
||||||
|
{
|
||||||
|
public class ToastMessageSink : ILogEventSink
|
||||||
|
{
|
||||||
|
private readonly IDialogService dialogService;
|
||||||
|
|
||||||
|
public ToastMessageSink(IDialogService dialogService)
|
||||||
|
{
|
||||||
|
this.dialogService = dialogService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Emit(LogEvent logEvent)
|
||||||
|
{
|
||||||
|
if (logEvent.Level >= LogEventLevel.Error)
|
||||||
|
{
|
||||||
|
var message = logEvent.RenderMessage();
|
||||||
|
dialogService.ShowToastMessage(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,6 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Avalonia.Threading;
|
|
||||||
using FileTime.App.Core.Clipboard;
|
using FileTime.App.Core.Clipboard;
|
||||||
using FileTime.App.Core.Command;
|
using FileTime.App.Core.Command;
|
||||||
using FileTime.Avalonia.Application;
|
using FileTime.Avalonia.Application;
|
||||||
@@ -17,6 +16,7 @@ using FileTime.Core.Models;
|
|||||||
using FileTime.Core.Providers;
|
using FileTime.Core.Providers;
|
||||||
using FileTime.Core.Timeline;
|
using FileTime.Core.Timeline;
|
||||||
using FileTime.Providers.Local;
|
using FileTime.Providers.Local;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace FileTime.Avalonia.Services
|
namespace FileTime.Avalonia.Services
|
||||||
{
|
{
|
||||||
@@ -27,22 +27,26 @@ namespace FileTime.Avalonia.Services
|
|||||||
private readonly AppState _appState;
|
private readonly AppState _appState;
|
||||||
private readonly LocalContentProvider _localContentProvider;
|
private readonly LocalContentProvider _localContentProvider;
|
||||||
private readonly ItemNameConverterService _itemNameConverterService;
|
private readonly ItemNameConverterService _itemNameConverterService;
|
||||||
private readonly DialogService _dialogService;
|
private readonly IDialogService _dialogService;
|
||||||
private readonly IClipboard _clipboard;
|
private readonly IClipboard _clipboard;
|
||||||
private readonly TimeRunner _timeRunner;
|
private readonly TimeRunner _timeRunner;
|
||||||
private readonly IIconProvider _iconProvider;
|
private readonly IIconProvider _iconProvider;
|
||||||
private readonly IEnumerable<IContentProvider> _contentProviders;
|
private readonly IEnumerable<IContentProvider> _contentProviders;
|
||||||
private readonly Dictionary<Commands, Func<Task>> _commandHandlers;
|
private readonly Dictionary<Commands, Func<Task>> _commandHandlers;
|
||||||
|
private readonly ProgramsService _programsService;
|
||||||
|
private readonly ILogger<CommandHandlerService> _logger;
|
||||||
|
|
||||||
public CommandHandlerService(
|
public CommandHandlerService(
|
||||||
AppState appState,
|
AppState appState,
|
||||||
LocalContentProvider localContentProvider,
|
LocalContentProvider localContentProvider,
|
||||||
ItemNameConverterService itemNameConverterService,
|
ItemNameConverterService itemNameConverterService,
|
||||||
DialogService dialogService,
|
IDialogService dialogService,
|
||||||
IClipboard clipboard,
|
IClipboard clipboard,
|
||||||
TimeRunner timeRunner,
|
TimeRunner timeRunner,
|
||||||
IIconProvider iconProvider,
|
IIconProvider iconProvider,
|
||||||
IEnumerable<IContentProvider> contentProviders)
|
IEnumerable<IContentProvider> contentProviders,
|
||||||
|
ProgramsService programsService,
|
||||||
|
ILogger<CommandHandlerService> logger)
|
||||||
{
|
{
|
||||||
_appState = appState;
|
_appState = appState;
|
||||||
_localContentProvider = localContentProvider;
|
_localContentProvider = localContentProvider;
|
||||||
@@ -52,6 +56,8 @@ namespace FileTime.Avalonia.Services
|
|||||||
_timeRunner = timeRunner;
|
_timeRunner = timeRunner;
|
||||||
_iconProvider = iconProvider;
|
_iconProvider = iconProvider;
|
||||||
_contentProviders = contentProviders;
|
_contentProviders = contentProviders;
|
||||||
|
_programsService = programsService;
|
||||||
|
_logger = logger;
|
||||||
|
|
||||||
_commandHandlers = new Dictionary<Commands, Func<Task>>
|
_commandHandlers = new Dictionary<Commands, Func<Task>>
|
||||||
{
|
{
|
||||||
@@ -541,7 +547,7 @@ namespace FileTime.Avalonia.Services
|
|||||||
{
|
{
|
||||||
if (_appState.SelectedTab.CurrentLocation.Container is LocalFolder localFolder)
|
if (_appState.SelectedTab.CurrentLocation.Container is LocalFolder localFolder)
|
||||||
{
|
{
|
||||||
var path = localFolder.Directory.FullName;
|
var path = localFolder.NativePath;
|
||||||
if (path != null)
|
if (path != null)
|
||||||
{
|
{
|
||||||
Process.Start("explorer.exe", "\"" + path + "\"");
|
Process.Start("explorer.exe", "\"" + path + "\"");
|
||||||
@@ -553,23 +559,12 @@ namespace FileTime.Avalonia.Services
|
|||||||
|
|
||||||
private async Task CopyPath()
|
private async Task CopyPath()
|
||||||
{
|
{
|
||||||
string? textToCopy = null;
|
var currentContainer = _appState.SelectedTab.CurrentLocation.Container;
|
||||||
if (_appState.SelectedTab.CurrentLocation.Container is LocalFolder localFolder)
|
var textToCopy = currentContainer.NativePath;
|
||||||
{
|
|
||||||
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)
|
if (textToCopy != null && global::Avalonia.Application.Current?.Clipboard is global::Avalonia.Input.Platform.IClipboard clipboard)
|
||||||
{
|
{
|
||||||
await global::Avalonia.Application.Current.Clipboard.SetTextAsync(textToCopy);
|
await clipboard.SetTextAsync(textToCopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -783,6 +778,46 @@ namespace FileTime.Avalonia.Services
|
|||||||
|
|
||||||
private Task Edit()
|
private Task Edit()
|
||||||
{
|
{
|
||||||
|
if (_appState.SelectedTab.SelectedItem?.Item is IElement element && element.NativePath is string filePath)
|
||||||
|
{
|
||||||
|
var getNext = false;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var editorProgram = _programsService.GetEditorProgram(getNext);
|
||||||
|
if (editorProgram is null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (editorProgram.Path is string executablePath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(editorProgram.Arguments))
|
||||||
|
{
|
||||||
|
Process.Start(executablePath, "\"" + filePath + "\"");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var parts = editorProgram.Arguments.Split("%%1");
|
||||||
|
var arguments = string.Join("%%1", parts.Select(p => p.Replace("%1", "\"" + filePath + "\""))).Replace("%%1", "%1");
|
||||||
|
Process.Start(executablePath, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO: else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (System.ComponentModel.Win32Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Error while running editor program, possible the executable path does not exists.");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Unkown error while running editor program.");
|
||||||
|
}
|
||||||
|
getNext = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO: else
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ using FileTime.Core.Interactions;
|
|||||||
|
|
||||||
namespace FileTime.Avalonia.Services
|
namespace FileTime.Avalonia.Services
|
||||||
{
|
{
|
||||||
public class DialogService
|
public class DialogService : IDialogService
|
||||||
{
|
{
|
||||||
private readonly AppState _appState;
|
private readonly AppState _appState;
|
||||||
|
|
||||||
@@ -93,10 +93,9 @@ namespace FileTime.Avalonia.Services
|
|||||||
|
|
||||||
public void ShowToastMessage(string text)
|
public void ShowToastMessage(string text)
|
||||||
{
|
{
|
||||||
_appState.PopupTexts.Add(text);
|
|
||||||
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
|
await Dispatcher.UIThread.InvokeAsync(() => _appState.PopupTexts.Add(text));
|
||||||
await Task.Delay(5000);
|
await Task.Delay(5000);
|
||||||
await Dispatcher.UIThread.InvokeAsync(() => _appState.PopupTexts.Remove(text));
|
await Dispatcher.UIThread.InvokeAsync(() => _appState.PopupTexts.Remove(text));
|
||||||
});
|
});
|
||||||
|
|||||||
22
src/GuiApp/FileTime.Avalonia/Services/IDialogService.cs
Normal file
22
src/GuiApp/FileTime.Avalonia/Services/IDialogService.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FileTime.Avalonia.Misc;
|
||||||
|
using FileTime.Core.Interactions;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Services
|
||||||
|
{
|
||||||
|
public interface IDialogService
|
||||||
|
{
|
||||||
|
void CancelInputs();
|
||||||
|
void CancelMessageBox();
|
||||||
|
void ClearInputs();
|
||||||
|
Task ProcessInputs();
|
||||||
|
void ProcessMessageBox();
|
||||||
|
void ReadInputs(List<InputElement> inputs, Action<List<InputElementWrapper>> inputHandler);
|
||||||
|
void ReadInputs(List<InputElement> inputs, Func<List<InputElementWrapper>, Task> inputHandler);
|
||||||
|
Task<string?[]> ReadInputs(IEnumerable<InputElement> fields);
|
||||||
|
void ShowMessageBox(string text, Func<Task> inputHandler);
|
||||||
|
void ShowToastMessage(string text);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,13 +17,13 @@ namespace FileTime.Avalonia.Services
|
|||||||
private readonly AppState _appState;
|
private readonly AppState _appState;
|
||||||
private readonly KeyboardConfigurationService _keyboardConfigurationService;
|
private readonly KeyboardConfigurationService _keyboardConfigurationService;
|
||||||
private readonly CommandHandlerService _commandHandlerService;
|
private readonly CommandHandlerService _commandHandlerService;
|
||||||
private readonly DialogService _dialogService;
|
private readonly IDialogService _dialogService;
|
||||||
|
|
||||||
public KeyInputHandlerService(
|
public KeyInputHandlerService(
|
||||||
AppState appState,
|
AppState appState,
|
||||||
KeyboardConfigurationService keyboardConfigurationService,
|
KeyboardConfigurationService keyboardConfigurationService,
|
||||||
CommandHandlerService commandHandlerService,
|
CommandHandlerService commandHandlerService,
|
||||||
DialogService dialogService)
|
IDialogService dialogService)
|
||||||
{
|
{
|
||||||
_appState = appState;
|
_appState = appState;
|
||||||
_keyboardConfigurationService = keyboardConfigurationService;
|
_keyboardConfigurationService = keyboardConfigurationService;
|
||||||
|
|||||||
42
src/GuiApp/FileTime.Avalonia/Services/ProgramsService.cs
Normal file
42
src/GuiApp/FileTime.Avalonia/Services/ProgramsService.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using FileTime.Avalonia.Configuration;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace FileTime.Avalonia.Services
|
||||||
|
{
|
||||||
|
public class ProgramsService
|
||||||
|
{
|
||||||
|
private readonly List<ProgramConfiguration> _editorPrograms;
|
||||||
|
private int lastGoodEditorProgramIndex;
|
||||||
|
|
||||||
|
public ProgramsService(IOptions<ProgramsConfiguration> configuration)
|
||||||
|
{
|
||||||
|
var config = configuration.Value;
|
||||||
|
_editorPrograms = config.EditorPrograms.Count == 0 ? config.DefaultEditorPrograms : config.EditorPrograms;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProgramConfiguration? GetEditorProgram(bool getNext = false)
|
||||||
|
{
|
||||||
|
if (getNext)
|
||||||
|
{
|
||||||
|
lastGoodEditorProgramIndex++;
|
||||||
|
}
|
||||||
|
if (lastGoodEditorProgramIndex < 0)
|
||||||
|
{
|
||||||
|
lastGoodEditorProgramIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_editorPrograms.Count <= lastGoodEditorProgramIndex)
|
||||||
|
{
|
||||||
|
ResetLastGoodEditor();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return _editorPrograms[lastGoodEditorProgramIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetLastGoodEditor()
|
||||||
|
{
|
||||||
|
lastGoodEditorProgramIndex = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
using System.IO;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using FileTime.Avalonia.Application;
|
using FileTime.Avalonia.Application;
|
||||||
using FileTime.Avalonia.Configuration;
|
using FileTime.Avalonia.Configuration;
|
||||||
using FileTime.Avalonia.IconProviders;
|
using FileTime.Avalonia.IconProviders;
|
||||||
|
using FileTime.Avalonia.Logging;
|
||||||
using FileTime.Avalonia.Services;
|
using FileTime.Avalonia.Services;
|
||||||
using FileTime.Avalonia.ViewModels;
|
using FileTime.Avalonia.ViewModels;
|
||||||
using FileTime.Core.Command;
|
using FileTime.Core.Command;
|
||||||
@@ -12,6 +14,7 @@ using FileTime.Providers.Smb;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using Serilog.Configuration;
|
||||||
|
|
||||||
namespace FileTime.Avalonia
|
namespace FileTime.Avalonia
|
||||||
{
|
{
|
||||||
@@ -20,20 +23,22 @@ namespace FileTime.Avalonia
|
|||||||
internal static IServiceCollection AddViewModels(this IServiceCollection serviceCollection)
|
internal static IServiceCollection AddViewModels(this IServiceCollection serviceCollection)
|
||||||
{
|
{
|
||||||
return serviceCollection
|
return serviceCollection
|
||||||
.AddSingleton<AppState>()
|
|
||||||
.AddTransient<MainPageViewModel>()
|
.AddTransient<MainPageViewModel>()
|
||||||
.AddSingleton<IInputInterface, BasicInputHandler>();
|
.AddSingleton<IInputInterface, BasicInputHandler>();
|
||||||
}
|
}
|
||||||
internal static IServiceCollection AddServices(this IServiceCollection serviceCollection)
|
internal static IServiceCollection AddServices(this IServiceCollection serviceCollection)
|
||||||
{
|
{
|
||||||
serviceCollection = serviceCollection
|
serviceCollection = serviceCollection
|
||||||
|
.AddSingleton<AppState>()
|
||||||
.AddSingleton<ItemNameConverterService>()
|
.AddSingleton<ItemNameConverterService>()
|
||||||
.AddSingleton<StatePersistenceService>()
|
.AddSingleton<StatePersistenceService>()
|
||||||
.AddSingleton<CommandHandlerService>()
|
.AddSingleton<CommandHandlerService>()
|
||||||
.AddSingleton<KeyboardConfigurationService>()
|
.AddSingleton<KeyboardConfigurationService>()
|
||||||
.AddSingleton<KeyInputHandlerService>()
|
.AddSingleton<KeyInputHandlerService>()
|
||||||
.AddSingleton<DialogService>()
|
.AddSingleton<IDialogService, DialogService>()
|
||||||
.AddSingleton(new PersistenceSettings(Program.AppDataRoot))
|
.AddSingleton(new PersistenceSettings(Program.AppDataRoot))
|
||||||
|
.AddSingleton<ProgramsService>()
|
||||||
|
.AddSingleton<ToastMessageSink>()
|
||||||
.AddSmbServices()
|
.AddSmbServices()
|
||||||
.AddSingleton<IIconProvider, MaterialIconProvider>();
|
.AddSingleton<IIconProvider, MaterialIconProvider>();
|
||||||
|
|
||||||
@@ -74,13 +79,13 @@ namespace FileTime.Avalonia
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
return serviceCollection
|
return serviceCollection
|
||||||
.Configure<KeyBindingConfiguration>(configuration.GetSection(MainConfiguration.KeybindingBaseConfigKey))
|
.Configure<ProgramsConfiguration>(configuration.GetSection(SectionNames.ProgramsSectionName))
|
||||||
|
.Configure<KeyBindingConfiguration>(configuration.GetSection(SectionNames.KeybindingSectionName))
|
||||||
.AddSingleton<IConfiguration>(configuration);
|
.AddSingleton<IConfiguration>(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IServiceCollection InitSerilog(this IServiceCollection serviceCollection)
|
internal static IServiceProvider InitSerilog(this IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
using var serviceProvider = serviceCollection.BuildServiceProvider();
|
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
.ReadFrom.Configuration(serviceProvider.GetService<IConfiguration>())
|
.ReadFrom.Configuration(serviceProvider.GetService<IConfiguration>())
|
||||||
.Enrich.FromLogContext()
|
.Enrich.FromLogContext()
|
||||||
@@ -89,9 +94,17 @@ namespace FileTime.Avalonia
|
|||||||
fileSizeLimitBytes: 10 * 1024 * 1024,
|
fileSizeLimitBytes: 10 * 1024 * 1024,
|
||||||
rollOnFileSizeLimit: true,
|
rollOnFileSizeLimit: true,
|
||||||
rollingInterval: RollingInterval.Day)
|
rollingInterval: RollingInterval.Day)
|
||||||
|
.WriteTo.MessageBoxSink(serviceProvider)
|
||||||
.CreateLogger();
|
.CreateLogger();
|
||||||
|
|
||||||
return serviceCollection;
|
return serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LoggerConfiguration MessageBoxSink(
|
||||||
|
this LoggerSinkConfiguration loggerConfiguration,
|
||||||
|
IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
return loggerConfiguration.Sink(serviceProvider.GetService<ToastMessageSink>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
[Inject(typeof(ILogger<MainPageViewModel>), PropertyName = "_logger")]
|
[Inject(typeof(ILogger<MainPageViewModel>), PropertyName = "_logger")]
|
||||||
[Inject(typeof(KeyboardConfigurationService))]
|
[Inject(typeof(KeyboardConfigurationService))]
|
||||||
[Inject(typeof(CommandHandlerService), PropertyAccessModifier = AccessModifier.Public)]
|
[Inject(typeof(CommandHandlerService), PropertyAccessModifier = AccessModifier.Public)]
|
||||||
[Inject(typeof(DialogService))]
|
[Inject(typeof(IDialogService), PropertyName = "_dialogService")]
|
||||||
[Inject(typeof(KeyInputHandlerService))]
|
[Inject(typeof(KeyInputHandlerService))]
|
||||||
public partial class MainPageViewModel : IMainPageViewModelBase
|
public partial class MainPageViewModel : IMainPageViewModelBase
|
||||||
{
|
{
|
||||||
@@ -73,7 +73,7 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
|
|
||||||
_timeRunner = App.ServiceProvider.GetService<TimeRunner>()!;
|
_timeRunner = App.ServiceProvider.GetService<TimeRunner>()!;
|
||||||
var inputInterface = (BasicInputHandler)App.ServiceProvider.GetService<IInputInterface>()!;
|
var inputInterface = (BasicInputHandler)App.ServiceProvider.GetService<IInputInterface>()!;
|
||||||
inputInterface.InputHandler = DialogService.ReadInputs;
|
inputInterface.InputHandler = _dialogService.ReadInputs;
|
||||||
App.ServiceProvider.GetService<TopContainer>();
|
App.ServiceProvider.GetService<TopContainer>();
|
||||||
await StatePersistence.LoadStatesAsync();
|
await StatePersistence.LoadStatesAsync();
|
||||||
|
|
||||||
@@ -246,25 +246,25 @@ namespace FileTime.Avalonia.ViewModels
|
|||||||
[Command]
|
[Command]
|
||||||
public async void ProcessInputs()
|
public async void ProcessInputs()
|
||||||
{
|
{
|
||||||
await DialogService.ProcessInputs();
|
await _dialogService.ProcessInputs();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public void CancelInputs()
|
public void CancelInputs()
|
||||||
{
|
{
|
||||||
DialogService.CancelInputs();
|
_dialogService.CancelInputs();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public void ProcessMessageBox()
|
public void ProcessMessageBox()
|
||||||
{
|
{
|
||||||
DialogService.ProcessMessageBox();
|
_dialogService.ProcessMessageBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Command]
|
[Command]
|
||||||
public void CancelMessageBox()
|
public void CancelMessageBox()
|
||||||
{
|
{
|
||||||
DialogService.CancelMessageBox();
|
_dialogService.CancelMessageBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action<bool> setHandled)
|
public void ProcessKeyDown(Key key, KeyModifiers keyModifiers, Action<bool> setHandled)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace FileTime.Providers.Local
|
|||||||
public string Name { get; } = "local";
|
public string Name { get; } = "local";
|
||||||
|
|
||||||
public string? FullName { get; }
|
public string? FullName { get; }
|
||||||
|
public string? NativePath => null;
|
||||||
public bool IsHidden => false;
|
public bool IsHidden => false;
|
||||||
public bool IsLoaded => true;
|
public bool IsLoaded => true;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace FileTime.Providers.Local
|
|||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
public string FullName { get; }
|
public string FullName { get; }
|
||||||
|
public string? NativePath => File.FullName;
|
||||||
|
|
||||||
public IContentProvider Provider { get; }
|
public IContentProvider Provider { get; }
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace FileTime.Providers.Local
|
|||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
public string FullName { get; }
|
public string FullName { get; }
|
||||||
|
public string? NativePath => Directory.FullName;
|
||||||
|
|
||||||
public bool IsLoaded => _items != null;
|
public bool IsLoaded => _items != null;
|
||||||
public SupportsDelete CanDelete { get; }
|
public SupportsDelete CanDelete { get; }
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace FileTime.Providers.Smb
|
|||||||
public string Name { get; } = "smb";
|
public string Name { get; } = "smb";
|
||||||
|
|
||||||
public string? FullName { get; }
|
public string? FullName { get; }
|
||||||
|
public string? NativePath => null;
|
||||||
|
|
||||||
public bool IsHidden => false;
|
public bool IsHidden => false;
|
||||||
public bool IsLoaded => true;
|
public bool IsLoaded => true;
|
||||||
@@ -177,5 +178,7 @@ namespace FileTime.Providers.Smb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetNativePath(string fullName) => fullName.Replace("/", "\\");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Providers;
|
using FileTime.Core.Providers;
|
||||||
using SMBLibrary.Client;
|
|
||||||
|
|
||||||
namespace FileTime.Providers.Smb
|
namespace FileTime.Providers.Smb
|
||||||
{
|
{
|
||||||
@@ -11,6 +10,7 @@ namespace FileTime.Providers.Smb
|
|||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
public string? FullName { get; }
|
public string? FullName { get; }
|
||||||
|
public string? NativePath { get; }
|
||||||
|
|
||||||
public bool IsHidden => false;
|
public bool IsHidden => false;
|
||||||
public SupportsDelete CanDelete => SupportsDelete.True;
|
public SupportsDelete CanDelete => SupportsDelete.True;
|
||||||
@@ -25,6 +25,7 @@ namespace FileTime.Providers.Smb
|
|||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
FullName = parent.FullName + Constants.SeparatorChar + Name;
|
FullName = parent.FullName + Constants.SeparatorChar + Name;
|
||||||
|
NativePath = SmbContentProvider.GetNativePath(FullName);
|
||||||
|
|
||||||
Provider = provider;
|
Provider = provider;
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
using AsyncEvent;
|
using AsyncEvent;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Providers;
|
using FileTime.Core.Providers;
|
||||||
using SMBLibrary;
|
|
||||||
using SMBLibrary.Client;
|
|
||||||
|
|
||||||
namespace FileTime.Providers.Smb
|
namespace FileTime.Providers.Smb
|
||||||
{
|
{
|
||||||
@@ -17,6 +15,7 @@ namespace FileTime.Providers.Smb
|
|||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
public string? FullName { get; }
|
public string? FullName { get; }
|
||||||
|
public string? NativePath { get; }
|
||||||
|
|
||||||
public bool IsHidden => false;
|
public bool IsHidden => false;
|
||||||
public bool IsLoaded => _items != null;
|
public bool IsLoaded => _items != null;
|
||||||
@@ -40,6 +39,7 @@ namespace FileTime.Providers.Smb
|
|||||||
|
|
||||||
Name = name;
|
Name = name;
|
||||||
FullName = parent?.FullName == null ? Name : parent.FullName + Constants.SeparatorChar + Name;
|
FullName = parent?.FullName == null ? Name : parent.FullName + Constants.SeparatorChar + Name;
|
||||||
|
NativePath = SmbContentProvider.GetNativePath(FullName);
|
||||||
Provider = contentProvider;
|
Provider = contentProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ namespace FileTime.Providers.Smb
|
|||||||
public string? Password { get; private set; }
|
public string? Password { get; private set; }
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
public string? FullName { get; }
|
public string? FullName { get; }
|
||||||
|
public string? NativePath { get; }
|
||||||
|
|
||||||
public bool IsHidden => false;
|
public bool IsHidden => false;
|
||||||
public bool IsLoaded => _items != null;
|
public bool IsLoaded => _items != null;
|
||||||
@@ -51,7 +51,7 @@ namespace FileTime.Providers.Smb
|
|||||||
Password = password;
|
Password = password;
|
||||||
|
|
||||||
Provider = contentProvider;
|
Provider = contentProvider;
|
||||||
FullName = Name = path;
|
NativePath = FullName = Name = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default)
|
public async Task<IReadOnlyList<IItem>?> GetItems(CancellationToken token = default)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace FileTime.Providers.Smb
|
|||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
public string? FullName { get; }
|
public string? FullName { get; }
|
||||||
|
public string? NativePath { get; }
|
||||||
|
|
||||||
public bool IsHidden => false;
|
public bool IsHidden => false;
|
||||||
public bool IsLoaded => _items != null;
|
public bool IsLoaded => _items != null;
|
||||||
@@ -40,6 +41,7 @@ namespace FileTime.Providers.Smb
|
|||||||
|
|
||||||
Name = name;
|
Name = name;
|
||||||
FullName = parent?.FullName == null ? Name : parent.FullName + Constants.SeparatorChar + Name;
|
FullName = parent?.FullName == null ? Name : parent.FullName + Constants.SeparatorChar + Name;
|
||||||
|
NativePath = SmbContentProvider.GetNativePath(FullName);
|
||||||
Provider = contentProvider;
|
Provider = contentProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user