diff --git a/Wino.Core.Domain/Entities/Shared/KeyboardShortcut.cs b/Wino.Core.Domain/Entities/Shared/KeyboardShortcut.cs
new file mode 100644
index 00000000..d89c4952
--- /dev/null
+++ b/Wino.Core.Domain/Entities/Shared/KeyboardShortcut.cs
@@ -0,0 +1,60 @@
+using System;
+using SQLite;
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Entities.Shared;
+
+///
+/// Represents a user-defined keyboard shortcut for mail operations.
+///
+public class KeyboardShortcut
+{
+ [PrimaryKey]
+ public Guid Id { get; set; }
+
+ ///
+ /// The key combination string (e.g., "D", "Delete", "F1").
+ ///
+ public string Key { get; set; }
+
+ ///
+ /// The modifier keys for this shortcut.
+ ///
+ public ModifierKeys ModifierKeys { get; set; }
+
+ ///
+ /// The mail operation this shortcut triggers.
+ ///
+ public MailOperation MailOperation { get; set; }
+
+ ///
+ /// Whether this shortcut is enabled.
+ ///
+ public bool IsEnabled { get; set; } = true;
+
+ ///
+ /// When this shortcut was created.
+ ///
+ public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
+
+ ///
+ /// User-friendly display name for the shortcut.
+ ///
+ public string DisplayName
+ {
+ get
+ {
+ var modifierText = string.Empty;
+ if (ModifierKeys.HasFlag(ModifierKeys.Control))
+ modifierText += "Ctrl+";
+ if (ModifierKeys.HasFlag(ModifierKeys.Alt))
+ modifierText += "Alt+";
+ if (ModifierKeys.HasFlag(ModifierKeys.Shift))
+ modifierText += "Shift+";
+ if (ModifierKeys.HasFlag(ModifierKeys.Windows))
+ modifierText += "Win+";
+
+ return modifierText + Key;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Wino.Core.Domain/Enums/ModifierKeys.cs b/Wino.Core.Domain/Enums/ModifierKeys.cs
new file mode 100644
index 00000000..f5d7147d
--- /dev/null
+++ b/Wino.Core.Domain/Enums/ModifierKeys.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Wino.Core.Domain.Enums;
+
+///
+/// Defines keyboard modifier keys that can be used in keyboard shortcuts.
+///
+[Flags]
+public enum ModifierKeys
+{
+ None = 0,
+ Control = 1,
+ Alt = 2,
+ Shift = 4,
+ Windows = 8
+}
\ No newline at end of file
diff --git a/Wino.Core.Domain/Enums/WinoPage.cs b/Wino.Core.Domain/Enums/WinoPage.cs
index 9bf5347a..8df1526d 100644
--- a/Wino.Core.Domain/Enums/WinoPage.cs
+++ b/Wino.Core.Domain/Enums/WinoPage.cs
@@ -26,6 +26,7 @@ public enum WinoPage
SettingOptionsPage,
AliasManagementPage,
EditAccountDetailsPage,
+ KeyboardShortcutsPage,
// Calendar
CalendarPage,
CalendarSettingsPage,
diff --git a/Wino.Core.Domain/Interfaces/IKeyboardShortcutService.cs b/Wino.Core.Domain/Interfaces/IKeyboardShortcutService.cs
new file mode 100644
index 00000000..1e7098ec
--- /dev/null
+++ b/Wino.Core.Domain/Interfaces/IKeyboardShortcutService.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using Wino.Core.Domain.Entities.Shared;
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Interfaces;
+
+///
+/// Service for managing keyboard shortcuts for mail operations.
+///
+public interface IKeyboardShortcutService
+{
+ ///
+ /// Gets all available keyboard shortcuts.
+ ///
+ /// Collection of keyboard shortcuts.
+ Task> GetKeyboardShortcutsAsync();
+
+ ///
+ /// Gets enabled keyboard shortcuts only.
+ ///
+ /// Collection of enabled keyboard shortcuts.
+ Task> GetEnabledKeyboardShortcutsAsync();
+
+ ///
+ /// Creates or updates a keyboard shortcut.
+ ///
+ /// The keyboard shortcut to save.
+ /// The saved keyboard shortcut.
+ Task SaveKeyboardShortcutAsync(KeyboardShortcut shortcut);
+
+ ///
+ /// Deletes a keyboard shortcut.
+ ///
+ /// The ID of the shortcut to delete.
+ Task DeleteKeyboardShortcutAsync(Guid shortcutId);
+
+ ///
+ /// Gets the mail operation for the given key combination.
+ ///
+ /// The pressed key.
+ /// The modifier keys pressed.
+ /// The mail operation if found, otherwise null.
+ Task GetMailOperationForKeyAsync(string key, ModifierKeys modifierKeys);
+
+ ///
+ /// Checks if a key combination is already assigned to another shortcut.
+ ///
+ /// The key to check.
+ /// The modifier keys to check.
+ /// Optional ID to exclude from the check (for updates).
+ /// True if the combination is already used, false otherwise.
+ Task IsKeyCombinationInUseAsync(string key, ModifierKeys modifierKeys, Guid? excludeShortcutId = null);
+
+ ///
+ /// Creates default keyboard shortcuts for common mail operations.
+ ///
+ Task CreateDefaultShortcutsAsync();
+
+ ///
+ /// Resets all shortcuts to defaults.
+ ///
+ Task ResetToDefaultShortcutsAsync();
+}
\ No newline at end of file
diff --git a/Wino.Core.Domain/Interfaces/IMailDialogService.cs b/Wino.Core.Domain/Interfaces/IMailDialogService.cs
index 53050931..988c75d5 100644
--- a/Wino.Core.Domain/Interfaces/IMailDialogService.cs
+++ b/Wino.Core.Domain/Interfaces/IMailDialogService.cs
@@ -5,6 +5,7 @@ using System.Threading.Tasks;
using Wino.Core.Domain.Entities.Mail;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models;
using Wino.Core.Domain.Models.Folders;
namespace Wino.Core.Domain.Interfaces;
@@ -49,4 +50,13 @@ public interface IMailDialogService : IDialogServiceBase
/// Presents a dialog to the user to show email source.
///
Task ShowMessageSourceDialogAsync(string messageSource);
+
+ ///
+ /// Presents a dialog to the user for keyboard shortcut creation/modification.
+ ///
+ /// Existing shortcut to edit, or null for new shortcut.
+ /// Dialog result with shortcut information.
+#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
+ Task ShowKeyboardShortcutDialogAsync(KeyboardShortcut existingShortcut = null);
+#pragma warning restore CS8625
}
diff --git a/Wino.Core.Domain/Models/KeyboardShortcutDialogResult.cs b/Wino.Core.Domain/Models/KeyboardShortcutDialogResult.cs
new file mode 100644
index 00000000..4c4cab97
--- /dev/null
+++ b/Wino.Core.Domain/Models/KeyboardShortcutDialogResult.cs
@@ -0,0 +1,54 @@
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.Domain.Models;
+
+///
+/// Result returned from keyboard shortcut dialog.
+///
+public class KeyboardShortcutDialogResult
+{
+ ///
+ /// Whether the dialog was completed successfully.
+ ///
+ public bool IsSuccess { get; set; }
+
+ ///
+ /// The key combination entered by the user.
+ ///
+ public string Key { get; set; } = string.Empty;
+
+ ///
+ /// The modifier keys selected by the user.
+ ///
+ public ModifierKeys ModifierKeys { get; set; }
+
+ ///
+ /// The mail operation selected by the user.
+ ///
+ public MailOperation MailOperation { get; set; }
+
+ ///
+ /// Creates a successful result.
+ ///
+ public static KeyboardShortcutDialogResult Success(string key, ModifierKeys modifierKeys, MailOperation mailOperation)
+ {
+ return new KeyboardShortcutDialogResult
+ {
+ IsSuccess = true,
+ Key = key,
+ ModifierKeys = modifierKeys,
+ MailOperation = mailOperation
+ };
+ }
+
+ ///
+ /// Creates a canceled result.
+ ///
+ public static KeyboardShortcutDialogResult Canceled()
+ {
+ return new KeyboardShortcutDialogResult
+ {
+ IsSuccess = false
+ };
+ }
+}
\ No newline at end of file
diff --git a/Wino.Core.Domain/Translations/en_US/resources.json b/Wino.Core.Domain/Translations/en_US/resources.json
index b6464abb..07ea2308 100644
--- a/Wino.Core.Domain/Translations/en_US/resources.json
+++ b/Wino.Core.Domain/Translations/en_US/resources.json
@@ -229,6 +229,22 @@
"HoverActionOption_MoveJunk": "Move to Junk",
"HoverActionOption_ToggleFlag": "Flag / Unflag",
"HoverActionOption_ToggleRead": "Read / Unread",
+ "KeyboardShortcuts_FailedToReset": "Failed to reset keyboard shortcuts.",
+ "KeyboardShortcuts_FailedToUpdate": "Failed to update keyboard shortcuts",
+ "KeyboardShortcuts_MailoperationAction": "Action",
+ "KeyboardShortcuts_FailedToLoad": "Failed to load keyboard shortcuts.",
+ "KeyboardShortcuts_EnterKeyForShortcut": "Please enter a key for the shortcut.",
+ "KeyboardShortcuts_SelectOperationForShortcut": "Please an action to perform for the shortcut.",
+ "KeyboardShortcuts_ShortcutInUse": "This shortcut is already in use by another s hortcut.",
+ "KeyboardShortcuts_FailedToSave": "Failed to save the shortcut.",
+ "KeyboardShortcuts_FailedToDelete": "Failed to delete the shortcut.",
+ "KeyboardShortcuts_PageDescription": "Set up keyboard shortcuts for quick mail operations. Press keys while focused on the key input field to capture shortcuts.",
+ "KeyboardShortcuts_Add": "Add shortcut",
+ "KeyboardShortcuts_ResetToDefaults": "Reset to Defaults",
+ "KeyboardShortcuts_PressKeysHere": "Press keys here...",
+ "KeyboardShortcuts_KeyCombination": "Key Combination",
+ "KeyboardShortcuts_FocusArea": "Focus the field above and press the desired key combination",
+ "KeyboardShortcuts_Modifiers": "Modifier Keys",
"ImageRenderingDisabled": "Image rendering is disabled for this message.",
"ImapAdvancedSetupDialog_AuthenticationMethod": "Authentication method",
"ImapAdvancedSetupDialog_ConnectionSecurity": "Connection security",
@@ -465,6 +481,8 @@
"SearchBarPlaceholder": "Search",
"SearchingIn": "Searching in",
"SearchPivotName": "Results",
+ "Settings_KeyboardShortcuts_Title": "Keyboard Shortcuts",
+ "Settings_KeyboardShortcuts_Description": "Manage keyboard shortcuts for quick actions on the mails.",
"SettingConfigureSpecialFolders_Button": "Configure",
"SettingsEditAccountDetails_IMAPConfiguration_Title": "IMAP/SMTP Configuration",
"SettingsEditAccountDetails_IMAPConfiguration_Description": "Change your incoming/outgoing server settings.",
diff --git a/Wino.Core.ViewModels/Data/KeyboardShortcutViewModel.cs b/Wino.Core.ViewModels/Data/KeyboardShortcutViewModel.cs
new file mode 100644
index 00000000..8c7b6e09
--- /dev/null
+++ b/Wino.Core.ViewModels/Data/KeyboardShortcutViewModel.cs
@@ -0,0 +1,86 @@
+using System;
+using CommunityToolkit.Mvvm.ComponentModel;
+using Wino.Core.Domain;
+using Wino.Core.Domain.Entities.Shared;
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.ViewModels.Data;
+
+///
+/// ViewModel wrapper for KeyboardShortcut entity.
+///
+public partial class KeyboardShortcutViewModel : ObservableObject
+{
+ [ObservableProperty]
+ private bool isEnabled;
+
+ public Guid Id { get; }
+ public string Key { get; }
+ public ModifierKeys ModifierKeys { get; }
+ public MailOperation MailOperation { get; }
+ public DateTime CreatedAt { get; }
+
+ public string DisplayName
+ {
+ get
+ {
+ var modifierText = string.Empty;
+ if (ModifierKeys.HasFlag(ModifierKeys.Control))
+ modifierText += "Ctrl+";
+ if (ModifierKeys.HasFlag(ModifierKeys.Alt))
+ modifierText += "Alt+";
+ if (ModifierKeys.HasFlag(ModifierKeys.Shift))
+ modifierText += "Shift+";
+ if (ModifierKeys.HasFlag(ModifierKeys.Windows))
+ modifierText += "Win+";
+
+ return modifierText + Key;
+ }
+ }
+
+ public string MailOperationDisplayName
+ {
+ get
+ {
+ return MailOperation switch
+ {
+ MailOperation.Archive => "Archive",
+ MailOperation.UnArchive => "Unarchive",
+ MailOperation.SoftDelete => "Delete",
+ MailOperation.Move => "Move",
+ MailOperation.MoveToJunk => "Move to Junk",
+ MailOperation.SetFlag => "Set Flag",
+ MailOperation.ClearFlag => "Clear Flag",
+ MailOperation.MarkAsRead => "Mark as Read",
+ MailOperation.MarkAsUnread => "Mark as Unread",
+ MailOperation.Reply => "Reply",
+ MailOperation.ReplyAll => "Reply All",
+ MailOperation.Forward => "Forward",
+ _ => MailOperation.ToString()
+ };
+ }
+ }
+
+ public KeyboardShortcutViewModel(KeyboardShortcut shortcut)
+ {
+ Id = shortcut.Id;
+ Key = shortcut.Key;
+ ModifierKeys = shortcut.ModifierKeys;
+ MailOperation = shortcut.MailOperation;
+ CreatedAt = shortcut.CreatedAt;
+ IsEnabled = shortcut.IsEnabled;
+ }
+
+ public KeyboardShortcut ToEntity()
+ {
+ return new KeyboardShortcut
+ {
+ Id = Id,
+ Key = Key,
+ ModifierKeys = ModifierKeys,
+ MailOperation = MailOperation,
+ CreatedAt = CreatedAt,
+ IsEnabled = IsEnabled
+ };
+ }
+}
diff --git a/Wino.Core.ViewModels/Data/MailOperationViewModel.cs b/Wino.Core.ViewModels/Data/MailOperationViewModel.cs
new file mode 100644
index 00000000..5b8067bd
--- /dev/null
+++ b/Wino.Core.ViewModels/Data/MailOperationViewModel.cs
@@ -0,0 +1,42 @@
+using Wino.Core.Domain;
+using Wino.Core.Domain.Enums;
+
+namespace Wino.Core.ViewModels.Data;
+
+///
+/// ViewModel for displaying mail operations in dropdowns/lists.
+///
+public class MailOperationViewModel
+{
+ public MailOperation Operation { get; }
+
+ public string DisplayName
+ {
+ get
+ {
+ return Operation switch
+ {
+ MailOperation.Archive => "Archive",
+ MailOperation.UnArchive => "Unarchive",
+ MailOperation.SoftDelete => "Delete",
+ MailOperation.Move => "Move",
+ MailOperation.MoveToJunk => "Move to Junk",
+ MailOperation.SetFlag => "Set Flag",
+ MailOperation.ClearFlag => "Clear Flag",
+ MailOperation.MarkAsRead => "Mark as Read",
+ MailOperation.MarkAsUnread => "Mark as Unread",
+ MailOperation.Reply => "Reply",
+ MailOperation.ReplyAll => "Reply All",
+ MailOperation.Forward => "Forward",
+ _ => Operation.ToString()
+ };
+ }
+ }
+
+ public MailOperationViewModel(MailOperation operation)
+ {
+ Operation = operation;
+ }
+
+ public override string ToString() => DisplayName;
+}
diff --git a/Wino.Core.ViewModels/KeyboardShortcutsPageViewModel.cs b/Wino.Core.ViewModels/KeyboardShortcutsPageViewModel.cs
new file mode 100644
index 00000000..0a2b5757
--- /dev/null
+++ b/Wino.Core.ViewModels/KeyboardShortcutsPageViewModel.cs
@@ -0,0 +1,179 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using Wino.Core.Domain;
+using Wino.Core.Domain.Entities.Shared;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Interfaces;
+using Wino.Core.Domain.Models.Navigation;
+using Wino.Core.ViewModels.Data;
+
+namespace Wino.Core.ViewModels;
+
+///
+/// ViewModel for managing keyboard shortcuts settings.
+///
+public partial class KeyboardShortcutsPageViewModel : CoreBaseViewModel
+{
+ private readonly IKeyboardShortcutService _keyboardShortcutService;
+ private readonly IMailDialogService _dialogService;
+
+ [ObservableProperty]
+ public partial ObservableCollection Shortcuts { get; set; } = new();
+
+ public KeyboardShortcutsPageViewModel(IKeyboardShortcutService keyboardShortcutService,
+ IMailDialogService dialogService)
+ {
+ _keyboardShortcutService = keyboardShortcutService;
+ _dialogService = dialogService;
+ }
+
+ public override async void OnNavigatedTo(NavigationMode mode, object parameters)
+ {
+ base.OnNavigatedTo(mode, parameters);
+ await LoadShortcutsAsync();
+ }
+
+ [RelayCommand]
+ private async Task LoadShortcutsAsync()
+ {
+ try
+ {
+ var keyboardShortcuts = await _keyboardShortcutService.GetKeyboardShortcutsAsync();
+
+ Shortcuts.Clear();
+ foreach (var shortcut in keyboardShortcuts)
+ {
+ Shortcuts.Add(new KeyboardShortcutViewModel(shortcut));
+ }
+ }
+ catch (Exception ex)
+ {
+ await _dialogService.ShowMessageAsync(
+ Translator.KeyboardShortcuts_FailedToLoad,
+ Translator.GeneralTitle_Error,
+ WinoCustomMessageDialogIcon.Error);
+ }
+ }
+
+ [RelayCommand]
+ private async Task StartAddingShortcutAsync()
+ {
+ var result = await _dialogService.ShowKeyboardShortcutDialogAsync();
+ if (result.IsSuccess)
+ {
+ try
+ {
+ // Check if key combination is already in use
+ var isInUse = await _keyboardShortcutService.IsKeyCombinationInUseAsync(result.Key, result.ModifierKeys, null);
+ if (isInUse)
+ {
+ await _dialogService.ShowMessageAsync(Translator.KeyboardShortcuts_ShortcutInUse, Translator.GeneralTitle_Error, WinoCustomMessageDialogIcon.Error);
+ return;
+ }
+
+ // Create new shortcut
+ var shortcut = new KeyboardShortcut
+ {
+ Key = result.Key,
+ ModifierKeys = result.ModifierKeys,
+ MailOperation = result.MailOperation,
+ IsEnabled = true
+ };
+
+ await _keyboardShortcutService.SaveKeyboardShortcutAsync(shortcut);
+ await LoadShortcutsAsync();
+ }
+ catch (Exception ex)
+ {
+ await _dialogService.ShowMessageAsync(
+ Translator.KeyboardShortcuts_FailedToSave,
+ Translator.GeneralTitle_Error,
+ WinoCustomMessageDialogIcon.Error);
+ }
+ }
+ }
+
+ [RelayCommand]
+ private async Task StartEditingShortcutAsync(KeyboardShortcutViewModel shortcut)
+ {
+ if (shortcut == null) return;
+
+ var dialogService = _dialogService as IMailDialogService;
+ if (dialogService == null) return;
+
+ var existingShortcut = shortcut.ToEntity();
+ var result = await dialogService.ShowKeyboardShortcutDialogAsync(existingShortcut);
+
+ if (result.IsSuccess)
+ {
+ try
+ {
+ // Check if key combination is already in use (excluding current shortcut)
+ var isInUse = await _keyboardShortcutService.IsKeyCombinationInUseAsync(result.Key, result.ModifierKeys, shortcut.Id);
+ if (isInUse)
+ {
+ await _dialogService.ShowMessageAsync(Translator.KeyboardShortcuts_ShortcutInUse, Translator.GeneralTitle_Error, WinoCustomMessageDialogIcon.Error);
+ return;
+ }
+
+ // Update existing shortcut
+ var updatedShortcut = shortcut.ToEntity();
+ updatedShortcut.Key = result.Key;
+ updatedShortcut.ModifierKeys = result.ModifierKeys;
+ updatedShortcut.MailOperation = result.MailOperation;
+
+ await _keyboardShortcutService.SaveKeyboardShortcutAsync(updatedShortcut);
+ await LoadShortcutsAsync();
+ }
+ catch (Exception ex)
+ {
+ await _dialogService.ShowMessageAsync(
+ Translator.KeyboardShortcuts_FailedToUpdate,
+ Translator.GeneralTitle_Error,
+ WinoCustomMessageDialogIcon.Error);
+ }
+ }
+ }
+
+
+
+ [RelayCommand]
+ private async Task DeleteShortcutAsync(KeyboardShortcutViewModel shortcut)
+ {
+ if (shortcut == null) return;
+
+ try
+ {
+ await _keyboardShortcutService.DeleteKeyboardShortcutAsync(shortcut.Id);
+ await LoadShortcutsAsync();
+ }
+ catch (Exception ex)
+ {
+ await _dialogService.ShowMessageAsync(
+ Translator.KeyboardShortcuts_FailedToDelete,
+ Translator.GeneralTitle_Error,
+ WinoCustomMessageDialogIcon.Error);
+ }
+ }
+
+ [RelayCommand]
+ private async Task ResetToDefaultsAsync()
+ {
+ try
+ {
+ await _keyboardShortcutService.ResetToDefaultShortcutsAsync();
+ await LoadShortcutsAsync();
+ }
+ catch (Exception ex)
+ {
+ await _dialogService.ShowMessageAsync(
+ Translator.KeyboardShortcuts_FailedToReset,
+ Translator.GeneralTitle_Error,
+ WinoCustomMessageDialogIcon.Error);
+ }
+ }
+
+}
diff --git a/Wino.Core.ViewModels/SettingOptionsPageViewModel.cs b/Wino.Core.ViewModels/SettingOptionsPageViewModel.cs
index 09411a1e..8745056f 100644
--- a/Wino.Core.ViewModels/SettingOptionsPageViewModel.cs
+++ b/Wino.Core.ViewModels/SettingOptionsPageViewModel.cs
@@ -38,6 +38,7 @@ public partial class SettingOptionsPageViewModel : CoreBaseViewModel
WinoPage.LanguageTimePage => Translator.SettingsLanguageTime_Title,
WinoPage.AppPreferencesPage => Translator.SettingsAppPreferences_Title,
WinoPage.CalendarSettingsPage => Translator.SettingsCalendarSettings_Title,
+ WinoPage.KeyboardShortcutsPage => "Keyboard Shortcuts",
_ => throw new NotImplementedException()
};
diff --git a/Wino.Core.WinUI/CoreUWPContainerSetup.cs b/Wino.Core.WinUI/CoreUWPContainerSetup.cs
index 02f4aeac..4e02fbeb 100644
--- a/Wino.Core.WinUI/CoreUWPContainerSetup.cs
+++ b/Wino.Core.WinUI/CoreUWPContainerSetup.cs
@@ -40,5 +40,6 @@ public static class CoreUWPContainerSetup
services.AddTransient(typeof(AboutPageViewModel));
services.AddTransient(typeof(SettingsPageViewModel));
services.AddTransient(typeof(ManageAccountsPagePageViewModel));
+ services.AddTransient(typeof(KeyboardShortcutsPageViewModel));
}
}
diff --git a/Wino.Mail.WinUI/Dialogs/KeyboardShortcutDialog.xaml b/Wino.Mail.WinUI/Dialogs/KeyboardShortcutDialog.xaml
new file mode 100644
index 00000000..fefb648f
--- /dev/null
+++ b/Wino.Mail.WinUI/Dialogs/KeyboardShortcutDialog.xaml
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Wino.Mail.WinUI/Dialogs/KeyboardShortcutDialog.xaml.cs b/Wino.Mail.WinUI/Dialogs/KeyboardShortcutDialog.xaml.cs
new file mode 100644
index 00000000..1773ea92
--- /dev/null
+++ b/Wino.Mail.WinUI/Dialogs/KeyboardShortcutDialog.xaml.cs
@@ -0,0 +1,145 @@
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Input;
+using Wino.Core.Domain.Entities.Shared;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Models;
+using Wino.Core.ViewModels.Data;
+
+namespace Wino.Dialogs;
+
+public sealed partial class KeyboardShortcutDialog : ContentDialog
+{
+ public KeyboardShortcutDialogResult Result { get; private set; } = KeyboardShortcutDialogResult.Canceled();
+
+ public List AvailableMailOperations { get; }
+
+ public MailOperationViewModel SelectedMailOperation { get; set; }
+ public bool IsControlPressed { get; set; }
+ public bool IsAltPressed { get; set; }
+ public bool IsShiftPressed { get; set; }
+ public bool IsWindowsPressed { get; set; }
+
+ public KeyboardShortcutDialog()
+ {
+ InitializeComponent();
+ AvailableMailOperations = GetAvailableMailOperations();
+ SelectedMailOperation = AvailableMailOperations.FirstOrDefault();
+ }
+
+ public KeyboardShortcutDialog(KeyboardShortcut existingShortcut) : this()
+ {
+ if (existingShortcut != null)
+ {
+ KeyInputTextBox.Text = existingShortcut.Key;
+ SelectedMailOperation = AvailableMailOperations.FirstOrDefault(x => x.Operation == existingShortcut.MailOperation);
+
+ var modifiers = existingShortcut.ModifierKeys;
+ IsControlPressed = modifiers.HasFlag(ModifierKeys.Control);
+ IsAltPressed = modifiers.HasFlag(ModifierKeys.Alt);
+ IsShiftPressed = modifiers.HasFlag(ModifierKeys.Shift);
+ IsWindowsPressed = modifiers.HasFlag(ModifierKeys.Windows);
+
+ Title = "Edit Keyboard Shortcut";
+ }
+ }
+
+ private void SaveClicked(ContentDialog sender, ContentDialogButtonClickEventArgs args)
+ {
+ // Clear any previous error
+ ErrorTextBlock.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed;
+
+ // Validate input
+ if (string.IsNullOrWhiteSpace(KeyInputTextBox.Text))
+ {
+ ShowError("Please enter a key for the shortcut.");
+ args.Cancel = true;
+ return;
+ }
+
+ if (SelectedMailOperation == null || SelectedMailOperation.Operation == MailOperation.None)
+ {
+ ShowError("Please select a mail operation for the shortcut.");
+ args.Cancel = true;
+ return;
+ }
+
+ // Get modifier keys
+ var modifierKeys = GetSelectedModifierKeys();
+
+ // Create successful result
+ Result = KeyboardShortcutDialogResult.Success(KeyInputTextBox.Text, modifierKeys, SelectedMailOperation.Operation);
+ }
+
+ private void KeyInputTextBox_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
+ {
+ // Clear error when user starts typing
+ ErrorTextBlock.Visibility = Microsoft.UI.Xaml.Visibility.Collapsed;
+
+ var key = e.Key.ToString();
+
+ // Update modifier states based on current key press
+ IsControlPressed = Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Control).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down);
+ IsAltPressed = Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Menu).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down);
+ IsShiftPressed = Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.Shift).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down);
+ IsWindowsPressed = Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.LeftWindows).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down) ||
+ Microsoft.UI.Input.InputKeyboardSource.GetKeyStateForCurrentThread(Windows.System.VirtualKey.RightWindows).HasFlag(Windows.UI.Core.CoreVirtualKeyStates.Down);
+
+ // Set the key (ignore modifier keys themselves)
+ if (key != "Control" && key != "Menu" && key != "Shift" && key != "LeftWindows" && key != "RightWindows")
+ {
+ KeyInputTextBox.Text = key;
+ }
+
+ // Prevent the key from being processed further
+ // e.Handled = true;
+ }
+
+ private ModifierKeys GetSelectedModifierKeys()
+ {
+ var modifiers = ModifierKeys.None;
+
+ if (IsControlPressed) modifiers |= ModifierKeys.Control;
+ if (IsAltPressed) modifiers |= ModifierKeys.Alt;
+ if (IsShiftPressed) modifiers |= ModifierKeys.Shift;
+ if (IsWindowsPressed) modifiers |= ModifierKeys.Windows;
+
+ return modifiers;
+ }
+
+ private void ShowError(string message)
+ {
+ ErrorTextBlock.Text = message;
+ ErrorTextBlock.Visibility = Microsoft.UI.Xaml.Visibility.Visible;
+ }
+
+ private static List GetAvailableMailOperations()
+ {
+ var operations = new List();
+
+ // Add commonly used mail operations that make sense for keyboard shortcuts
+ var validOperations = new[]
+ {
+ MailOperation.Archive,
+ MailOperation.UnArchive,
+ MailOperation.SoftDelete,
+ MailOperation.Move,
+ MailOperation.MoveToJunk,
+ MailOperation.SetFlag,
+ MailOperation.ClearFlag,
+ MailOperation.MarkAsRead,
+ MailOperation.MarkAsUnread,
+ MailOperation.Reply,
+ MailOperation.ReplyAll,
+ MailOperation.Forward
+ };
+
+ foreach (var operation in validOperations)
+ {
+ operations.Add(new MailOperationViewModel(operation));
+ }
+
+ return operations.OrderBy(x => x.DisplayName).ToList();
+ }
+}
diff --git a/Wino.Mail.WinUI/Package.appxmanifest b/Wino.Mail.WinUI/Package.appxmanifest
index 6df5b884..9c49b925 100644
--- a/Wino.Mail.WinUI/Package.appxmanifest
+++ b/Wino.Mail.WinUI/Package.appxmanifest
@@ -20,7 +20,7 @@
+ Version="0.0.4.0" />
diff --git a/Wino.Mail.WinUI/Services/DialogService.cs b/Wino.Mail.WinUI/Services/DialogService.cs
index fb4d43d8..63a22ad9 100644
--- a/Wino.Mail.WinUI/Services/DialogService.cs
+++ b/Wino.Mail.WinUI/Services/DialogService.cs
@@ -10,6 +10,7 @@ using Wino.Core.Domain.Entities.Mail;
using Wino.Core.Domain.Entities.Shared;
using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
+using Wino.Core.Domain.Models;
using Wino.Core.Domain.Models.Accounts;
using Wino.Core.Domain.Models.Folders;
using Wino.Core.Domain.Models.Synchronization;
@@ -194,4 +195,18 @@ public class DialogService : DialogServiceBase, IMailDialogService
await HandleDialogPresentationAsync(accountReorderDialog);
}
+
+#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
+ public async Task ShowKeyboardShortcutDialogAsync(KeyboardShortcut existingShortcut = null)
+#pragma warning restore CS8625
+ {
+ var dialog = new KeyboardShortcutDialog(existingShortcut)
+ {
+ RequestedTheme = ThemeService.RootTheme.ToWindowsElementTheme()
+ };
+
+ await HandleDialogPresentationAsync(dialog);
+
+ return dialog.Result;
+ }
}
diff --git a/Wino.Mail.WinUI/Services/NavigationService.cs b/Wino.Mail.WinUI/Services/NavigationService.cs
index 90498938..18e839d2 100644
--- a/Wino.Mail.WinUI/Services/NavigationService.cs
+++ b/Wino.Mail.WinUI/Services/NavigationService.cs
@@ -7,8 +7,8 @@ using Wino.Core.Domain.Enums;
using Wino.Core.Domain.Interfaces;
using Wino.Core.Domain.Models.Navigation;
using Wino.Core.WinUI;
-using Wino.Core.WinUI.Services;
using Wino.Core.WinUI.Interfaces;
+using Wino.Core.WinUI.Services;
using Wino.Helpers;
using Wino.Mail.ViewModels.Data;
using Wino.Mail.ViewModels.Messages;
@@ -59,6 +59,7 @@ public class NavigationService : NavigationServiceBase, INavigationService
WinoPage.AliasManagementPage => typeof(AliasManagementPage),
WinoPage.LanguageTimePage => typeof(LanguageTimePage),
WinoPage.EditAccountDetailsPage => typeof(EditAccountDetailsPage),
+ WinoPage.KeyboardShortcutsPage => typeof(KeyboardShortcutsPage),
_ => null,
};
}
diff --git a/Wino.Mail.WinUI/Services/SettingsBuilderService.cs b/Wino.Mail.WinUI/Services/SettingsBuilderService.cs
index 8c2718b5..a289e2a6 100644
--- a/Wino.Mail.WinUI/Services/SettingsBuilderService.cs
+++ b/Wino.Mail.WinUI/Services/SettingsBuilderService.cs
@@ -15,6 +15,7 @@ public class SettingsBuilderService : ISettingsBuilderService
new SettingOption(Translator.SettingsAppPreferences_Title, Translator.SettingsAppPreferences_Description, WinoPage.AppPreferencesPage,"F1 M 15.078125 1.25 C 15.566406 1.25 16.033527 1.349285 16.479492 1.547852 C 16.925455 1.74642 17.31608 2.013348 17.651367 2.348633 C 17.986652 2.68392 18.25358 3.074545 18.452148 3.520508 C 18.650715 3.966473 18.75 4.433594 18.75 4.921875 L 18.75 15.078125 C 18.75 15.566406 18.650715 16.033529 18.452148 16.479492 C 18.25358 16.925455 17.986652 17.31608 17.651367 17.651367 C 17.31608 17.986654 16.925455 18.25358 16.479492 18.452148 C 16.033527 18.650717 15.566406 18.75 15.078125 18.75 L 4.921875 18.75 C 4.433594 18.75 3.966471 18.650717 3.520508 18.452148 C 3.074544 18.25358 2.683919 17.986654 2.348633 17.651367 C 2.013346 17.31608 1.746419 16.925455 1.547852 16.479492 C 1.349284 16.033529 1.25 15.566406 1.25 15.078125 L 1.25 4.921875 C 1.25 4.433594 1.349284 3.966473 1.547852 3.520508 C 1.746419 3.074545 2.013346 2.68392 2.348633 2.348633 C 2.683919 2.013348 3.074544 1.74642 3.520508 1.547852 C 3.966471 1.349285 4.433594 1.25 4.921875 1.25 Z M 4.951172 2.5 C 4.625651 2.5 4.314778 2.566732 4.018555 2.700195 C 3.722331 2.83366 3.461914 3.012695 3.237305 3.237305 C 3.012695 3.461914 2.833659 3.722332 2.700195 4.018555 C 2.566732 4.314779 2.5 4.625651 2.5 4.951172 L 2.5 5 L 17.5 5 L 17.5 4.951172 C 17.5 4.625651 17.433268 4.314779 17.299805 4.018555 C 17.16634 3.722332 16.987305 3.461914 16.762695 3.237305 C 16.538086 3.012695 16.277668 2.83366 15.981445 2.700195 C 15.685221 2.566732 15.374349 2.5 15.048828 2.5 Z M 15.048828 17.5 C 15.374349 17.5 15.685221 17.433268 15.981445 17.299805 C 16.277668 17.166342 16.538086 16.987305 16.762695 16.762695 C 16.987305 16.538086 17.16634 16.27767 17.299805 15.981445 C 17.433268 15.685222 17.5 15.37435 17.5 15.048828 L 17.5 6.25 L 2.5 6.25 L 2.5 15.048828 C 2.5 15.37435 2.566732 15.685222 2.700195 15.981445 C 2.833659 16.27767 3.012695 16.538086 3.237305 16.762695 C 3.461914 16.987305 3.722331 17.166342 4.018555 17.299805 C 4.314778 17.433268 4.625651 17.5 4.951172 17.5 Z M 12.724609 8.935547 C 12.724609 9.195964 12.762044 9.446615 12.836914 9.6875 C 12.911783 9.928386 13.020832 10.151367 13.164062 10.356445 C 13.307291 10.561523 13.476562 10.742188 13.671875 10.898438 C 13.867188 11.054688 14.088541 11.178386 14.335938 11.269531 C 14.348957 11.367188 14.358723 11.466472 14.365234 11.567383 C 14.371744 11.668295 14.375 11.770834 14.375 11.875 C 14.375 11.979167 14.371744 12.081706 14.365234 12.182617 C 14.358723 12.283529 14.348957 12.382812 14.335938 12.480469 C 14.088541 12.571615 13.867188 12.695312 13.671875 12.851562 C 13.476562 13.007812 13.307291 13.188477 13.164062 13.393555 C 13.020832 13.598633 12.911783 13.821615 12.836914 14.0625 C 12.762044 14.303386 12.724609 14.554037 12.724609 14.814453 C 12.724609 14.886068 12.727864 14.960938 12.734375 15.039062 C 12.740885 15.117188 12.75065 15.192058 12.763672 15.263672 C 12.470703 15.511068 12.145182 15.712891 11.787109 15.869141 C 11.546224 15.621745 11.274414 15.43457 10.97168 15.307617 C 10.668945 15.180664 10.345052 15.117188 10 15.117188 C 9.654947 15.117188 9.331055 15.180664 9.02832 15.307617 C 8.725586 15.43457 8.453775 15.621745 8.212891 15.869141 C 7.854817 15.712891 7.529296 15.511068 7.236328 15.263672 C 7.249349 15.192058 7.259114 15.117188 7.265625 15.039062 C 7.272135 14.960938 7.275391 14.886068 7.275391 14.814453 C 7.275391 14.554037 7.237956 14.303386 7.163086 14.0625 C 7.088216 13.821615 6.979167 13.598633 6.835938 13.393555 C 6.692708 13.188477 6.52181 13.007812 6.323242 12.851562 C 6.124674 12.695312 5.904948 12.571615 5.664062 12.480469 C 5.651042 12.382812 5.641276 12.283529 5.634766 12.182617 C 5.628255 12.081706 5.625 11.979167 5.625 11.875 C 5.625 11.770834 5.628255 11.668295 5.634766 11.567383 C 5.641276 11.466472 5.651042 11.367188 5.664062 11.269531 C 5.904948 11.178386 6.124674 11.054688 6.323242 10.898438 C 6.52181 10.742188 6.692708 10.561523 6.835938 10.356445 C 6.979167 10.151367 7.088216 9.928386 7.163086 9.6875 C 7.237956 9.446615 7.275391 9.195964 7.275391 8.935547 C 7.275391 8.863933 7.272135 8.789062 7.265625 8.710938 C 7.259114 8.632812 7.249349 8.557943 7.236328 8.486328 C 7.529296 8.238933 7.854817 8.037109 8.212891 7.880859 C 8.440755 8.121745 8.712564 8.307292 9.02832 8.4375 C 9.344075 8.567709 9.667969 8.632812 10 8.632812 C 10.332031 8.632812 10.655924 8.567709 10.97168 8.4375 C 11.287435 8.307292 11.559244 8.121745 11.787109 7.880859 C 12.145182 8.037109 12.470703 8.238933 12.763672 8.486328 C 12.75065 8.557943 12.740885 8.632812 12.734375 8.710938 C 12.727864 8.789062 12.724609 8.863933 12.724609 8.935547 Z M 10.9375 11.875 C 10.9375 11.614584 10.846354 11.393229 10.664062 11.210938 C 10.481771 11.028646 10.260416 10.9375 10 10.9375 C 9.739583 10.9375 9.518229 11.028646 9.335938 11.210938 C 9.153646 11.393229 9.0625 11.614584 9.0625 11.875 C 9.0625 12.135417 9.153646 12.356771 9.335938 12.539062 C 9.518229 12.721354 9.739583 12.8125 10 12.8125 C 10.260416 12.8125 10.481771 12.721354 10.664062 12.539062 C 10.846354 12.356771 10.9375 12.135417 10.9375 11.875 Z "),
new SettingOption(Translator.SettingsLanguageTime_Title, Translator.SettingsLanguageTime_Description, WinoPage.LanguageTimePage,"F1 M 4.765625 12.324219 C 4.088542 12.167969 3.458659 11.899414 2.875977 11.518555 C 2.293294 11.137695 1.788737 10.680339 1.362305 10.146484 C 0.935872 9.612631 0.602214 9.020183 0.361328 8.369141 C 0.120443 7.7181 0 7.044271 0 6.347656 C 0 5.468751 0.159505 4.645184 0.478516 3.876953 C 0.797526 3.108725 1.236979 2.436523 1.796875 1.860352 C 2.356771 1.28418 3.017578 0.830078 3.779297 0.498047 C 4.541016 0.166016 5.364583 0 6.25 0 C 7.115885 0 7.92806 0.162762 8.686523 0.488281 C 9.444986 0.813803 10.107422 1.259766 10.673828 1.826172 C 11.240234 2.392578 11.686197 3.055014 12.011719 3.813477 C 12.337239 4.57194 12.5 5.384115 12.5 6.25 L 11.25 6.25 L 11.25 6.152344 C 11.25 5.475261 11.114908 4.838867 10.844727 4.243164 C 10.574544 3.647461 10.209961 3.128256 9.750977 2.685547 C 9.291992 2.24284 8.761393 1.892904 8.15918 1.635742 C 7.556966 1.378582 6.920573 1.25 6.25 1.25 C 5.579427 1.25 4.943034 1.378582 4.34082 1.635742 C 3.738607 1.892904 3.208008 2.24284 2.749023 2.685547 C 2.290039 3.128256 1.925456 3.647461 1.655273 4.243164 C 1.385091 4.838867 1.25 5.475261 1.25 6.152344 L 1.25 6.328125 C 1.25 6.901042 1.352539 7.454428 1.557617 7.988281 C 1.762695 8.522136 2.045898 9.005534 2.407227 9.438477 C 2.768555 9.87142 3.191732 10.239258 3.676758 10.541992 C 4.161784 10.844727 4.6875 11.048178 5.253906 11.152344 Z M 5.625 7.5 C 5.455729 7.5 5.309245 7.438151 5.185547 7.314453 C 5.061849 7.190756 5 7.044271 5 6.875 L 5 3.125 C 5 2.95573 5.061849 2.809246 5.185547 2.685547 C 5.309245 2.56185 5.455729 2.5 5.625 2.5 C 5.794271 2.5 5.940755 2.56185 6.064453 2.685547 C 6.188151 2.809246 6.25 2.95573 6.25 3.125 L 6.25 6.25 L 8.125 6.25 C 8.294271 6.25 8.440755 6.31185 8.564453 6.435547 C 8.68815 6.559245 8.75 6.705729 8.75 6.875 C 8.75 7.044271 8.68815 7.190756 8.564453 7.314453 C 8.440755 7.438151 8.294271 7.5 8.125 7.5 Z M 10 10 L 10 8.125 C 10 7.95573 10.061849 7.809246 10.185547 7.685547 C 10.309244 7.56185 10.455729 7.5 10.625 7.5 L 14.375 7.5 C 14.375 7.447917 14.373372 7.394206 14.370117 7.338867 C 14.366861 7.283529 14.365234 7.226563 14.365234 7.167969 C 14.365234 7.057292 14.371744 6.948242 14.384766 6.84082 C 14.397786 6.733398 14.425455 6.635742 14.467773 6.547852 C 14.51009 6.459961 14.573566 6.388347 14.658203 6.333008 C 14.742838 6.27767 14.856771 6.25 15 6.25 C 15.143229 6.25 15.255533 6.27767 15.336914 6.333008 C 15.418294 6.388347 15.480143 6.459961 15.522461 6.547852 C 15.564777 6.635742 15.592447 6.733398 15.605469 6.84082 C 15.618489 6.948242 15.625 7.057292 15.625 7.167969 L 15.625 7.5 L 19.375 7.5 C 19.54427 7.5 19.690754 7.56185 19.814453 7.685547 C 19.93815 7.809246 20 7.95573 20 8.125 L 20 10 C 20 10.169271 19.93815 10.315756 19.814453 10.439453 C 19.690754 10.563151 19.54427 10.625 19.375 10.625 C 19.205729 10.625 19.059244 10.563151 18.935547 10.439453 C 18.811848 10.315756 18.75 10.169271 18.75 10 L 18.75 8.75 L 11.25 8.75 L 11.25 10 C 11.25 10.169271 11.18815 10.315756 11.064453 10.439453 C 10.940755 10.563151 10.794271 10.625 10.625 10.625 C 10.455729 10.625 10.309244 10.563151 10.185547 10.439453 C 10.061849 10.315756 10 10.169271 10 10 Z M 14.375 17.5 C 14.205729 17.5 14.059244 17.43815 13.935547 17.314453 C 13.811849 17.190756 13.75 17.044271 13.75 16.875 C 13.75 16.731771 13.777669 16.619467 13.833008 16.538086 C 13.888346 16.456705 13.95996 16.394857 14.047852 16.352539 C 14.135741 16.310221 14.233397 16.282553 14.34082 16.269531 C 14.448241 16.256512 14.557291 16.25 14.667969 16.25 L 15 16.25 L 15 13.75 L 11.875 13.75 C 11.705729 13.75 11.559244 13.688151 11.435547 13.564453 C 11.311849 13.440756 11.25 13.294271 11.25 13.125 C 11.25 12.955729 11.311849 12.809245 11.435547 12.685547 C 11.559244 12.56185 11.705729 12.5 11.875 12.5 L 15 12.5 C 14.999999 12.376303 15.035807 12.259115 15.107422 12.148438 L 15.703125 11.25 L 13.125 11.25 C 12.955729 11.25 12.809244 11.188151 12.685547 11.064453 C 12.561849 10.940756 12.5 10.794271 12.5 10.625 C 12.5 10.455729 12.561849 10.309245 12.685547 10.185547 C 12.809244 10.06185 12.955729 10 13.125 10 L 16.875 10 C 17.04427 10 17.190754 10.06185 17.314453 10.185547 C 17.43815 10.309245 17.5 10.455729 17.5 10.625 C 17.5 10.748698 17.464191 10.862631 17.392578 10.966797 L 16.376953 12.5 L 19.375 12.5 C 19.54427 12.5 19.690754 12.56185 19.814453 12.685547 C 19.93815 12.809245 20 12.955729 20 13.125 C 20 13.294271 19.93815 13.440756 19.814453 13.564453 C 19.690754 13.688151 19.54427 13.75 19.375 13.75 L 16.25 13.75 L 16.25 16.25 C 16.25 16.425781 16.217447 16.588543 16.152344 16.738281 C 16.087238 16.888021 15.997721 17.019857 15.883789 17.133789 C 15.769856 17.247721 15.638021 17.33724 15.488281 17.402344 C 15.338541 17.467447 15.17578 17.5 15 17.5 Z M 4.0625 18.125 C 4.0625 18.046875 4.075521 17.972006 4.101562 17.900391 C 4.257812 17.477213 4.41569 17.05892 4.575195 16.645508 C 4.7347 16.232096 4.892578 15.813803 5.048828 15.390625 L 6.914062 10.400391 C 6.959635 10.276693 7.036133 10.185547 7.143555 10.126953 C 7.250977 10.068359 7.369792 10.039062 7.5 10.039062 C 7.630208 10.039062 7.749023 10.068359 7.856445 10.126953 C 7.963867 10.185547 8.040364 10.276693 8.085938 10.400391 L 9.951172 15.390625 C 10.107422 15.813803 10.265299 16.232096 10.424805 16.645508 C 10.58431 17.05892 10.742188 17.477213 10.898438 17.900391 C 10.924479 17.972006 10.9375 18.046875 10.9375 18.125 C 10.9375 18.300781 10.877278 18.448893 10.756836 18.569336 C 10.636393 18.689779 10.488281 18.75 10.3125 18.75 C 10.175781 18.75 10.056966 18.714193 9.956055 18.642578 C 9.855143 18.570963 9.778646 18.470053 9.726562 18.339844 L 8.945312 16.25 L 6.054688 16.25 L 5.273438 18.339844 C 5.227864 18.463541 5.151367 18.562826 5.043945 18.637695 C 4.936523 18.712564 4.817708 18.75 4.6875 18.75 C 4.511719 18.75 4.363606 18.689779 4.243164 18.569336 C 4.122721 18.448893 4.0625 18.300781 4.0625 18.125 Z M 7.5 12.402344 L 6.523438 15 L 8.476562 15 Z "),
new SettingOption(Translator.SettingsPersonalization_Title, Translator.SettingsPersonalization_Description, WinoPage.PersonalizationPage,"F1 M 10 17.5 L 10 18.75 L 12.5 18.75 L 12.5 20 L 6.25 20 L 6.25 18.75 L 8.75 18.75 L 8.75 17.5 L 0 17.5 L 0 6.25 L 10 6.25 L 8.740234 7.5 L 1.25 7.5 L 1.25 16.25 L 17.5 16.25 L 17.5 8.75 L 18.75 7.5 L 18.75 17.5 Z M 5 13.75 C 5.175781 13.75 5.338542 13.717448 5.488281 13.652344 C 5.638021 13.58724 5.769856 13.497722 5.883789 13.383789 C 5.997721 13.269857 6.087239 13.138021 6.152344 12.988281 C 6.217448 12.838542 6.25 12.675781 6.25 12.5 C 6.25 12.18099 6.306966 11.878256 6.420898 11.591797 C 6.53483 11.305339 6.69108 11.051433 6.889648 10.830078 C 7.088216 10.608725 7.322591 10.424805 7.592773 10.27832 C 7.862955 10.131836 8.157552 10.042318 8.476562 10.009766 L 15.419922 3.066406 C 15.602213 2.884115 15.813802 2.744141 16.054688 2.646484 C 16.295572 2.548828 16.542969 2.5 16.796875 2.5 C 17.063801 2.5 17.31608 2.550457 17.553711 2.651367 C 17.79134 2.752279 17.998047 2.890625 18.173828 3.066406 C 18.349609 3.242188 18.487955 3.448895 18.588867 3.686523 C 18.689777 3.924154 18.740234 4.179688 18.740234 4.453125 C 18.740234 4.707031 18.691406 4.954428 18.59375 5.195312 C 18.496094 5.436199 18.356119 5.647787 18.173828 5.830078 L 11.230469 12.773438 C 11.197916 13.085938 11.110025 13.378906 10.966797 13.652344 C 10.823567 13.925781 10.639648 14.161784 10.415039 14.360352 C 10.19043 14.55892 9.936523 14.71517 9.65332 14.829102 C 9.370117 14.943034 9.06901 15 8.75 15 L 2.5 15 L 2.5 13.75 Z M 16.796875 3.75 C 16.608072 3.75 16.445312 3.818359 16.308594 3.955078 L 11.962891 8.300781 C 12.333984 8.58724 12.66276 8.916016 12.949219 9.287109 L 17.294922 4.941406 C 17.431641 4.804688 17.5 4.641928 17.5 4.453125 C 17.5 4.257812 17.430012 4.091797 17.290039 3.955078 C 17.150064 3.818359 16.985676 3.75 16.796875 3.75 Z M 10.175781 10.087891 C 10.572916 10.348308 10.901692 10.677084 11.162109 11.074219 L 12.060547 10.185547 C 11.787109 9.794922 11.455078 9.462891 11.064453 9.189453 Z M 10 12.5 C 10 12.324219 9.967447 12.161459 9.902344 12.011719 C 9.837239 11.861979 9.747721 11.730144 9.633789 11.616211 C 9.519856 11.502279 9.388021 11.412761 9.238281 11.347656 C 9.088541 11.282553 8.925781 11.25 8.75 11.25 C 8.574219 11.25 8.411458 11.282553 8.261719 11.347656 C 8.111979 11.412761 7.980143 11.502279 7.866211 11.616211 C 7.752278 11.730144 7.66276 11.861979 7.597656 12.011719 C 7.532552 12.161459 7.5 12.324219 7.5 12.5 C 7.5 12.942709 7.389322 13.359375 7.167969 13.75 L 8.75 13.75 C 8.919271 13.75 9.080403 13.717448 9.233398 13.652344 C 9.386393 13.58724 9.519856 13.497722 9.633789 13.383789 C 9.747721 13.269857 9.837239 13.136394 9.902344 12.983398 C 9.967447 12.830404 10 12.669271 10 12.5 Z "),
+ new SettingOption(Translator.Settings_KeyboardShortcuts_Title, Translator.Settings_KeyboardShortcuts_Description, WinoPage.KeyboardShortcutsPage,"F1 M 2.451172 16.25 C 2.125651 16.25 1.814779 16.18327 1.518555 16.049805 C 1.222331 15.916342 0.961914 15.737305 0.737305 15.512695 C 0.512695 15.288086 0.333659 15.02767 0.200195 14.731445 C 0.066732 14.435222 0 14.12435 0 13.798828 L 0 4.951172 C 0 4.625651 0.066732 4.314779 0.200195 4.018555 C 0.333659 3.722332 0.512695 3.461914 0.737305 3.237305 C 0.961914 3.012695 1.222331 2.83366 1.518555 2.700195 C 1.814779 2.566732 2.125651 2.5 2.451172 2.5 L 17.548828 2.5 C 17.874348 2.5 18.185221 2.566732 18.481445 2.700195 C 18.777668 2.83366 19.038086 3.012695 19.262695 3.237305 C 19.487305 3.461914 19.66634 3.722332 19.799805 4.018555 C 19.933268 4.314779 20 4.625651 20 4.951172 L 20 13.798828 C 20 14.12435 19.933268 14.435222 19.799805 14.731445 C 19.66634 15.02767 19.487305 15.288086 19.262695 15.512695 C 19.038086 15.737305 18.777668 15.916342 18.481445 16.049805 C 18.185221 16.18327 17.874348 16.25 17.548828 16.25 Z M 17.5 15 C 17.675781 15 17.838541 14.967448 17.988281 14.902344 C 18.13802 14.83724 18.269855 14.747722 18.383789 14.633789 C 18.497721 14.519857 18.587238 14.388021 18.652344 14.238281 C 18.717447 14.088542 18.75 13.925781 18.75 13.75 L 18.75 5 C 18.75 4.830729 18.717447 4.669597 18.652344 4.516602 C 18.587238 4.363607 18.497721 4.230144 18.383789 4.116211 C 18.269855 4.002279 18.136393 3.912762 17.983398 3.847656 C 17.830402 3.782553 17.66927 3.75 17.5 3.75 L 2.5 3.75 C 2.324219 3.75 2.161458 3.782553 2.011719 3.847656 C 1.861979 3.912762 1.730143 4.002279 1.616211 4.116211 C 1.502279 4.230144 1.41276 4.361979 1.347656 4.511719 C 1.282552 4.661459 1.25 4.82422 1.25 5 L 1.25 13.75 C 1.25 13.925781 1.282552 14.09017 1.347656 14.243164 C 1.41276 14.396159 1.500651 14.527995 1.611328 14.638672 C 1.722005 14.74935 1.853841 14.83724 2.006836 14.902344 C 2.159831 14.967448 2.324219 15 2.5 15 Z M 3.125 6.5625 C 3.125 6.302084 3.216146 6.08073 3.398438 5.898438 C 3.580729 5.716146 3.802083 5.625 4.0625 5.625 C 4.322917 5.625 4.544271 5.716146 4.726562 5.898438 C 4.908854 6.08073 5 6.302084 5 6.5625 C 5 6.822917 4.908854 7.044271 4.726562 7.226562 C 4.544271 7.408854 4.322917 7.5 4.0625 7.5 C 3.802083 7.5 3.580729 7.408854 3.398438 7.226562 C 3.216146 7.044271 3.125 6.822917 3.125 6.5625 Z M 6.875 6.5625 C 6.875 6.302084 6.966146 6.08073 7.148438 5.898438 C 7.330729 5.716146 7.552083 5.625 7.8125 5.625 C 8.072916 5.625 8.294271 5.716146 8.476562 5.898438 C 8.658854 6.08073 8.75 6.302084 8.75 6.5625 C 8.75 6.822917 8.658854 7.044271 8.476562 7.226562 C 8.294271 7.408854 8.072916 7.5 7.8125 7.5 C 7.552083 7.5 7.330729 7.408854 7.148438 7.226562 C 6.966146 7.044271 6.875 6.822917 6.875 6.5625 Z M 10.625 6.5625 C 10.625 6.302084 10.716146 6.08073 10.898438 5.898438 C 11.080729 5.716146 11.302083 5.625 11.5625 5.625 C 11.822916 5.625 12.044271 5.716146 12.226562 5.898438 C 12.408854 6.08073 12.5 6.302084 12.5 6.5625 C 12.5 6.822917 12.408854 7.044271 12.226562 7.226562 C 12.044271 7.408854 11.822916 7.5 11.5625 7.5 C 11.302083 7.5 11.080729 7.408854 10.898438 7.226562 C 10.716146 7.044271 10.625 6.822917 10.625 6.5625 Z M 14.375 6.5625 C 14.375 6.302084 14.466146 6.08073 14.648438 5.898438 C 14.830729 5.716146 15.052083 5.625 15.3125 5.625 C 15.572916 5.625 15.79427 5.716146 15.976562 5.898438 C 16.158854 6.08073 16.25 6.302084 16.25 6.5625 C 16.25 6.822917 16.158854 7.044271 15.976562 7.226562 C 15.79427 7.408854 15.572916 7.5 15.3125 7.5 C 15.052083 7.5 14.830729 7.408854 14.648438 7.226562 C 14.466146 7.044271 14.375 6.822917 14.375 6.5625 Z M 5.625 10.3125 C 5.625 10.052084 5.716146 9.830729 5.898438 9.648438 C 6.080729 9.466146 6.302083 9.375 6.5625 9.375 C 6.822917 9.375 7.044271 9.466146 7.226562 9.648438 C 7.408854 9.830729 7.5 10.052084 7.5 10.3125 C 7.5 10.572917 7.408854 10.794271 7.226562 10.976562 C 7.044271 11.158854 6.822917 11.25 6.5625 11.25 C 6.302083 11.25 6.080729 11.158854 5.898438 10.976562 C 5.716146 10.794271 5.625 10.572917 5.625 10.3125 Z M 9.375 10.3125 C 9.375 10.052084 9.466146 9.830729 9.648438 9.648438 C 9.830729 9.466146 10.052083 9.375 10.3125 9.375 C 10.572916 9.375 10.794271 9.466146 10.976562 9.648438 C 11.158854 9.830729 11.25 10.052084 11.25 10.3125 C 11.25 10.572917 11.158854 10.794271 10.976562 10.976562 C 10.794271 11.158854 10.572916 11.25 10.3125 11.25 C 10.052083 11.25 9.830729 11.158854 9.648438 10.976562 C 9.466146 10.794271 9.375 10.572917 9.375 10.3125 Z M 13.125 10.3125 C 13.124999 10.052084 13.216145 9.830729 13.398438 9.648438 C 13.580729 9.466146 13.802083 9.375 14.0625 9.375 C 14.322916 9.375 14.544271 9.466146 14.726562 9.648438 C 14.908854 9.830729 14.999999 10.052084 15 10.3125 C 14.999999 10.572917 14.908854 10.794271 14.726562 10.976562 C 14.544271 11.158854 14.322916 11.25 14.0625 11.25 C 13.802083 11.25 13.580729 11.158854 13.398438 10.976562 C 13.216145 10.794271 13.124999 10.572917 13.125 10.3125 Z M 4.375 13.75 C 4.205729 13.75 4.059245 13.688151 3.935547 13.564453 C 3.811849 13.440756 3.75 13.294271 3.75 13.125 C 3.75 12.955729 3.811849 12.809245 3.935547 12.685547 C 4.059245 12.56185 4.205729 12.5 4.375 12.5 L 15.625 12.5 C 15.79427 12.5 15.940754 12.56185 16.064453 12.685547 C 16.18815 12.809245 16.25 12.955729 16.25 13.125 C 16.25 13.294271 16.18815 13.440756 16.064453 13.564453 C 15.940754 13.688151 15.79427 13.75 15.625 13.75 Z "),
new SettingOption(Translator.SettingsMessageList_Title, Translator.SettingsMessageList_Description, WinoPage.MessageListPage,"F1 M 20 1.25 L 20 12.5 L 18.75 12.5 L 18.75 2.5 L 1.25 2.5 L 1.25 13.75 L 3.75 13.75 L 3.75 16.611328 L 6.611328 13.75 L 13.75 13.75 L 13.75 15 L 7.138672 15 L 2.5 19.638672 L 2.5 15 L 0 15 L 0 1.25 Z M 16.875 13.75 L 20 16.875 L 16.875 20 L 15.986328 19.111328 L 17.607422 17.5 L 11.25 17.5 L 11.25 16.25 L 17.607422 16.25 L 15.986328 14.638672 Z "),
new SettingOption(Translator.SettingsReadComposePane_Title, Translator.SettingsReadComposePane_Description, WinoPage.ReadComposePanePage,"F1 M 20 2.5 L 20 3.75 L 8.75 3.75 L 8.75 2.5 Z M 17.5 15 L 0 15 L 0 13.75 L 17.5 13.75 Z M 2.5 10 L 20 10 L 20 11.25 L 2.5 11.25 Z M 2.5 17.5 L 20 17.5 L 20 18.75 L 2.5 18.75 Z M 3.125 7.5 C 2.695312 7.5 2.291667 7.416992 1.914062 7.250977 C 1.536458 7.084961 1.206055 6.860352 0.922852 6.577148 C 0.639648 6.293945 0.415039 5.963542 0.249023 5.585938 C 0.083008 5.208334 0 4.804688 0 4.375 C 0 3.945312 0.083008 3.541668 0.249023 3.164062 C 0.415039 2.786459 0.639648 2.456055 0.922852 2.172852 C 1.206055 1.889648 1.536458 1.665039 1.914062 1.499023 C 2.291667 1.333008 2.695312 1.25 3.125 1.25 C 3.554688 1.25 3.958333 1.333008 4.335938 1.499023 C 4.713542 1.665039 5.043945 1.889648 5.327148 2.172852 C 5.610352 2.456055 5.834961 2.786459 6.000977 3.164062 C 6.166992 3.541668 6.25 3.945312 6.25 4.375 L 5 4.375 C 5 4.114584 4.951172 3.870443 4.853516 3.642578 C 4.755859 3.414715 4.622396 3.216146 4.453125 3.046875 C 4.283854 2.877605 4.085286 2.744141 3.857422 2.646484 C 3.629557 2.548828 3.385417 2.5 3.125 2.5 C 2.864583 2.5 2.620443 2.548828 2.392578 2.646484 C 2.164713 2.744141 1.966146 2.877605 1.796875 3.046875 C 1.627604 3.216146 1.494141 3.414715 1.396484 3.642578 C 1.298828 3.870443 1.25 4.114584 1.25 4.375 C 1.25 4.635418 1.298828 4.879559 1.396484 5.107422 C 1.494141 5.335287 1.627604 5.533854 1.796875 5.703125 C 1.966146 5.872396 2.164713 6.005859 2.392578 6.103516 C 2.620443 6.201172 2.864583 6.25 3.125 6.25 L 17.5 6.25 L 17.5 7.5 Z "),
new SettingOption(Translator.SettingsAbout_Title, Translator.SettingsAbout_Description, WinoPage.AboutPage,"F1 M 9.375 18.75 C 8.509114 18.75 7.677409 18.639322 6.879883 18.417969 C 6.082356 18.196615 5.335286 17.882486 4.638672 17.475586 C 3.942057 17.068686 3.308919 16.580404 2.739258 16.010742 C 2.169596 15.441081 1.681315 14.807943 1.274414 14.111328 C 0.867513 13.414714 0.553385 12.667644 0.332031 11.870117 C 0.110677 11.072592 0 10.240886 0 9.375 C 0 8.509115 0.110677 7.677409 0.332031 6.879883 C 0.553385 6.082357 0.867513 5.335287 1.274414 4.638672 C 1.681315 3.942059 2.169596 3.30892 2.739258 2.739258 C 3.308919 2.169598 3.942057 1.681316 4.638672 1.274414 C 5.335286 0.867514 6.082356 0.553387 6.879883 0.332031 C 7.677409 0.110678 8.509114 0 9.375 0 C 10.240885 0 11.072591 0.110678 11.870117 0.332031 C 12.667643 0.553387 13.414713 0.867514 14.111328 1.274414 C 14.807942 1.681316 15.44108 2.169598 16.010742 2.739258 C 16.580402 3.30892 17.068684 3.942059 17.475586 4.638672 C 17.882486 5.335287 18.196613 6.082357 18.417969 6.879883 C 18.639322 7.677409 18.75 8.509115 18.75 9.375 C 18.75 10.240886 18.639322 11.072592 18.417969 11.870117 C 18.196613 12.667644 17.882486 13.414714 17.475586 14.111328 C 17.068684 14.807943 16.580402 15.441081 16.010742 16.010742 C 15.44108 16.580404 14.807942 17.068686 14.111328 17.475586 C 13.414713 17.882486 12.667643 18.196615 11.870117 18.417969 C 11.072591 18.639322 10.240885 18.75 9.375 18.75 Z M 9.375 1.25 C 8.626302 1.25 7.906901 1.347656 7.216797 1.542969 C 6.526692 1.738281 5.880533 2.011719 5.27832 2.363281 C 4.676106 2.714844 4.127604 3.138021 3.632812 3.632812 C 3.138021 4.127604 2.714844 4.676107 2.363281 5.27832 C 2.011719 5.880534 1.738281 6.52832 1.542969 7.22168 C 1.347656 7.915039 1.25 8.632812 1.25 9.375 C 1.25 10.117188 1.347656 10.834961 1.542969 11.52832 C 1.738281 12.22168 2.011719 12.869467 2.363281 13.47168 C 2.714844 14.073894 3.138021 14.622396 3.632812 15.117188 C 4.127604 15.611979 4.676106 16.035156 5.27832 16.386719 C 5.880533 16.738281 6.526692 17.011719 7.216797 17.207031 C 7.906901 17.402344 8.626302 17.5 9.375 17.5 C 10.117188 17.5 10.834961 17.402344 11.52832 17.207031 C 12.221679 17.011719 12.869465 16.738281 13.47168 16.386719 C 14.073893 16.035156 14.622396 15.611979 15.117188 15.117188 C 15.611979 14.622396 16.035156 14.073894 16.386719 13.47168 C 16.738281 12.869467 17.011719 12.223308 17.207031 11.533203 C 17.402344 10.8431 17.5 10.123698 17.5 9.375 C 17.5 8.632812 17.402344 7.915039 17.207031 7.22168 C 17.011719 6.52832 16.738281 5.880534 16.386719 5.27832 C 16.035156 4.676107 15.611979 4.127604 15.117188 3.632812 C 14.622396 3.138021 14.073893 2.714844 13.47168 2.363281 C 12.869465 2.011719 12.221679 1.738281 11.52832 1.542969 C 10.834961 1.347656 10.117188 1.25 9.375 1.25 Z M 8.75 7.5 L 10 7.5 L 10 13.75 L 8.75 13.75 Z M 8.75 5 L 10 5 L 10 6.25 L 8.75 6.25 Z "),
diff --git a/Wino.Mail.WinUI/Views/Abstract/KeyboardShortuctsPageAbstract.cs b/Wino.Mail.WinUI/Views/Abstract/KeyboardShortuctsPageAbstract.cs
new file mode 100644
index 00000000..193ce90a
--- /dev/null
+++ b/Wino.Mail.WinUI/Views/Abstract/KeyboardShortuctsPageAbstract.cs
@@ -0,0 +1,8 @@
+using Wino.Core.ViewModels;
+using Wino.Views.Abstract;
+
+namespace Wino.Mail.WinUI.Views.Abstract;
+
+public abstract class KeyboardShortcutsPageAbstract : SettingsPageBase
+{
+}
diff --git a/Wino.Mail.WinUI/Views/Settings/KeyboardShortcutsPage.xaml b/Wino.Mail.WinUI/Views/Settings/KeyboardShortcutsPage.xaml
new file mode 100644
index 00000000..617484ee
--- /dev/null
+++ b/Wino.Mail.WinUI/Views/Settings/KeyboardShortcutsPage.xaml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Wino.Mail.WinUI/Views/Settings/KeyboardShortcutsPage.xaml.cs b/Wino.Mail.WinUI/Views/Settings/KeyboardShortcutsPage.xaml.cs
new file mode 100644
index 00000000..011852c7
--- /dev/null
+++ b/Wino.Mail.WinUI/Views/Settings/KeyboardShortcutsPage.xaml.cs
@@ -0,0 +1,11 @@
+using Wino.Mail.WinUI.Views.Abstract;
+
+namespace Wino.Views.Settings;
+
+public sealed partial class KeyboardShortcutsPage : KeyboardShortcutsPageAbstract
+{
+ public KeyboardShortcutsPage()
+ {
+ this.InitializeComponent();
+ }
+}
diff --git a/Wino.Mail.WinUI/Wino.Mail.WinUI.csproj b/Wino.Mail.WinUI/Wino.Mail.WinUI.csproj
index d9876ef1..c276b633 100644
--- a/Wino.Mail.WinUI/Wino.Mail.WinUI.csproj
+++ b/Wino.Mail.WinUI/Wino.Mail.WinUI.csproj
@@ -259,12 +259,13 @@
True
True
False
- False
+ True
SHA256
True
True
Always
x64
0
+ 2661584A2F31D3419FFF8AA09A2C16B1991B8290
\ No newline at end of file
diff --git a/Wino.Services/DatabaseService.cs b/Wino.Services/DatabaseService.cs
index 2d316a26..d886c8ae 100644
--- a/Wino.Services/DatabaseService.cs
+++ b/Wino.Services/DatabaseService.cs
@@ -58,7 +58,8 @@ public class DatabaseService : IDatabaseService
typeof(CalendarEventAttendee),
typeof(CalendarItem),
typeof(Reminder),
- typeof(Thumbnail)
+ typeof(Thumbnail),
+ typeof(KeyboardShortcut)
);
}
}
diff --git a/Wino.Services/KeyboardShortcutService.cs b/Wino.Services/KeyboardShortcutService.cs
new file mode 100644
index 00000000..262cc53d
--- /dev/null
+++ b/Wino.Services/KeyboardShortcutService.cs
@@ -0,0 +1,218 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using SqlKata;
+using Wino.Core.Domain.Entities.Shared;
+using Wino.Core.Domain.Enums;
+using Wino.Core.Domain.Interfaces;
+using Wino.Services.Extensions;
+
+namespace Wino.Services;
+
+///
+/// Service for managing keyboard shortcuts for mail operations.
+///
+public class KeyboardShortcutService : BaseDatabaseService, IKeyboardShortcutService
+{
+ public KeyboardShortcutService(IDatabaseService databaseService) : base(databaseService)
+ {
+ }
+
+ ///
+ /// Gets all available keyboard shortcuts.
+ ///
+ public async Task> GetKeyboardShortcutsAsync()
+ {
+ var query = new Query(nameof(KeyboardShortcut))
+ .OrderBy(nameof(KeyboardShortcut.MailOperation));
+
+ return await Connection.QueryAsync(query.GetRawQuery());
+ }
+
+ ///
+ /// Gets enabled keyboard shortcuts only.
+ ///
+ public async Task> GetEnabledKeyboardShortcutsAsync()
+ {
+ var query = new Query(nameof(KeyboardShortcut))
+ .Where(nameof(KeyboardShortcut.IsEnabled), true)
+ .OrderBy(nameof(KeyboardShortcut.MailOperation));
+
+ return await Connection.QueryAsync(query.GetRawQuery());
+ }
+
+ ///
+ /// Creates or updates a keyboard shortcut.
+ ///
+ public async Task SaveKeyboardShortcutAsync(KeyboardShortcut shortcut)
+ {
+ if (shortcut.Id == Guid.Empty)
+ {
+ shortcut.Id = Guid.NewGuid();
+ shortcut.CreatedAt = DateTime.UtcNow;
+ await Connection.InsertAsync(shortcut);
+ }
+ else
+ {
+ await Connection.UpdateAsync(shortcut);
+ }
+
+ return shortcut;
+ }
+
+ ///
+ /// Deletes a keyboard shortcut.
+ ///
+ public async Task DeleteKeyboardShortcutAsync(Guid shortcutId)
+ {
+ var query = new Query(nameof(KeyboardShortcut))
+ .Where(nameof(KeyboardShortcut.Id), shortcutId);
+
+ await Connection.ExecuteAsync($"DELETE FROM {nameof(KeyboardShortcut)} WHERE {nameof(KeyboardShortcut.Id)} = ?", shortcutId);
+ }
+
+ ///
+ /// Gets the mail operation for the given key combination.
+ ///
+ public async Task GetMailOperationForKeyAsync(string key, ModifierKeys modifierKeys)
+ {
+ var query = new Query(nameof(KeyboardShortcut))
+ .Where(nameof(KeyboardShortcut.Key), key)
+ .Where(nameof(KeyboardShortcut.ModifierKeys), (int)modifierKeys)
+ .Where(nameof(KeyboardShortcut.IsEnabled), true);
+
+ var shortcut = await Connection.FindWithQueryAsync(query.GetRawQuery());
+ return shortcut?.MailOperation;
+ }
+
+ ///
+ /// Checks if a key combination is already assigned to another shortcut.
+ ///
+ public async Task IsKeyCombinationInUseAsync(string key, ModifierKeys modifierKeys, Guid? excludeShortcutId = null)
+ {
+ var query = new Query(nameof(KeyboardShortcut))
+ .Where(nameof(KeyboardShortcut.Key), key)
+ .Where(nameof(KeyboardShortcut.ModifierKeys), (int)modifierKeys);
+
+ if (excludeShortcutId.HasValue)
+ {
+ query = query.WhereNot(nameof(KeyboardShortcut.Id), excludeShortcutId.Value);
+ }
+
+ var shortcut = await Connection.FindWithQueryAsync(query.GetRawQuery());
+ return shortcut != null;
+ }
+
+ ///
+ /// Creates default keyboard shortcuts for common mail operations.
+ ///
+ public async Task CreateDefaultShortcutsAsync()
+ {
+ var defaultShortcuts = GetDefaultShortcuts();
+
+ foreach (var shortcut in defaultShortcuts)
+ {
+ // Only create if it doesn't exist already
+ var exists = await IsKeyCombinationInUseAsync(shortcut.Key, shortcut.ModifierKeys);
+ if (!exists)
+ {
+ await SaveKeyboardShortcutAsync(shortcut);
+ }
+ }
+ }
+
+ ///
+ /// Resets all shortcuts to defaults.
+ ///
+ public async Task ResetToDefaultShortcutsAsync()
+ {
+ // Delete all existing shortcuts
+ await Connection.ExecuteAsync($"DELETE FROM {nameof(KeyboardShortcut)}");
+
+ // Create default shortcuts
+ await CreateDefaultShortcutsAsync();
+ }
+
+ ///
+ /// Gets the default keyboard shortcuts.
+ ///
+ private static List GetDefaultShortcuts()
+ {
+ return new List
+ {
+ new KeyboardShortcut
+ {
+ Id = Guid.NewGuid(),
+ Key = "Delete",
+ ModifierKeys = ModifierKeys.None,
+ MailOperation = MailOperation.SoftDelete,
+ IsEnabled = true
+ },
+ new KeyboardShortcut
+ {
+ Id = Guid.NewGuid(),
+ Key = "Delete",
+ ModifierKeys = ModifierKeys.Shift,
+ MailOperation = MailOperation.HardDelete,
+ IsEnabled = true
+ },
+ new KeyboardShortcut
+ {
+ Id = Guid.NewGuid(),
+ Key = "A",
+ ModifierKeys = ModifierKeys.Control,
+ MailOperation = MailOperation.Archive,
+ IsEnabled = true
+ },
+ new KeyboardShortcut
+ {
+ Id = Guid.NewGuid(),
+ Key = "R",
+ ModifierKeys = ModifierKeys.Control,
+ MailOperation = MailOperation.MarkAsRead,
+ IsEnabled = true
+ },
+ new KeyboardShortcut
+ {
+ Id = Guid.NewGuid(),
+ Key = "U",
+ ModifierKeys = ModifierKeys.Control,
+ MailOperation = MailOperation.MarkAsUnread,
+ IsEnabled = true
+ },
+ new KeyboardShortcut
+ {
+ Id = Guid.NewGuid(),
+ Key = "F",
+ ModifierKeys = ModifierKeys.Control,
+ MailOperation = MailOperation.SetFlag,
+ IsEnabled = true
+ },
+ new KeyboardShortcut
+ {
+ Id = Guid.NewGuid(),
+ Key = "F",
+ ModifierKeys = ModifierKeys.Control | ModifierKeys.Shift,
+ MailOperation = MailOperation.ClearFlag,
+ IsEnabled = true
+ },
+ new KeyboardShortcut
+ {
+ Id = Guid.NewGuid(),
+ Key = "J",
+ ModifierKeys = ModifierKeys.Control,
+ MailOperation = MailOperation.MoveToJunk,
+ IsEnabled = true
+ },
+ new KeyboardShortcut
+ {
+ Id = Guid.NewGuid(),
+ Key = "M",
+ ModifierKeys = ModifierKeys.Control,
+ MailOperation = MailOperation.Move,
+ IsEnabled = true
+ }
+ };
+ }
+}
\ No newline at end of file
diff --git a/Wino.Services/ServicesContainerSetup.cs b/Wino.Services/ServicesContainerSetup.cs
index f8cea686..42647998 100644
--- a/Wino.Services/ServicesContainerSetup.cs
+++ b/Wino.Services/ServicesContainerSetup.cs
@@ -23,5 +23,6 @@ public static class ServicesContainerSetup
services.AddTransient();
services.AddTransient();
services.AddTransient();
+ services.AddTransient();
}
}