2026-03-14 14:14:58 +01:00
|
|
|
using System;
|
2026-03-12 19:04:47 +01:00
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using Wino.Core.Domain.Enums;
|
|
|
|
|
|
|
|
|
|
namespace Wino.Core.Domain.Models.Settings;
|
|
|
|
|
|
|
|
|
|
public sealed class SettingsNavigationItemInfo(
|
|
|
|
|
WinoPage? pageType,
|
|
|
|
|
string title,
|
|
|
|
|
string description,
|
|
|
|
|
string glyph = "",
|
2026-03-14 14:14:58 +01:00
|
|
|
bool isSeparator = false,
|
|
|
|
|
string searchKeywords = "")
|
2026-03-12 19:04:47 +01:00
|
|
|
{
|
|
|
|
|
public WinoPage? PageType { get; } = pageType;
|
|
|
|
|
public string Title { get; } = title;
|
|
|
|
|
public string Description { get; } = description;
|
|
|
|
|
public string Glyph { get; } = glyph;
|
|
|
|
|
public bool IsSeparator { get; } = isSeparator;
|
2026-03-14 14:14:58 +01:00
|
|
|
public string SearchKeywords { get; } = searchKeywords;
|
2026-03-12 19:04:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static class SettingsNavigationInfoProvider
|
|
|
|
|
{
|
|
|
|
|
public static IReadOnlyList<SettingsNavigationItemInfo> GetNavigationItems(string manageAccountsDescription = "")
|
|
|
|
|
{
|
|
|
|
|
return
|
|
|
|
|
[
|
|
|
|
|
new(WinoPage.SettingOptionsPage,
|
|
|
|
|
Translator.SettingsHome_Title,
|
|
|
|
|
Translator.SettingsOptions_HeroDescription,
|
|
|
|
|
"\uE80F"),
|
|
|
|
|
new(WinoPage.ManageAccountsPage,
|
|
|
|
|
Translator.SettingsManageAccountSettings_Title,
|
|
|
|
|
manageAccountsDescription,
|
2026-03-14 14:14:58 +01:00
|
|
|
"\uE77B",
|
|
|
|
|
searchKeywords: Translator.SettingsSearch_ManageAccounts_Keywords),
|
2026-03-18 09:00:26 +01:00
|
|
|
new(WinoPage.WinoAccountManagementPage,
|
|
|
|
|
Translator.WinoAccount_SettingsSection_Title,
|
|
|
|
|
Translator.WinoAccount_SettingsSection_Description,
|
|
|
|
|
"\uE77B",
|
2026-03-21 00:58:01 +01:00
|
|
|
searchKeywords: string.Empty),
|
2026-03-12 19:04:47 +01:00
|
|
|
new(null, Translator.SettingsOptions_GeneralSection, string.Empty, "\uE713", isSeparator: true),
|
|
|
|
|
new(WinoPage.AppPreferencesPage,
|
|
|
|
|
Translator.SettingsAppPreferences_Title,
|
|
|
|
|
Translator.SettingsAppPreferences_Description,
|
2026-03-14 14:14:58 +01:00
|
|
|
"\uE770",
|
|
|
|
|
searchKeywords: Translator.SettingsSearch_AppPreferences_Keywords),
|
2026-03-12 19:04:47 +01:00
|
|
|
new(WinoPage.LanguageTimePage,
|
|
|
|
|
Translator.SettingsLanguageTime_Title,
|
|
|
|
|
Translator.SettingsLanguageTime_Description,
|
2026-03-14 14:14:58 +01:00
|
|
|
"\uE775",
|
|
|
|
|
searchKeywords: Translator.SettingsSearch_LanguageTime_Keywords),
|
2026-03-12 19:04:47 +01:00
|
|
|
new(WinoPage.PersonalizationPage,
|
|
|
|
|
Translator.SettingsPersonalization_Title,
|
|
|
|
|
Translator.SettingsPersonalization_Description,
|
2026-03-14 14:14:58 +01:00
|
|
|
"\uE771",
|
|
|
|
|
searchKeywords: Translator.SettingsSearch_Personalization_Keywords),
|
2026-03-12 19:04:47 +01:00
|
|
|
new(WinoPage.AboutPage,
|
|
|
|
|
Translator.SettingsAbout_Title,
|
|
|
|
|
Translator.SettingsAbout_Description,
|
2026-03-14 14:14:58 +01:00
|
|
|
"\uE946",
|
|
|
|
|
searchKeywords: Translator.SettingsSearch_About_Keywords),
|
2026-03-12 19:04:47 +01:00
|
|
|
new(null, Translator.SettingsOptions_MailSection, string.Empty, "\uE715", isSeparator: true),
|
|
|
|
|
new(WinoPage.KeyboardShortcutsPage,
|
|
|
|
|
Translator.Settings_KeyboardShortcuts_Title,
|
|
|
|
|
Translator.Settings_KeyboardShortcuts_Description,
|
2026-03-14 14:14:58 +01:00
|
|
|
"\uE765",
|
|
|
|
|
searchKeywords: Translator.SettingsSearch_KeyboardShortcuts_Keywords),
|
2026-03-12 19:04:47 +01:00
|
|
|
new(WinoPage.MessageListPage,
|
|
|
|
|
Translator.SettingsMessageList_Title,
|
|
|
|
|
Translator.SettingsMessageList_Description,
|
2026-03-14 14:14:58 +01:00
|
|
|
"\uE8C4",
|
|
|
|
|
searchKeywords: Translator.SettingsSearch_MessageList_Keywords),
|
2026-03-12 19:04:47 +01:00
|
|
|
new(WinoPage.ReadComposePanePage,
|
|
|
|
|
Translator.SettingsReadComposePane_Title,
|
|
|
|
|
Translator.SettingsReadComposePane_Description,
|
2026-03-14 14:14:58 +01:00
|
|
|
"\uE8BD",
|
|
|
|
|
searchKeywords: Translator.SettingsSearch_ReadComposePane_Keywords),
|
2026-03-12 19:04:47 +01:00
|
|
|
new(WinoPage.SignatureAndEncryptionPage,
|
|
|
|
|
Translator.SettingsSignatureAndEncryption_Title,
|
|
|
|
|
Translator.SettingsSignatureAndEncryption_Description,
|
2026-03-14 14:14:58 +01:00
|
|
|
"\uE8D7",
|
|
|
|
|
searchKeywords: Translator.SettingsSearch_SignatureAndEncryption_Keywords),
|
2026-03-12 19:04:47 +01:00
|
|
|
new(WinoPage.StoragePage,
|
|
|
|
|
Translator.SettingsStorage_Title,
|
|
|
|
|
Translator.SettingsStorage_Description,
|
2026-03-14 14:14:58 +01:00
|
|
|
"\uE81C",
|
|
|
|
|
searchKeywords: Translator.SettingsSearch_Storage_Keywords),
|
2026-03-12 19:04:47 +01:00
|
|
|
new(null, Translator.SettingsOptions_CalendarSection, string.Empty, "\uE787", isSeparator: true),
|
|
|
|
|
new(WinoPage.CalendarSettingsPage,
|
|
|
|
|
Translator.SettingsCalendarSettings_Title,
|
|
|
|
|
Translator.SettingsCalendarSettings_Description,
|
2026-03-14 14:14:58 +01:00
|
|
|
"\uE787",
|
|
|
|
|
searchKeywords: Translator.SettingsSearch_CalendarSettings_Keywords)
|
2026-03-12 19:04:47 +01:00
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-14 14:14:58 +01:00
|
|
|
public static IReadOnlyList<SettingsNavigationItemInfo> Search(string query, string manageAccountsDescription = "")
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(query))
|
|
|
|
|
return [];
|
|
|
|
|
|
|
|
|
|
var normalizedQuery = NormalizeSearchText(query);
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(normalizedQuery))
|
|
|
|
|
return [];
|
|
|
|
|
|
|
|
|
|
var queryTerms = normalizedQuery.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
|
|
|
|
|
|
|
|
|
return GetNavigationItems(manageAccountsDescription)
|
|
|
|
|
.Where(item => item.PageType.HasValue && !item.IsSeparator && item.PageType.Value != WinoPage.SettingOptionsPage)
|
|
|
|
|
.Select(item => new
|
|
|
|
|
{
|
|
|
|
|
Item = item,
|
|
|
|
|
Score = CalculateSearchScore(item, normalizedQuery, queryTerms)
|
|
|
|
|
})
|
|
|
|
|
.Where(x => x.Score > 0)
|
|
|
|
|
.OrderByDescending(x => x.Score)
|
|
|
|
|
.ThenBy(x => x.Item.Title)
|
|
|
|
|
.Select(x => x.Item)
|
|
|
|
|
.ToList();
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-12 19:04:47 +01:00
|
|
|
public static SettingsNavigationItemInfo GetInfo(WinoPage pageType, string manageAccountsDescription = "")
|
|
|
|
|
{
|
|
|
|
|
var rootPage = GetRootPage(pageType);
|
|
|
|
|
return GetNavigationItems(manageAccountsDescription).First(item => item.PageType == rootPage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static string GetPageTitle(WinoPage pageType)
|
|
|
|
|
=> pageType switch
|
|
|
|
|
{
|
|
|
|
|
WinoPage.SettingOptionsPage => Translator.MenuSettings,
|
|
|
|
|
WinoPage.ManageAccountsPage => Translator.SettingsManageAccountSettings_Title,
|
|
|
|
|
WinoPage.AccountManagementPage => Translator.SettingsManageAccountSettings_Title,
|
2026-03-18 09:00:26 +01:00
|
|
|
WinoPage.WinoAccountManagementPage => Translator.WinoAccount_SettingsSection_Title,
|
2026-03-12 19:04:47 +01:00
|
|
|
WinoPage.PersonalizationPage => Translator.SettingsPersonalization_Title,
|
|
|
|
|
WinoPage.AboutPage => Translator.SettingsAbout_Title,
|
|
|
|
|
WinoPage.MessageListPage => Translator.SettingsMessageList_Title,
|
|
|
|
|
WinoPage.ReadComposePanePage => Translator.SettingsReadComposePane_Title,
|
|
|
|
|
WinoPage.LanguageTimePage => Translator.SettingsLanguageTime_Title,
|
|
|
|
|
WinoPage.AppPreferencesPage => Translator.SettingsAppPreferences_Title,
|
|
|
|
|
WinoPage.CalendarSettingsPage => Translator.SettingsCalendarSettings_Title,
|
|
|
|
|
WinoPage.SignatureAndEncryptionPage => Translator.SettingsSignatureAndEncryption_Title,
|
|
|
|
|
WinoPage.KeyboardShortcutsPage => Translator.Settings_KeyboardShortcuts_Title,
|
|
|
|
|
WinoPage.StoragePage => Translator.SettingsStorage_Title,
|
|
|
|
|
WinoPage.EmailTemplatesPage => Translator.SettingsEmailTemplates_Title,
|
|
|
|
|
WinoPage.CreateEmailTemplatePage => Translator.SettingsEmailTemplates_Title,
|
|
|
|
|
_ => GetInfo(pageType).Title
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public static WinoPage GetRootPage(WinoPage pageType)
|
|
|
|
|
=> pageType switch
|
|
|
|
|
{
|
|
|
|
|
WinoPage.AccountManagementPage => WinoPage.ManageAccountsPage,
|
|
|
|
|
WinoPage.AccountDetailsPage => WinoPage.ManageAccountsPage,
|
|
|
|
|
WinoPage.MergedAccountDetailsPage => WinoPage.ManageAccountsPage,
|
|
|
|
|
WinoPage.AliasManagementPage => WinoPage.ManageAccountsPage,
|
|
|
|
|
WinoPage.SignatureManagementPage => WinoPage.ManageAccountsPage,
|
|
|
|
|
WinoPage.ImapCalDavSettingsPage => WinoPage.ManageAccountsPage,
|
|
|
|
|
WinoPage.EmailTemplatesPage => WinoPage.ManageAccountsPage,
|
|
|
|
|
WinoPage.CreateEmailTemplatePage => WinoPage.ManageAccountsPage,
|
|
|
|
|
WinoPage.CalendarAccountSettingsPage => WinoPage.CalendarSettingsPage,
|
|
|
|
|
_ => pageType
|
|
|
|
|
};
|
2026-03-14 14:14:58 +01:00
|
|
|
|
|
|
|
|
private static int CalculateSearchScore(SettingsNavigationItemInfo item, string normalizedQuery, IReadOnlyList<string> queryTerms)
|
|
|
|
|
{
|
|
|
|
|
var title = NormalizeSearchText(item.Title);
|
|
|
|
|
var description = NormalizeSearchText(item.Description);
|
|
|
|
|
var keywords = NormalizeSearchText(item.SearchKeywords);
|
|
|
|
|
var combinedText = string.Join(' ', new[] { title, description, keywords }.Where(text => !string.IsNullOrWhiteSpace(text)));
|
|
|
|
|
|
|
|
|
|
if (!combinedText.Contains(normalizedQuery, StringComparison.Ordinal) &&
|
|
|
|
|
!queryTerms.All(term => combinedText.Contains(term, StringComparison.Ordinal)))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var score = 0;
|
|
|
|
|
|
|
|
|
|
if (title.StartsWith(normalizedQuery, StringComparison.Ordinal))
|
|
|
|
|
score += 500;
|
|
|
|
|
else if (title.Contains(normalizedQuery, StringComparison.Ordinal))
|
|
|
|
|
score += 360;
|
|
|
|
|
|
|
|
|
|
if (keywords.Contains(normalizedQuery, StringComparison.Ordinal))
|
|
|
|
|
score += 280;
|
|
|
|
|
|
|
|
|
|
if (description.Contains(normalizedQuery, StringComparison.Ordinal))
|
|
|
|
|
score += 180;
|
|
|
|
|
|
|
|
|
|
foreach (var term in queryTerms)
|
|
|
|
|
{
|
|
|
|
|
if (title.Contains(term, StringComparison.Ordinal))
|
|
|
|
|
score += 70;
|
|
|
|
|
|
|
|
|
|
if (keywords.Contains(term, StringComparison.Ordinal))
|
|
|
|
|
score += 50;
|
|
|
|
|
|
|
|
|
|
if (description.Contains(term, StringComparison.Ordinal))
|
|
|
|
|
score += 30;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return score;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string NormalizeSearchText(string value)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
|
|
|
return string.Empty;
|
|
|
|
|
|
|
|
|
|
var sanitized = value
|
|
|
|
|
.ToLowerInvariant()
|
|
|
|
|
.Select(character => char.IsLetterOrDigit(character) ? character : ' ')
|
|
|
|
|
.ToArray();
|
|
|
|
|
|
|
|
|
|
return string.Join(' ', new string(sanitized).Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries));
|
|
|
|
|
}
|
2026-03-12 19:04:47 +01:00
|
|
|
}
|