2025-10-29 16:26:46 +01:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Wino.Core.Domain.Entities.Shared;
|
|
|
|
|
using Wino.Core.Domain.Enums;
|
|
|
|
|
using Wino.Core.Domain.Interfaces;
|
|
|
|
|
using Wino.Services.Extensions;
|
|
|
|
|
|
|
|
|
|
namespace Wino.Services;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-08 13:21:42 +01:00
|
|
|
/// Service for managing keyboard shortcuts for mail and calendar actions.
|
2025-10-29 16:26:46 +01:00
|
|
|
/// </summary>
|
|
|
|
|
public class KeyboardShortcutService : BaseDatabaseService, IKeyboardShortcutService
|
|
|
|
|
{
|
|
|
|
|
public KeyboardShortcutService(IDatabaseService databaseService) : base(databaseService)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets all available keyboard shortcuts.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async Task<IEnumerable<KeyboardShortcut>> GetKeyboardShortcutsAsync()
|
|
|
|
|
{
|
2025-11-15 13:29:02 +01:00
|
|
|
return await Connection.QueryAsync<KeyboardShortcut>(
|
2026-03-08 13:21:42 +01:00
|
|
|
"SELECT * FROM KeyboardShortcut ORDER BY Mode, Action");
|
2025-10-29 16:26:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets enabled keyboard shortcuts only.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async Task<IEnumerable<KeyboardShortcut>> GetEnabledKeyboardShortcutsAsync()
|
|
|
|
|
{
|
2025-11-15 13:29:02 +01:00
|
|
|
return await Connection.QueryAsync<KeyboardShortcut>(
|
2026-03-08 13:21:42 +01:00
|
|
|
"SELECT * FROM KeyboardShortcut WHERE IsEnabled = ? ORDER BY Mode, Action",
|
2025-11-15 13:29:02 +01:00
|
|
|
true);
|
2025-10-29 16:26:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates or updates a keyboard shortcut.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async Task<KeyboardShortcut> SaveKeyboardShortcutAsync(KeyboardShortcut shortcut)
|
|
|
|
|
{
|
|
|
|
|
if (shortcut.Id == Guid.Empty)
|
|
|
|
|
{
|
|
|
|
|
shortcut.Id = Guid.NewGuid();
|
|
|
|
|
shortcut.CreatedAt = DateTime.UtcNow;
|
2025-11-14 14:28:10 +01:00
|
|
|
await Connection.InsertAsync(shortcut, typeof(KeyboardShortcut));
|
2025-10-29 16:26:46 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2025-11-14 14:28:10 +01:00
|
|
|
await Connection.UpdateAsync(shortcut, typeof(KeyboardShortcut));
|
2025-10-29 16:26:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return shortcut;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Deletes a keyboard shortcut.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async Task DeleteKeyboardShortcutAsync(Guid shortcutId)
|
|
|
|
|
{
|
|
|
|
|
await Connection.ExecuteAsync($"DELETE FROM {nameof(KeyboardShortcut)} WHERE {nameof(KeyboardShortcut.Id)} = ?", shortcutId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2026-03-08 13:21:42 +01:00
|
|
|
/// Gets the shortcut for the given key combination.
|
2025-10-29 16:26:46 +01:00
|
|
|
/// </summary>
|
2026-03-08 13:21:42 +01:00
|
|
|
public async Task<KeyboardShortcut> GetShortcutForKeyAsync(WinoApplicationMode mode, string key, ModifierKeys modifierKeys)
|
2025-10-29 16:26:46 +01:00
|
|
|
{
|
2026-03-08 13:21:42 +01:00
|
|
|
const string query = "SELECT * FROM KeyboardShortcut WHERE Mode = ? AND Key = ? AND ModifierKeys = ? AND IsEnabled = ? LIMIT 1";
|
|
|
|
|
return await Connection.FindWithQueryAsync<KeyboardShortcut>(query, (int)mode, key, (int)modifierKeys, 1);
|
2025-10-29 16:26:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks if a key combination is already assigned to another shortcut.
|
|
|
|
|
/// </summary>
|
2026-03-08 13:21:42 +01:00
|
|
|
public async Task<bool> IsKeyCombinationInUseAsync(WinoApplicationMode mode, string key, ModifierKeys modifierKeys, Guid? excludeShortcutId = null)
|
2025-10-29 16:26:46 +01:00
|
|
|
{
|
2025-11-15 13:29:02 +01:00
|
|
|
string query;
|
|
|
|
|
KeyboardShortcut shortcut;
|
2026-03-08 13:21:42 +01:00
|
|
|
|
2025-10-29 16:26:46 +01:00
|
|
|
if (excludeShortcutId.HasValue)
|
|
|
|
|
{
|
2026-03-08 13:21:42 +01:00
|
|
|
query = "SELECT * FROM KeyboardShortcut WHERE Mode = ? AND Key = ? AND ModifierKeys = ? AND Id != ? LIMIT 1";
|
|
|
|
|
shortcut = await Connection.FindWithQueryAsync<KeyboardShortcut>(query, (int)mode, key, (int)modifierKeys, excludeShortcutId.Value);
|
2025-10-29 16:26:46 +01:00
|
|
|
}
|
2025-11-15 13:29:02 +01:00
|
|
|
else
|
|
|
|
|
{
|
2026-03-08 13:21:42 +01:00
|
|
|
query = "SELECT * FROM KeyboardShortcut WHERE Mode = ? AND Key = ? AND ModifierKeys = ? LIMIT 1";
|
|
|
|
|
shortcut = await Connection.FindWithQueryAsync<KeyboardShortcut>(query, (int)mode, key, (int)modifierKeys);
|
2025-11-15 13:29:02 +01:00
|
|
|
}
|
2026-03-08 13:21:42 +01:00
|
|
|
|
2025-10-29 16:26:46 +01:00
|
|
|
return shortcut != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates default keyboard shortcuts for common mail operations.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async Task CreateDefaultShortcutsAsync()
|
|
|
|
|
{
|
|
|
|
|
var defaultShortcuts = GetDefaultShortcuts();
|
|
|
|
|
|
|
|
|
|
foreach (var shortcut in defaultShortcuts)
|
|
|
|
|
{
|
|
|
|
|
// Only create if it doesn't exist already
|
2026-03-08 13:21:42 +01:00
|
|
|
var exists = await IsKeyCombinationInUseAsync(shortcut.Mode, shortcut.Key, shortcut.ModifierKeys);
|
2025-10-29 16:26:46 +01:00
|
|
|
if (!exists)
|
|
|
|
|
{
|
|
|
|
|
await SaveKeyboardShortcutAsync(shortcut);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Resets all shortcuts to defaults.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public async Task ResetToDefaultShortcutsAsync()
|
|
|
|
|
{
|
|
|
|
|
// Delete all existing shortcuts
|
|
|
|
|
await Connection.ExecuteAsync($"DELETE FROM {nameof(KeyboardShortcut)}");
|
|
|
|
|
|
|
|
|
|
// Create default shortcuts
|
|
|
|
|
await CreateDefaultShortcutsAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets the default keyboard shortcuts.
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static List<KeyboardShortcut> GetDefaultShortcuts()
|
|
|
|
|
{
|
|
|
|
|
return new List<KeyboardShortcut>
|
|
|
|
|
{
|
|
|
|
|
new KeyboardShortcut
|
|
|
|
|
{
|
|
|
|
|
Id = Guid.NewGuid(),
|
|
|
|
|
Key = "Delete",
|
|
|
|
|
ModifierKeys = ModifierKeys.None,
|
2026-03-08 13:21:42 +01:00
|
|
|
Mode = WinoApplicationMode.Mail,
|
|
|
|
|
Action = KeyboardShortcutAction.Delete,
|
2025-10-29 16:26:46 +01:00
|
|
|
IsEnabled = true
|
|
|
|
|
},
|
|
|
|
|
new KeyboardShortcut
|
|
|
|
|
{
|
|
|
|
|
Id = Guid.NewGuid(),
|
2026-03-08 13:21:42 +01:00
|
|
|
Key = "N",
|
|
|
|
|
ModifierKeys = ModifierKeys.Control,
|
|
|
|
|
Mode = WinoApplicationMode.Mail,
|
|
|
|
|
Action = KeyboardShortcutAction.NewMail,
|
2025-10-29 16:26:46 +01:00
|
|
|
IsEnabled = true
|
|
|
|
|
},
|
|
|
|
|
new KeyboardShortcut
|
|
|
|
|
{
|
|
|
|
|
Id = Guid.NewGuid(),
|
|
|
|
|
Key = "A",
|
|
|
|
|
ModifierKeys = ModifierKeys.Control,
|
2026-03-08 13:21:42 +01:00
|
|
|
Mode = WinoApplicationMode.Mail,
|
|
|
|
|
Action = KeyboardShortcutAction.ToggleArchive,
|
2025-10-29 16:26:46 +01:00
|
|
|
IsEnabled = true
|
|
|
|
|
},
|
|
|
|
|
new KeyboardShortcut
|
|
|
|
|
{
|
|
|
|
|
Id = Guid.NewGuid(),
|
|
|
|
|
Key = "R",
|
|
|
|
|
ModifierKeys = ModifierKeys.Control,
|
2026-03-08 13:21:42 +01:00
|
|
|
Mode = WinoApplicationMode.Mail,
|
|
|
|
|
Action = KeyboardShortcutAction.ToggleReadUnread,
|
2025-10-29 16:26:46 +01:00
|
|
|
IsEnabled = true
|
|
|
|
|
},
|
|
|
|
|
new KeyboardShortcut
|
|
|
|
|
{
|
|
|
|
|
Id = Guid.NewGuid(),
|
2026-03-08 13:21:42 +01:00
|
|
|
Key = "F",
|
2025-10-29 16:26:46 +01:00
|
|
|
ModifierKeys = ModifierKeys.Control,
|
2026-03-08 13:21:42 +01:00
|
|
|
Mode = WinoApplicationMode.Mail,
|
|
|
|
|
Action = KeyboardShortcutAction.ToggleFlag,
|
2025-10-29 16:26:46 +01:00
|
|
|
IsEnabled = true
|
|
|
|
|
},
|
|
|
|
|
new KeyboardShortcut
|
|
|
|
|
{
|
|
|
|
|
Id = Guid.NewGuid(),
|
2026-03-08 13:21:42 +01:00
|
|
|
Key = "M",
|
2025-10-29 16:26:46 +01:00
|
|
|
ModifierKeys = ModifierKeys.Control,
|
2026-03-08 13:21:42 +01:00
|
|
|
Mode = WinoApplicationMode.Mail,
|
|
|
|
|
Action = KeyboardShortcutAction.Move,
|
2025-10-29 16:26:46 +01:00
|
|
|
IsEnabled = true
|
|
|
|
|
},
|
|
|
|
|
new KeyboardShortcut
|
|
|
|
|
{
|
|
|
|
|
Id = Guid.NewGuid(),
|
2026-03-08 13:21:42 +01:00
|
|
|
Key = "R",
|
|
|
|
|
ModifierKeys = ModifierKeys.Control,
|
|
|
|
|
Mode = WinoApplicationMode.Mail,
|
|
|
|
|
Action = KeyboardShortcutAction.Reply,
|
2025-10-29 16:26:46 +01:00
|
|
|
IsEnabled = true
|
|
|
|
|
},
|
|
|
|
|
new KeyboardShortcut
|
|
|
|
|
{
|
|
|
|
|
Id = Guid.NewGuid(),
|
2026-03-08 13:21:42 +01:00
|
|
|
Key = "R",
|
|
|
|
|
ModifierKeys = ModifierKeys.Control | ModifierKeys.Shift,
|
|
|
|
|
Mode = WinoApplicationMode.Mail,
|
|
|
|
|
Action = KeyboardShortcutAction.ReplyAll,
|
2025-10-29 16:26:46 +01:00
|
|
|
IsEnabled = true
|
|
|
|
|
},
|
|
|
|
|
new KeyboardShortcut
|
|
|
|
|
{
|
|
|
|
|
Id = Guid.NewGuid(),
|
2026-03-08 13:21:42 +01:00
|
|
|
Key = "Enter",
|
2025-10-29 16:26:46 +01:00
|
|
|
ModifierKeys = ModifierKeys.Control,
|
2026-03-08 13:21:42 +01:00
|
|
|
Mode = WinoApplicationMode.Mail,
|
|
|
|
|
Action = KeyboardShortcutAction.Send,
|
2025-10-29 16:26:46 +01:00
|
|
|
IsEnabled = true
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
2026-03-08 13:21:42 +01:00
|
|
|
}
|