diff --git a/src/PassKey.Core/Services/CardTypeDetector.cs b/src/PassKey.Core/Services/CardTypeDetector.cs
index 8f74c51..640b34f 100644
--- a/src/PassKey.Core/Services/CardTypeDetector.cs
+++ b/src/PassKey.Core/Services/CardTypeDetector.cs
@@ -4,6 +4,34 @@ namespace PassKey.Core.Services;
public static class CardTypeDetector
{
+ ///
+ /// BIN (Bank Identification Number) / IIN prefix ranges used for card-type detection.
+ /// Sources: EMVCo IIN Registry; updated ranges as of 2024.
+ ///
+ private static class BinRanges
+ {
+ // MasterCard: standard range 51-55 is checked inline with a 2-digit prefix;
+ // the expanded range covers re-issued BINs introduced in 2017.
+ internal const int MasterCardExpandedStart = 2221;
+ internal const int MasterCardExpandedEnd = 2720;
+
+ // Discover: 3-digit prefix range (644-649)
+ internal const int DiscoverRange3Start = 644;
+ internal const int DiscoverRange3End = 649;
+
+ // Discover: 6-digit IIN range (co-branded UnionPay; 622126-622925)
+ internal const int DiscoverRange6Start = 622126;
+ internal const int DiscoverRange6End = 622925;
+
+ // JCB: 4-digit prefix range (3528-3589)
+ internal const int JcbRangeStart = 3528;
+ internal const int JcbRangeEnd = 3589;
+
+ // Diners Club Classic: 3-digit prefix range (300-305)
+ internal const int DinersRange3Start = 300;
+ internal const int DinersRange3End = 305;
+ }
+
///
/// Detects the card type from the card number using BIN prefix tables.
///
@@ -24,7 +52,7 @@ public static CardType Detect(string cardNumber)
if (digits.StartsWith('4'))
return CardType.Visa;
- // MasterCard: 51-55 or 2221-2720
+ // MasterCard: 51-55 or expanded range 2221-2720
if (digits.Length >= 2)
{
var prefix2 = int.Parse(digits[..2]);
@@ -34,7 +62,7 @@ public static CardType Detect(string cardNumber)
if (digits.Length >= 4)
{
var prefix4 = int.Parse(digits[..4]);
- if (prefix4 >= 2221 && prefix4 <= 2720)
+ if (prefix4 >= BinRanges.MasterCardExpandedStart && prefix4 <= BinRanges.MasterCardExpandedEnd)
return CardType.MasterCard;
}
@@ -44,13 +72,13 @@ public static CardType Detect(string cardNumber)
if (digits.Length >= 3)
{
var prefix3 = int.Parse(digits[..3]);
- if (prefix3 >= 644 && prefix3 <= 649)
+ if (prefix3 >= BinRanges.DiscoverRange3Start && prefix3 <= BinRanges.DiscoverRange3End)
return CardType.Discover;
}
if (digits.Length >= 6)
{
var prefix6 = int.Parse(digits[..6]);
- if (prefix6 >= 622126 && prefix6 <= 622925)
+ if (prefix6 >= BinRanges.DiscoverRange6Start && prefix6 <= BinRanges.DiscoverRange6End)
return CardType.Discover;
}
@@ -58,7 +86,7 @@ public static CardType Detect(string cardNumber)
if (digits.Length >= 4)
{
var prefix4 = int.Parse(digits[..4]);
- if (prefix4 >= 3528 && prefix4 <= 3589)
+ if (prefix4 >= BinRanges.JcbRangeStart && prefix4 <= BinRanges.JcbRangeEnd)
return CardType.JCB;
}
@@ -68,7 +96,7 @@ public static CardType Detect(string cardNumber)
if (digits.Length >= 3)
{
var prefix3 = int.Parse(digits[..3]);
- if (prefix3 >= 300 && prefix3 <= 305)
+ if (prefix3 >= BinRanges.DinersRange3Start && prefix3 <= BinRanges.DinersRange3End)
return CardType.DinersClub;
}
diff --git a/src/PassKey.Core/Services/MergeService.cs b/src/PassKey.Core/Services/MergeService.cs
index ede6de1..0e40955 100644
--- a/src/PassKey.Core/Services/MergeService.cs
+++ b/src/PassKey.Core/Services/MergeService.cs
@@ -11,82 +11,56 @@ public ImportResult MergeInto(Vault target, Vault source, ImportMergeStrategy st
ArgumentNullException.ThrowIfNull(target);
ArgumentNullException.ThrowIfNull(source);
- int pwImported = 0, cardImported = 0, idImported = 0, noteImported = 0;
- int skipped = 0, overwritten = 0;
+ var (pwImported, pwSkipped, pwOverwritten) = MergeCollection(target.Passwords, source.Passwords, strategy, ComputePasswordHash);
+ var (cardImported, cardSkipped, cardOverwritten) = MergeCollection(target.CreditCards, source.CreditCards, strategy, ComputeCardHash);
+ var (idImported, idSkipped, idOverwritten) = MergeCollection(target.Identities, source.Identities, strategy, ComputeIdentityHash);
+ var (noteImported, noteSkipped, noteOverwritten) = MergeCollection(target.SecureNotes, source.SecureNotes, strategy, ComputeNoteHash);
- // Build hash sets of existing entries
- var existingPwHashes = BuildHashSet(target.Passwords, ComputePasswordHash);
- var existingCardHashes = BuildHashSet(target.CreditCards, ComputeCardHash);
- var existingIdHashes = BuildHashSet(target.Identities, ComputeIdentityHash);
- var existingNoteHashes = BuildHashSet(target.SecureNotes, ComputeNoteHash);
+ target.LastModified = DateTime.UtcNow;
- // Merge passwords
- foreach (var entry in source.Passwords)
+ return new ImportResult
{
- var hash = ComputePasswordHash(entry);
- var result = MergeEntry(target.Passwords, entry, hash, existingPwHashes, strategy, ComputePasswordHash);
- switch (result)
- {
- case MergeAction.Imported: pwImported++; break;
- case MergeAction.Skipped: skipped++; break;
- case MergeAction.Overwritten: overwritten++; break;
- }
- }
+ PasswordsImported = pwImported,
+ CardsImported = cardImported,
+ IdentitiesImported = idImported,
+ NotesImported = noteImported,
+ Skipped = pwSkipped + cardSkipped + idSkipped + noteSkipped,
+ Overwritten = pwOverwritten + cardOverwritten + idOverwritten + noteOverwritten
+ };
+ }
- // Merge credit cards
- foreach (var entry in source.CreditCards)
- {
- var hash = ComputeCardHash(entry);
- var result = MergeEntry(target.CreditCards, entry, hash, existingCardHashes, strategy, ComputeCardHash);
- switch (result)
- {
- case MergeAction.Imported: cardImported++; break;
- case MergeAction.Skipped: skipped++; break;
- case MergeAction.Overwritten: overwritten++; break;
- }
- }
+ private enum MergeAction { Imported, Skipped, Overwritten }
- // Merge identities
- foreach (var entry in source.Identities)
- {
- var hash = ComputeIdentityHash(entry);
- var result = MergeEntry(target.Identities, entry, hash, existingIdHashes, strategy, ComputeIdentityHash);
- switch (result)
- {
- case MergeAction.Imported: idImported++; break;
- case MergeAction.Skipped: skipped++; break;
- case MergeAction.Overwritten: overwritten++; break;
- }
- }
+ private const int NoteHashSnippetLength = 256;
+
+ ///
+ /// Merges all entries from into
+ /// applying the given for duplicates.
+ /// Returns a tuple of (imported, skipped, overwritten) counts.
+ ///
+ private static (int imported, int skipped, int overwritten) MergeCollection(
+ List targetList,
+ List sourceList,
+ ImportMergeStrategy strategy,
+ Func hashFunc) where T : class
+ {
+ int imported = 0, skipped = 0, overwritten = 0;
+ var existingHashes = BuildHashSet(targetList, hashFunc);
- // Merge secure notes
- foreach (var entry in source.SecureNotes)
+ foreach (var entry in sourceList)
{
- var hash = ComputeNoteHash(entry);
- var result = MergeEntry(target.SecureNotes, entry, hash, existingNoteHashes, strategy, ComputeNoteHash);
+ var hash = hashFunc(entry);
+ var result = MergeEntry(targetList, entry, hash, existingHashes, strategy, hashFunc);
switch (result)
{
- case MergeAction.Imported: noteImported++; break;
- case MergeAction.Skipped: skipped++; break;
+ case MergeAction.Imported: imported++; break;
+ case MergeAction.Skipped: skipped++; break;
case MergeAction.Overwritten: overwritten++; break;
}
}
-
- target.LastModified = DateTime.UtcNow;
-
- return new ImportResult
- {
- PasswordsImported = pwImported,
- CardsImported = cardImported,
- IdentitiesImported = idImported,
- NotesImported = noteImported,
- Skipped = skipped,
- Overwritten = overwritten
- };
+ return (imported, skipped, overwritten);
}
- private enum MergeAction { Imported, Skipped, Overwritten }
-
private static MergeAction MergeEntry(
List targetList, T entry, string hash,
Dictionary existingHashes,
@@ -165,8 +139,8 @@ internal static string ComputeIdentityHash(IdentityEntry entry)
internal static string ComputeNoteHash(SecureNoteEntry entry)
{
- var contentSnippet = entry.Content.Length > 256
- ? entry.Content[..256]
+ var contentSnippet = entry.Content.Length > NoteHashSnippetLength
+ ? entry.Content[..NoteHashSnippetLength]
: entry.Content;
var input = $"{entry.Title.ToLowerInvariant()}|{contentSnippet}";
return ComputeSha256(input);
diff --git a/src/PassKey.Core/Services/PasswordGenerator.cs b/src/PassKey.Core/Services/PasswordGenerator.cs
index f8ad768..c2af863 100644
--- a/src/PassKey.Core/Services/PasswordGenerator.cs
+++ b/src/PassKey.Core/Services/PasswordGenerator.cs
@@ -10,11 +10,15 @@ public sealed class PasswordGenerator : IPasswordGenerator
private const string Symbols = "!@#$%^&*()-_=+[]{}|;:',.<>?/~`";
private const string AmbiguousChars = "0O1lI|";
+ private const int MinPasswordLength = 8;
+ private const int MaxPasswordLength = 128;
+
public string Generate(PasswordGeneratorOptions options)
{
ArgumentNullException.ThrowIfNull(options);
- if (options.Length < 8 || options.Length > 128)
- throw new ArgumentOutOfRangeException(nameof(options), "Length must be between 8 and 128.");
+ if (options.Length < MinPasswordLength || options.Length > MaxPasswordLength)
+ throw new ArgumentOutOfRangeException(nameof(options),
+ $"Length must be between {MinPasswordLength} and {MaxPasswordLength}.");
var charPool = BuildCharPool(options);
if (charPool.Length == 0)
diff --git a/src/PassKey.Core/Services/PasswordStrengthAnalyzer.cs b/src/PassKey.Core/Services/PasswordStrengthAnalyzer.cs
index bf81fa4..31a0435 100644
--- a/src/PassKey.Core/Services/PasswordStrengthAnalyzer.cs
+++ b/src/PassKey.Core/Services/PasswordStrengthAnalyzer.cs
@@ -104,6 +104,19 @@ private static bool ContainsCommonPattern(string password)
return false;
}
+ ///
+ /// Time conversion constants used when formatting the estimated crack-time string.
+ ///
+ private static class TimeConstants
+ {
+ internal const double SecondsPerMinute = 60;
+ internal const double SecondsPerHour = 3_600; // 60 * 60
+ internal const double SecondsPerDay = 86_400; // 60 * 60 * 24
+ internal const double SecondsPerYear = 31_536_000; // 365 * 24 * 60 * 60
+ internal const double SecondsPerCentury = SecondsPerYear * 100;
+ internal const double SecondsPerMillennium = SecondsPerYear * 1_000;
+ }
+
private static string EstimateCrackTime(int length, bool hasUpper, bool hasLower, bool hasDigit, bool hasSymbol)
{
var charsetSize = 0;
@@ -121,12 +134,12 @@ private static string EstimateCrackTime(int length, bool hasUpper, bool hasLower
return seconds switch
{
< 1 => "instant",
- < 60 => "seconds",
- < 3600 => $"{(int)(seconds / 60)} minutes",
- < 86400 => $"{(int)(seconds / 3600)} hours",
- < 31536000 => $"{(int)(seconds / 86400)} days",
- < 31536000.0 * 100 => $"{(int)(seconds / 31536000)} years",
- < 31536000.0 * 1000 => "centuries",
+ < TimeConstants.SecondsPerMinute => "seconds",
+ < TimeConstants.SecondsPerHour => $"{(int)(seconds / TimeConstants.SecondsPerMinute)} minutes",
+ < TimeConstants.SecondsPerDay => $"{(int)(seconds / TimeConstants.SecondsPerHour)} hours",
+ < TimeConstants.SecondsPerYear => $"{(int)(seconds / TimeConstants.SecondsPerDay)} days",
+ < TimeConstants.SecondsPerCentury => $"{(int)(seconds / TimeConstants.SecondsPerYear)} years",
+ < TimeConstants.SecondsPerMillennium => "centuries",
_ => "millennia"
};
}
diff --git a/src/PassKey.Desktop/Helpers/ListViewHelpers.cs b/src/PassKey.Desktop/Helpers/ListViewHelpers.cs
new file mode 100644
index 0000000..728d287
--- /dev/null
+++ b/src/PassKey.Desktop/Helpers/ListViewHelpers.cs
@@ -0,0 +1,36 @@
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+
+namespace PassKey.Desktop.Helpers;
+
+///
+/// Shared UI helpers for list-view code-behind classes.
+/// Centralises boilerplate that would otherwise be duplicated across
+/// PasswordsListView, CreditCardsListView, IdentitiesListView
+/// and SecureNotesListView.
+///
+internal static class ListViewHelpers
+{
+ ///
+ /// Opens for 2 seconds, then closes it automatically
+ /// via a .
+ ///
+ /// The to show (e.g. SavedTip).
+ ///
+ /// Optional action invoked immediately after opening the tip.
+ /// Used by SecureNotesListView to trigger the accessibility announcer.
+ ///
+ internal static void ShowSavedToast(TeachingTip tip, Action? extraAction = null)
+ {
+ tip.IsOpen = true;
+ extraAction?.Invoke();
+
+ var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
+ timer.Tick += (s, _) =>
+ {
+ tip.IsOpen = false;
+ ((DispatcherTimer)s!).Stop();
+ };
+ timer.Start();
+ }
+}
diff --git a/src/PassKey.Desktop/ViewModels/DashboardViewModel.cs b/src/PassKey.Desktop/ViewModels/DashboardViewModel.cs
index b2e48aa..aecde50 100644
--- a/src/PassKey.Desktop/ViewModels/DashboardViewModel.cs
+++ b/src/PassKey.Desktop/ViewModels/DashboardViewModel.cs
@@ -34,91 +34,143 @@ public partial class DashboardViewModel : ObservableObject
private string _deletedIdentity = "Identità eliminata";
private string _deletedNote = "Nota eliminata";
- // Greeting
+ // ── Greeting ─────────────────────────────────────────────────────────────
+
+ ///
+ /// Personalised greeting shown at the top of the dashboard.
+ /// Text is time-dependent: morning / afternoon / evening variant.
+ /// Updated each time runs.
+ ///
[ObservableProperty]
public partial string GreetingMessage { get; set; } = string.Empty;
- // Stat card totals
+ // ── Stat card totals ─────────────────────────────────────────────────────
+
+ /// Total count of password entries currently in the vault.
[ObservableProperty]
public partial int TotalPasswords { get; set; }
+ /// Total count of credit card entries currently in the vault.
[ObservableProperty]
public partial int TotalCards { get; set; }
+ /// Total count of identity profiles currently in the vault.
[ObservableProperty]
public partial int TotalIdentities { get; set; }
+ /// Total count of secure notes currently in the vault.
[ObservableProperty]
public partial int TotalNotes { get; set; }
- // Per-card weekly activity (4 types × 3 actions = 12 properties)
+ // ── Weekly activity counters (4 types × 3 actions = 12 properties) ───────
+
+ /// Number of password entries added in the past 7 days.
[ObservableProperty]
public partial int PasswordsAdded { get; set; }
+ /// Number of password entries deleted in the past 7 days.
[ObservableProperty]
public partial int PasswordsRemoved { get; set; }
+ /// Number of password entries edited in the past 7 days.
[ObservableProperty]
public partial int PasswordsModified { get; set; }
+ /// Number of credit card entries added in the past 7 days.
[ObservableProperty]
public partial int CardsAdded { get; set; }
+ /// Number of credit card entries deleted in the past 7 days.
[ObservableProperty]
public partial int CardsRemoved { get; set; }
+ /// Number of credit card entries edited in the past 7 days.
[ObservableProperty]
public partial int CardsModified { get; set; }
+ /// Number of identity profiles added in the past 7 days.
[ObservableProperty]
public partial int IdentitiesAdded { get; set; }
+ /// Number of identity profiles deleted in the past 7 days.
[ObservableProperty]
public partial int IdentitiesRemoved { get; set; }
+ /// Number of identity profiles edited in the past 7 days.
[ObservableProperty]
public partial int IdentitiesModified { get; set; }
+ /// Number of secure notes added in the past 7 days.
[ObservableProperty]
public partial int NotesAdded { get; set; }
+ /// Number of secure notes deleted in the past 7 days.
[ObservableProperty]
public partial int NotesRemoved { get; set; }
+ /// Number of secure notes edited in the past 7 days.
[ObservableProperty]
public partial int NotesModified { get; set; }
- // Password health
+ // ── Vault health ─────────────────────────────────────────────────────────
+
+ ///
+ /// Overall vault health score (0–100).
+ /// Computed from the ratio of strong vs. weak passwords in the vault.
+ ///
[ObservableProperty]
public partial int VaultHealthScore { get; set; }
+ /// Count of password entries rated Weak or VeryWeak by the strength analyser.
[ObservableProperty]
public partial int WeakPasswordCount { get; set; }
- // Expiring cards
+ // ── Expiring credit cards ─────────────────────────────────────────────────
+
+ /// Number of credit cards expiring within the next 60 days.
[ObservableProperty]
public partial int ExpiringCardsCount { get; set; }
+ /// when at least one card is expiring soon; drives the warning banner visibility.
[ObservableProperty]
public partial bool HasExpiringCards { get; set; }
- // Recent activity
+ // ── Recent activity ───────────────────────────────────────────────────────
+
+ /// Up to 15 most recent vault activity items, shown in the dashboard timeline.
public ObservableCollection RecentItems { get; } = [];
- // Empty state
+ // ── Empty state ───────────────────────────────────────────────────────────
+
+ ///
+ /// when the vault contains no entries of any type.
+ /// Drives the dashboard empty-state placeholder visibility.
+ ///
[ObservableProperty]
public partial bool IsVaultEmpty { get; set; }
- // Search
+ // ── Search ────────────────────────────────────────────────────────────────
+
+ ///
+ /// Current search query entered by the user in the dashboard search box.
+ /// Setting this property triggers a reactive search across all vault entry types.
+ ///
[ObservableProperty]
public partial string SearchQuery { get; set; } = string.Empty;
+ /// Flat list of search results across all vault sections, bound to the search results panel.
public ObservableCollection SearchResults { get; } = [];
+ /// when is non-empty; drives the results panel visibility.
[ObservableProperty]
public partial bool HasSearchResults { get; set; }
- // Navigation event: fired when user clicks a recent item or search result
+ // ── Navigation ────────────────────────────────────────────────────────────
+
+ ///
+ /// Fired when the user clicks a recent-activity item or a search result.
+ /// Parameters: vault section identifier (e.g. "Passwords") and entry .
+ ///
public event Action? NavigateToItemRequested;
public DashboardViewModel(
diff --git a/src/PassKey.Desktop/Views/CreditCardDetailView.xaml.cs b/src/PassKey.Desktop/Views/CreditCardDetailView.xaml.cs
index 78bcd43..7a20144 100644
--- a/src/PassKey.Desktop/Views/CreditCardDetailView.xaml.cs
+++ b/src/PassKey.Desktop/Views/CreditCardDetailView.xaml.cs
@@ -16,7 +16,7 @@ public sealed partial class CreditCardDetailView : UserControl
{
private CreditCardDetailViewModel? _viewModel;
private bool _updatingFromVm;
- private readonly Microsoft.Windows.ApplicationModel.Resources.ResourceLoader _res = new();
+ private readonly Microsoft.Windows.ApplicationModel.Resources.ResourceLoader _resourceLoader = new();
///
/// All 10 accent colors for the swatch selector.
@@ -100,8 +100,8 @@ public void SetViewModel(CreditCardDetailViewModel vm)
// Subtitle
PanelSubtitle.Text = isEdit
- ? _res.GetString("CardPanelSubtitleEdit")
- : _res.GetString("CardPanelSubtitleNew");
+ ? _resourceLoader.GetString("CardPanelSubtitleEdit")
+ : _resourceLoader.GetString("CardPanelSubtitleNew");
// Hook SecureInputBox events
CvvInput.PasswordChanged += OnCvvChanged;
@@ -265,7 +265,7 @@ private void UpdateCardTypeIndicator()
CardType.JCB => "JCB",
CardType.Maestro => "Maestro",
CardType.DinersClub => "Diners Club",
- _ => _res.GetString("CardTypeUnknown")
+ _ => _resourceLoader.GetString("CardTypeUnknown")
};
// Luhn validation
@@ -278,14 +278,14 @@ private void UpdateCardTypeIndicator()
{
LuhnIcon.Glyph = "\uE73E"; // checkmark
LuhnIcon.Foreground = (Brush)Application.Current.Resources["LuhnValidBrush"];
- LuhnLabel.Text = _res.GetString("LuhnValid");
+ LuhnLabel.Text = _resourceLoader.GetString("LuhnValid");
LuhnLabel.Foreground = (Brush)Application.Current.Resources["LuhnValidBrush"];
}
else
{
LuhnIcon.Glyph = "\uE711"; // dismiss
LuhnIcon.Foreground = (Brush)Application.Current.Resources["LuhnInvalidBrush"];
- LuhnLabel.Text = _res.GetString("LuhnInvalid");
+ LuhnLabel.Text = _resourceLoader.GetString("LuhnInvalid");
LuhnLabel.Foreground = (Brush)Application.Current.Resources["LuhnInvalidBrush"];
}
}
@@ -318,7 +318,7 @@ private void UpdateSavingState(bool saving)
{
SaveProgress.IsActive = saving;
SaveProgress.Visibility = saving ? Visibility.Visible : Visibility.Collapsed;
- SaveButtonText.Text = saving ? _res.GetString("SaveInProgress") : _res.GetString("ButtonSaveLabel/Text");
+ SaveButtonText.Text = saving ? _resourceLoader.GetString("SaveInProgress") : _resourceLoader.GetString("ButtonSaveLabel/Text");
SaveButton.IsEnabled = !saving;
}
diff --git a/src/PassKey.Desktop/Views/CreditCardsListView.xaml.cs b/src/PassKey.Desktop/Views/CreditCardsListView.xaml.cs
index 58aa62e..cecd707 100644
--- a/src/PassKey.Desktop/Views/CreditCardsListView.xaml.cs
+++ b/src/PassKey.Desktop/Views/CreditCardsListView.xaml.cs
@@ -6,6 +6,7 @@
using PassKey.Core.Models;
using PassKey.Core.Services;
using PassKey.Desktop.Controls;
+using PassKey.Desktop.Helpers;
using PassKey.Desktop.ViewModels;
namespace PassKey.Desktop.Views;
@@ -16,7 +17,7 @@ namespace PassKey.Desktop.Views;
public sealed partial class CreditCardsListView : UserControl
{
private CreditCardsListViewModel? _viewModel;
- private readonly ResourceLoader _res = new();
+ private readonly ResourceLoader _resourceLoader = new();
public CreditCardsListView()
{
@@ -29,8 +30,8 @@ public async void SetViewModel(CreditCardsListViewModel vm)
DataContext = vm;
// Apply localized empty-state strings (guarantees correct language on every OS locale).
- EmptyState.Title = _res.GetString("EmptyCardsTitle");
- EmptyState.Subtitle = _res.GetString("EmptyCardsSubtitle");
+ EmptyState.Title = _resourceLoader.GetString("EmptyCardsTitle");
+ EmptyState.Subtitle = _resourceLoader.GetString("EmptyCardsSubtitle");
vm.PropertyChanged += OnViewModelPropertyChanged;
vm.SaveCompleted += ShowSavedToast;
@@ -208,17 +209,7 @@ private void EditEntry_Click(object sender, RoutedEventArgs e)
// --- Toast ---
- public void ShowSavedToast()
- {
- SavedTip.IsOpen = true;
- var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
- timer.Tick += (s, _) =>
- {
- SavedTip.IsOpen = false;
- ((DispatcherTimer)s!).Stop();
- };
- timer.Start();
- }
+ public void ShowSavedToast() => ListViewHelpers.ShowSavedToast(SavedTip);
// Hover effects — show/hide action buttons
private void Row_PointerEntered(object sender, Microsoft.UI.Xaml.Input.PointerRoutedEventArgs e)
diff --git a/src/PassKey.Desktop/Views/DashboardView.xaml.cs b/src/PassKey.Desktop/Views/DashboardView.xaml.cs
index 663c8de..1249a7b 100644
--- a/src/PassKey.Desktop/Views/DashboardView.xaml.cs
+++ b/src/PassKey.Desktop/Views/DashboardView.xaml.cs
@@ -13,18 +13,18 @@ namespace PassKey.Desktop.Views;
public sealed partial class DashboardView : UserControl
{
private DashboardViewModel? _viewModel;
- private readonly ResourceLoader _res = new();
+ private readonly ResourceLoader _resourceLoader = new();
private DispatcherTimer? _searchTimer;
public DashboardView()
{
InitializeComponent();
- EmptyState.Title = _res.GetString("EmptyDashboardTitle");
- EmptyState.Subtitle = _res.GetString("EmptyDashboardSubtitle");
- EmptyState.PrimaryActionText = _res.GetString("AddPassword");
- EmptyState.SecondaryActionText = _res.GetString("ImportData");
+ EmptyState.Title = _resourceLoader.GetString("EmptyDashboardTitle");
+ EmptyState.Subtitle = _resourceLoader.GetString("EmptyDashboardSubtitle");
+ EmptyState.PrimaryActionText = _resourceLoader.GetString("AddPassword");
+ EmptyState.SecondaryActionText = _resourceLoader.GetString("ImportData");
- VaultOverviewTitle.Text = _res.GetString("DashVaultOverview");
+ VaultOverviewTitle.Text = _resourceLoader.GetString("DashVaultOverview");
}
public async void SetViewModel(DashboardViewModel vm)
@@ -36,20 +36,20 @@ public async void SetViewModel(DashboardViewModel vm)
// Pass localized resources to ViewModel
vm.SetGreetingResources(
- _res.GetString("GreetingMorning"),
- _res.GetString("GreetingAfternoon"),
- _res.GetString("GreetingEvening"));
+ _resourceLoader.GetString("GreetingMorning"),
+ _resourceLoader.GetString("GreetingAfternoon"),
+ _resourceLoader.GetString("GreetingEvening"));
vm.SetActionLabels(
- _res.GetString("ActionCreated"),
- _res.GetString("ActionModified"),
- _res.GetString("ActionDeleted"));
+ _resourceLoader.GetString("ActionCreated"),
+ _resourceLoader.GetString("ActionModified"),
+ _resourceLoader.GetString("ActionDeleted"));
vm.SetDeletedLabels(
- _res.GetString("DeletedPassword"),
- _res.GetString("DeletedCard"),
- _res.GetString("DeletedIdentity"),
- _res.GetString("DeletedNote"));
+ _resourceLoader.GetString("DeletedPassword"),
+ _resourceLoader.GetString("DeletedCard"),
+ _resourceLoader.GetString("DeletedIdentity"),
+ _resourceLoader.GetString("DeletedNote"));
// Wire empty state buttons via PrimaryActionCommand/SecondaryActionCommand
EmptyState.PrimaryActionCommand = new CommunityToolkit.Mvvm.Input.RelayCommand(
@@ -102,13 +102,13 @@ private void UpdateUI()
NotesCount.Text = _viewModel.TotalNotes.ToString();
// Stat card subtitles
- PasswordsSubtitle.Text = _res.GetString("DashSubtitlePasswords");
- CardsSubtitle.Text = _res.GetString("DashSubtitleCards");
- IdentitiesSubtitle.Text = _res.GetString("DashSubtitleIdentities");
- NotesSubtitle.Text = _res.GetString("DashSubtitleNotes");
+ PasswordsSubtitle.Text = _resourceLoader.GetString("DashSubtitlePasswords");
+ CardsSubtitle.Text = _resourceLoader.GetString("DashSubtitleCards");
+ IdentitiesSubtitle.Text = _resourceLoader.GetString("DashSubtitleIdentities");
+ NotesSubtitle.Text = _resourceLoader.GetString("DashSubtitleNotes");
// Per-card compact activity (3 indicators each)
- var noChangesLabel = _res.GetString("DashCardNoChanges");
+ var noChangesLabel = _resourceLoader.GetString("DashCardNoChanges");
UpdateCardActivity(_viewModel.PasswordsAdded, _viewModel.PasswordsRemoved, _viewModel.PasswordsModified,
PwActivityRow, PwNoChanges, PwAdded, PwRemoved, PwModified, noChangesLabel);
UpdateCardActivity(_viewModel.CardsAdded, _viewModel.CardsRemoved, _viewModel.CardsModified,
@@ -125,10 +125,10 @@ private void UpdateUI()
HealthRing.Value = _viewModel.VaultHealthScore;
HealthScoreText.Text = $"{_viewModel.VaultHealthScore}%";
HealthRing.Foreground = GetHealthBrush(_viewModel.VaultHealthScore);
- HealthTitle.Text = _res.GetString("DashHealthTitle");
+ HealthTitle.Text = _resourceLoader.GetString("DashHealthTitle");
HealthSubtitle.Text = _viewModel.WeakPasswordCount > 0
- ? string.Format(_res.GetString("DashHealthWeak"), _viewModel.WeakPasswordCount)
- : _res.GetString("DashHealthGood");
+ ? string.Format(_resourceLoader.GetString("DashHealthWeak"), _viewModel.WeakPasswordCount)
+ : _resourceLoader.GetString("DashHealthGood");
}
else
{
@@ -141,7 +141,7 @@ private void UpdateUI()
ExpiringCardsAlert.Visibility = Visibility.Visible;
ExpiringCardsAlert.IsOpen = true;
ExpiringCardsAlert.Message = string.Format(
- _res.GetString("DashExpiringCards"), _viewModel.ExpiringCardsCount);
+ _resourceLoader.GetString("DashExpiringCards"), _viewModel.ExpiringCardsCount);
}
else
{
diff --git a/src/PassKey.Desktop/Views/IdentitiesListView.xaml.cs b/src/PassKey.Desktop/Views/IdentitiesListView.xaml.cs
index 9eda370..3876d2e 100644
--- a/src/PassKey.Desktop/Views/IdentitiesListView.xaml.cs
+++ b/src/PassKey.Desktop/Views/IdentitiesListView.xaml.cs
@@ -7,6 +7,7 @@
using Microsoft.UI.Xaml.Media;
using Microsoft.Windows.ApplicationModel.Resources;
using PassKey.Core.Models;
+using PassKey.Desktop.Helpers;
using PassKey.Desktop.ViewModels;
namespace PassKey.Desktop.Views;
@@ -17,7 +18,7 @@ namespace PassKey.Desktop.Views;
public sealed partial class IdentitiesListView : UserControl
{
private IdentitiesListViewModel? _viewModel;
- private readonly ResourceLoader _res = new();
+ private readonly ResourceLoader _resourceLoader = new();
public IdentitiesListView()
{
@@ -33,8 +34,8 @@ public async void SetViewModel(IdentitiesListViewModel vm)
vm.SaveCompleted += ShowSavedToast;
// Apply localized empty-state strings (guarantees correct language on every OS locale).
- EmptyState.Title = _res.GetString("EmptyIdentitiesTitle");
- EmptyState.Subtitle = _res.GetString("EmptyIdentitiesSubtitle");
+ EmptyState.Title = _resourceLoader.GetString("EmptyIdentitiesTitle");
+ EmptyState.Subtitle = _resourceLoader.GetString("EmptyIdentitiesSubtitle");
await vm.LoadEntriesCommand.ExecuteAsync(null);
UpdateList();
UpdateEmptyState();
@@ -181,17 +182,7 @@ private void Card_PointerExited(object sender, Microsoft.UI.Xaml.Input.PointerRo
}
// Save confirmation toast
- public void ShowSavedToast()
- {
- SavedTip.IsOpen = true;
- var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
- timer.Tick += (s, _) =>
- {
- SavedTip.IsOpen = false;
- ((DispatcherTimer)s!).Stop();
- };
- timer.Start();
- }
+ public void ShowSavedToast() => ListViewHelpers.ShowSavedToast(SavedTip);
// ── Formatters ────────────────────────────────────────────────────────────
diff --git a/src/PassKey.Desktop/Views/IdentityDetailView.xaml.cs b/src/PassKey.Desktop/Views/IdentityDetailView.xaml.cs
index ac77527..4bc878d 100644
--- a/src/PassKey.Desktop/Views/IdentityDetailView.xaml.cs
+++ b/src/PassKey.Desktop/Views/IdentityDetailView.xaml.cs
@@ -13,7 +13,7 @@ public sealed partial class IdentityDetailView : UserControl
{
private IdentityDetailViewModel? _viewModel;
private bool _updatingFromVm;
- private readonly Microsoft.Windows.ApplicationModel.Resources.ResourceLoader _res = new();
+ private readonly Microsoft.Windows.ApplicationModel.Resources.ResourceLoader _resourceLoader = new();
public IdentityDetailView()
{
@@ -68,8 +68,8 @@ public void SetViewModel(IdentityDetailViewModel vm)
// Subtitle
PanelSubtitle.Text = isEdit
- ? _res.GetString("IdPanelSubtitleEdit")
- : _res.GetString("IdPanelSubtitleNew");
+ ? _resourceLoader.GetString("IdPanelSubtitleEdit")
+ : _resourceLoader.GetString("IdPanelSubtitleNew");
// Expand sections that have data in edit mode
if (!string.IsNullOrWhiteSpace(vm.Street) || !string.IsNullOrWhiteSpace(vm.City) ||
@@ -236,7 +236,7 @@ private void UpdateSavingState(bool saving)
{
SaveProgress.IsActive = saving;
SaveProgress.Visibility = saving ? Visibility.Visible : Visibility.Collapsed;
- SaveButtonText.Text = saving ? _res.GetString("SaveInProgress") : _res.GetString("ButtonSave");
+ SaveButtonText.Text = saving ? _resourceLoader.GetString("SaveInProgress") : _resourceLoader.GetString("ButtonSave");
SaveButton.IsEnabled = !saving;
}
diff --git a/src/PassKey.Desktop/Views/PasswordDetailView.xaml.cs b/src/PassKey.Desktop/Views/PasswordDetailView.xaml.cs
index 96d8cf2..7aac1e8 100644
--- a/src/PassKey.Desktop/Views/PasswordDetailView.xaml.cs
+++ b/src/PassKey.Desktop/Views/PasswordDetailView.xaml.cs
@@ -17,7 +17,7 @@ public sealed partial class PasswordDetailView : UserControl
{
private PasswordDetailViewModel? _viewModel;
private bool _updatingFromVm;
- private readonly ResourceLoader _res = new();
+ private readonly ResourceLoader _resourceLoader = new();
// 24 Segoe MDL2 Assets glyphs for the icon picker
private static readonly string[] IconGlyphs =
@@ -65,8 +65,8 @@ public void SetViewModel(PasswordDetailViewModel vm)
// Subtitle
PanelSubtitle.Text = isEdit
- ? _res.GetString("PwPanelSubtitleEdit")
- : _res.GetString("PwPanelSubtitleNew");
+ ? _resourceLoader.GetString("PwPanelSubtitleEdit")
+ : _resourceLoader.GetString("PwPanelSubtitleNew");
// Strength indicator
UpdateStrengthLabel();
@@ -219,11 +219,11 @@ private void UpdateStrengthLabel()
StrengthLabel.Visibility = Visibility.Visible;
StrengthLabel.Text = label switch
{
- "VeryWeak" => _res.GetString("StrengthVeryWeak"),
- "Weak" => _res.GetString("StrengthWeak"),
- "Medium" => _res.GetString("StrengthMedium"),
- "Strong" => _res.GetString("StrengthStrong"),
- "VeryStrong" => _res.GetString("StrengthVeryStrong"),
+ "VeryWeak" => _resourceLoader.GetString("StrengthVeryWeak"),
+ "Weak" => _resourceLoader.GetString("StrengthWeak"),
+ "Medium" => _resourceLoader.GetString("StrengthMedium"),
+ "Strong" => _resourceLoader.GetString("StrengthStrong"),
+ "VeryStrong" => _resourceLoader.GetString("StrengthVeryStrong"),
_ => label
};
StrengthLabel.Foreground = GetStrengthBrush(_viewModel.PasswordStrengthScore);
diff --git a/src/PassKey.Desktop/Views/PasswordsListView.xaml.cs b/src/PassKey.Desktop/Views/PasswordsListView.xaml.cs
index e3c31d7..cc25a6c 100644
--- a/src/PassKey.Desktop/Views/PasswordsListView.xaml.cs
+++ b/src/PassKey.Desktop/Views/PasswordsListView.xaml.cs
@@ -5,6 +5,7 @@
using Microsoft.UI.Xaml.Media.Imaging;
using Microsoft.Windows.ApplicationModel.Resources;
using PassKey.Core.Models;
+using PassKey.Desktop.Helpers;
using PassKey.Desktop.ViewModels;
using Windows.Storage.Streams;
@@ -17,7 +18,7 @@ namespace PassKey.Desktop.Views;
public sealed partial class PasswordsListView : UserControl
{
private PasswordsListViewModel? _viewModel;
- private readonly ResourceLoader _res = new();
+ private readonly ResourceLoader _resourceLoader = new();
public PasswordsListView()
{
@@ -30,8 +31,8 @@ public async void SetViewModel(PasswordsListViewModel vm)
DataContext = vm;
// Apply localized empty-state strings (guarantees correct language on every OS locale).
- EmptyState.Title = _res.GetString("EmptyPasswordsTitle");
- EmptyState.Subtitle = _res.GetString("EmptyPasswordsSubtitle");
+ EmptyState.Title = _resourceLoader.GetString("EmptyPasswordsTitle");
+ EmptyState.Subtitle = _resourceLoader.GetString("EmptyPasswordsSubtitle");
vm.PropertyChanged += OnViewModelPropertyChanged;
vm.SaveCompleted += ShowSavedToast;
@@ -99,19 +100,9 @@ private void UpdateDetailContent()
}
}
- // --- Toast (Step F) ---
+ // --- Toast ---
- public void ShowSavedToast()
- {
- SavedTip.IsOpen = true;
- var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
- timer.Tick += (s, _) =>
- {
- SavedTip.IsOpen = false;
- ((DispatcherTimer)s!).Stop();
- };
- timer.Start();
- }
+ public void ShowSavedToast() => ListViewHelpers.ShowSavedToast(SavedTip);
// --- Search ---
diff --git a/src/PassKey.Desktop/Views/SecureNotesListView.xaml.cs b/src/PassKey.Desktop/Views/SecureNotesListView.xaml.cs
index 3feca18..a0c41a8 100644
--- a/src/PassKey.Desktop/Views/SecureNotesListView.xaml.cs
+++ b/src/PassKey.Desktop/Views/SecureNotesListView.xaml.cs
@@ -7,6 +7,7 @@
using Microsoft.Windows.ApplicationModel.Resources;
using PassKey.Core.Constants;
using PassKey.Core.Models;
+using PassKey.Desktop.Helpers;
using PassKey.Desktop.ViewModels;
namespace PassKey.Desktop.Views;
@@ -19,7 +20,7 @@ namespace PassKey.Desktop.Views;
public sealed partial class SecureNotesListView : UserControl
{
private SecureNotesListViewModel? _viewModel;
- private readonly ResourceLoader _res = new();
+ private readonly ResourceLoader _resourceLoader = new();
public SecureNotesListView()
{
@@ -37,10 +38,10 @@ public async void SetViewModel(SecureNotesListViewModel vm)
BuildCategoryFilter();
// Apply localized empty-state strings (guarantees correct language on every OS locale).
- EmptyState.Title = _res.GetString("EmptyNotesTitle");
- EmptyState.Subtitle = _res.GetString("EmptyNotesSubtitle");
- FilteredEmptyState.Title = _res.GetString("EmptyFilteredTitle");
- FilteredEmptyState.Subtitle = _res.GetString("EmptyFilteredSubtitle");
+ EmptyState.Title = _resourceLoader.GetString("EmptyNotesTitle");
+ EmptyState.Subtitle = _resourceLoader.GetString("EmptyNotesSubtitle");
+ FilteredEmptyState.Title = _resourceLoader.GetString("EmptyFilteredTitle");
+ FilteredEmptyState.Subtitle = _resourceLoader.GetString("EmptyFilteredSubtitle");
await vm.LoadEntriesCommand.ExecuteAsync(null);
UpdateList();
@@ -310,18 +311,7 @@ private void NotesList_ContainerContentChanging(ListViewBase sender,
// --- Toast conferma salvataggio ---
- public void ShowSavedToast()
- {
- SavedTip.IsOpen = true;
- Announce("Nota salvata.");
- var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
- timer.Tick += (s, _) =>
- {
- SavedTip.IsOpen = false;
- ((DispatcherTimer)s!).Stop();
- };
- timer.Start();
- }
+ public void ShowSavedToast() => ListViewHelpers.ShowSavedToast(SavedTip, () => Announce("Nota salvata."));
// --- Helpers ---
diff --git a/src/PassKey.Desktop/Views/SettingsView.xaml.cs b/src/PassKey.Desktop/Views/SettingsView.xaml.cs
index d6c0827..014b759 100644
--- a/src/PassKey.Desktop/Views/SettingsView.xaml.cs
+++ b/src/PassKey.Desktop/Views/SettingsView.xaml.cs
@@ -13,7 +13,7 @@ public sealed partial class SettingsView : UserControl
{
private SettingsViewModel? _viewModel;
private bool _updatingFromVm;
- private readonly ResourceLoader _res = new();
+ private readonly ResourceLoader _resourceLoader = new();
private IDialogQueueService _dialogQueue = null!;
/// Raised when the user clicks "Guida e scorciatoie" to navigate to HelpView.
@@ -143,21 +143,21 @@ private async void ChangePwButton_Click(object sender, RoutedEventArgs e)
var currentPwBox = new SecureInputBox
{
- PlaceholderText = _res.GetString("ChangePwCurrentPlaceholder"),
+ PlaceholderText = _resourceLoader.GetString("ChangePwCurrentPlaceholder"),
ShowRevealButton = Visibility.Visible,
Width = 320
};
var newPwBox = new SecureInputBox
{
- PlaceholderText = _res.GetString("ChangePwNewPlaceholder"),
+ PlaceholderText = _resourceLoader.GetString("ChangePwNewPlaceholder"),
ShowRevealButton = Visibility.Visible,
Width = 320
};
var confirmPwBox = new SecureInputBox
{
- PlaceholderText = _res.GetString("ChangePwConfirmPlaceholder"),
+ PlaceholderText = _resourceLoader.GetString("ChangePwConfirmPlaceholder"),
ShowRevealButton = Visibility.Visible,
Width = 320
};
@@ -178,10 +178,10 @@ private async void ChangePwButton_Click(object sender, RoutedEventArgs e)
var dialog = new ContentDialog
{
- Title = _res.GetString("ChangePwDialogTitle"),
+ Title = _resourceLoader.GetString("ChangePwDialogTitle"),
Content = panel,
- PrimaryButtonText = _res.GetString("ChangePwDialogPrimary"),
- CloseButtonText = _res.GetString("ChangePwDialogClose"),
+ PrimaryButtonText = _resourceLoader.GetString("ChangePwDialogPrimary"),
+ CloseButtonText = _resourceLoader.GetString("ChangePwDialogClose"),
DefaultButton = ContentDialogButton.Close,
XamlRoot = XamlRoot
};
@@ -196,13 +196,13 @@ private async void ChangePwButton_Click(object sender, RoutedEventArgs e)
string? error = null;
if (string.IsNullOrEmpty(currentPw))
- error = _res.GetString("ChangePwErrEmpty");
+ error = _resourceLoader.GetString("ChangePwErrEmpty");
else if (newPw.Length < 8)
- error = _res.GetString("ChangePwErrShort");
+ error = _resourceLoader.GetString("ChangePwErrShort");
else if (newPw != confirmPw)
- error = _res.GetString("ChangePwErrMismatch");
+ error = _resourceLoader.GetString("ChangePwErrMismatch");
else if (newPw == currentPw)
- error = _res.GetString("ChangePwErrSame");
+ error = _resourceLoader.GetString("ChangePwErrSame");
if (error is not null)
{
@@ -226,14 +226,14 @@ private async void ChangePwButton_Click(object sender, RoutedEventArgs e)
if (success)
{
await ShowInfoDialogAsync(
- _res.GetString("ChangePwSuccessTitle"),
- _res.GetString("ChangePwSuccessMessage"));
+ _resourceLoader.GetString("ChangePwSuccessTitle"),
+ _resourceLoader.GetString("ChangePwSuccessMessage"));
}
else
{
await ShowInfoDialogAsync(
- _res.GetString("ChangePwErrorTitle"),
- _res.GetString("ChangePwErrorMessage"));
+ _resourceLoader.GetString("ChangePwErrorTitle"),
+ _resourceLoader.GetString("ChangePwErrorMessage"));
}
}
finally
@@ -283,11 +283,11 @@ private async void CheckUpdateButton_Click(object sender, RoutedEventArgs e)
private string FormatLastCheckTime(DateTime? utc)
{
- if (!utc.HasValue) return _res.GetString("UpdateNeverChecked");
+ if (!utc.HasValue) return _resourceLoader.GetString("UpdateNeverChecked");
var diff = DateTime.Now - utc.Value.ToLocalTime();
- if (diff.TotalMinutes < 1) return _res.GetString("UpdateJustChecked");
- if (diff.TotalHours < 1) return string.Format(_res.GetString("UpdateCheckedMinutesAgo"), (int)diff.TotalMinutes);
- if (diff.TotalDays < 1) return string.Format(_res.GetString("UpdateCheckedHoursAgo"), (int)diff.TotalHours);
+ if (diff.TotalMinutes < 1) return _resourceLoader.GetString("UpdateJustChecked");
+ if (diff.TotalHours < 1) return string.Format(_resourceLoader.GetString("UpdateCheckedMinutesAgo"), (int)diff.TotalMinutes);
+ if (diff.TotalDays < 1) return string.Format(_resourceLoader.GetString("UpdateCheckedHoursAgo"), (int)diff.TotalHours);
return utc.Value.ToLocalTime().ToString("d MMM yyyy, HH:mm");
}
@@ -321,13 +321,13 @@ private async void ImportButton_Click(object sender, RoutedEventArgs e)
{
var pwBox = new SecureInputBox
{
- PlaceholderText = _res.GetString("BackupPwPlaceholder"),
+ PlaceholderText = _resourceLoader.GetString("BackupPwPlaceholder"),
ShowRevealButton = Visibility.Visible,
Width = 320
};
var confirmBox = new SecureInputBox
{
- PlaceholderText = _res.GetString("BackupPwConfirmPlaceholder"),
+ PlaceholderText = _resourceLoader.GetString("BackupPwConfirmPlaceholder"),
ShowRevealButton = Visibility.Visible,
Width = 320
};
@@ -341,7 +341,7 @@ private async void ImportButton_Click(object sender, RoutedEventArgs e)
var descText = new TextBlock
{
- Text = _res.GetString("BackupPwDialogDesc"),
+ Text = _resourceLoader.GetString("BackupPwDialogDesc"),
TextWrapping = TextWrapping.Wrap,
Margin = new Thickness(0, 0, 0, 12)
};
@@ -354,10 +354,10 @@ private async void ImportButton_Click(object sender, RoutedEventArgs e)
var dialog = new ContentDialog
{
- Title = _res.GetString("BackupPwDialogTitle"),
+ Title = _resourceLoader.GetString("BackupPwDialogTitle"),
Content = panel,
PrimaryButtonText = "OK",
- CloseButtonText = _res.GetString("RestoreWarningCancel"),
+ CloseButtonText = _resourceLoader.GetString("RestoreWarningCancel"),
DefaultButton = ContentDialogButton.Primary,
XamlRoot = XamlRoot
};
@@ -366,11 +366,11 @@ private async void ImportButton_Click(object sender, RoutedEventArgs e)
{
string? error = null;
if (string.IsNullOrEmpty(pwBox.Password))
- error = _res.GetString("BackupPwErrEmpty");
+ error = _resourceLoader.GetString("BackupPwErrEmpty");
else if (pwBox.Password.Length < 8)
- error = _res.GetString("BackupPwErrShort");
+ error = _resourceLoader.GetString("BackupPwErrShort");
else if (pwBox.Password != confirmBox.Password)
- error = _res.GetString("BackupPwErrMismatch");
+ error = _resourceLoader.GetString("BackupPwErrMismatch");
if (error is not null)
{
@@ -390,10 +390,10 @@ private async Task OnRestoreWarningRequested()
{
var dialog = new ContentDialog
{
- Title = _res.GetString("RestoreWarningTitle"),
- Content = _res.GetString("RestoreWarningMessage"),
- PrimaryButtonText = _res.GetString("RestoreWarningConfirm"),
- CloseButtonText = _res.GetString("RestoreWarningCancel"),
+ Title = _resourceLoader.GetString("RestoreWarningTitle"),
+ Content = _resourceLoader.GetString("RestoreWarningMessage"),
+ PrimaryButtonText = _resourceLoader.GetString("RestoreWarningConfirm"),
+ CloseButtonText = _resourceLoader.GetString("RestoreWarningCancel"),
DefaultButton = ContentDialogButton.Close,
XamlRoot = XamlRoot
};
@@ -405,17 +405,17 @@ private async Task OnRestoreWarningRequested()
{
var pwBox = new SecureInputBox
{
- PlaceholderText = _res.GetString("RestorePwPlaceholder"),
+ PlaceholderText = _resourceLoader.GetString("RestorePwPlaceholder"),
ShowRevealButton = Visibility.Visible,
Width = 320
};
var dialog = new ContentDialog
{
- Title = _res.GetString("RestorePwDialogTitle"),
+ Title = _resourceLoader.GetString("RestorePwDialogTitle"),
Content = pwBox,
PrimaryButtonText = "OK",
- CloseButtonText = _res.GetString("RestoreWarningCancel"),
+ CloseButtonText = _resourceLoader.GetString("RestoreWarningCancel"),
DefaultButton = ContentDialogButton.Primary,
XamlRoot = XamlRoot
};
@@ -429,18 +429,18 @@ private async Task OnRestoreWarningRequested()
private async Task<(ImportFormat format, bool confirmed)> OnImportFormatRequested()
{
var combo = new ComboBox { Width = 320 };
- combo.Items.Add(new ComboBoxItem { Content = _res.GetString("ImportFormatCsv"), Tag = ImportFormat.Csv });
- combo.Items.Add(new ComboBoxItem { Content = _res.GetString("ImportFormatKdbx"), Tag = ImportFormat.Kdbx });
- combo.Items.Add(new ComboBoxItem { Content = _res.GetString("ImportFormatOnePux"), Tag = ImportFormat.OnePux });
- combo.Items.Add(new ComboBoxItem { Content = _res.GetString("ImportFormatBitwarden"), Tag = ImportFormat.Bitwarden });
+ combo.Items.Add(new ComboBoxItem { Content = _resourceLoader.GetString("ImportFormatCsv"), Tag = ImportFormat.Csv });
+ combo.Items.Add(new ComboBoxItem { Content = _resourceLoader.GetString("ImportFormatKdbx"), Tag = ImportFormat.Kdbx });
+ combo.Items.Add(new ComboBoxItem { Content = _resourceLoader.GetString("ImportFormatOnePux"), Tag = ImportFormat.OnePux });
+ combo.Items.Add(new ComboBoxItem { Content = _resourceLoader.GetString("ImportFormatBitwarden"), Tag = ImportFormat.Bitwarden });
combo.SelectedIndex = 0;
var dialog = new ContentDialog
{
- Title = _res.GetString("ImportFormatDialogTitle"),
+ Title = _resourceLoader.GetString("ImportFormatDialogTitle"),
Content = combo,
PrimaryButtonText = "OK",
- CloseButtonText = _res.GetString("RestoreWarningCancel"),
+ CloseButtonText = _resourceLoader.GetString("RestoreWarningCancel"),
DefaultButton = ContentDialogButton.Primary,
XamlRoot = XamlRoot
};
@@ -458,17 +458,17 @@ private async Task OnRestoreWarningRequested()
{
var pwBox = new SecureInputBox
{
- PlaceholderText = _res.GetString("ImportKdbxPwPlaceholder"),
+ PlaceholderText = _resourceLoader.GetString("ImportKdbxPwPlaceholder"),
ShowRevealButton = Visibility.Visible,
Width = 320
};
var dialog = new ContentDialog
{
- Title = _res.GetString("ImportKdbxPwTitle"),
+ Title = _resourceLoader.GetString("ImportKdbxPwTitle"),
Content = pwBox,
PrimaryButtonText = "OK",
- CloseButtonText = _res.GetString("RestoreWarningCancel"),
+ CloseButtonText = _resourceLoader.GetString("RestoreWarningCancel"),
DefaultButton = ContentDialogButton.Primary,
XamlRoot = XamlRoot
};
@@ -488,15 +488,15 @@ private async Task OnRestoreWarningRequested()
Margin = new Thickness(0, 0, 0, 16)
};
var lines = new System.Text.StringBuilder();
- if (pwCount > 0) lines.AppendLine(string.Format(_res.GetString("ImportSummaryPasswords"), pwCount));
- if (cardCount > 0) lines.AppendLine(string.Format(_res.GetString("ImportSummaryCards"), cardCount));
- if (idCount > 0) lines.AppendLine(string.Format(_res.GetString("ImportSummaryIdentities"), idCount));
- if (noteCount > 0) lines.AppendLine(string.Format(_res.GetString("ImportSummaryNotes"), noteCount));
+ if (pwCount > 0) lines.AppendLine(string.Format(_resourceLoader.GetString("ImportSummaryPasswords"), pwCount));
+ if (cardCount > 0) lines.AppendLine(string.Format(_resourceLoader.GetString("ImportSummaryCards"), cardCount));
+ if (idCount > 0) lines.AppendLine(string.Format(_resourceLoader.GetString("ImportSummaryIdentities"), idCount));
+ if (noteCount > 0) lines.AppendLine(string.Format(_resourceLoader.GetString("ImportSummaryNotes"), noteCount));
summaryText.Text = lines.ToString().TrimEnd();
- var skipRadio = new RadioButton { Content = _res.GetString("ImportMergeSkip"), IsChecked = true };
- var overwriteRadio = new RadioButton { Content = _res.GetString("ImportMergeOverwrite") };
- var keepBothRadio = new RadioButton { Content = _res.GetString("ImportMergeKeepBoth") };
+ var skipRadio = new RadioButton { Content = _resourceLoader.GetString("ImportMergeSkip"), IsChecked = true };
+ var overwriteRadio = new RadioButton { Content = _resourceLoader.GetString("ImportMergeOverwrite") };
+ var keepBothRadio = new RadioButton { Content = _resourceLoader.GetString("ImportMergeKeepBoth") };
var panel = new StackPanel { Spacing = 8 };
panel.Children.Add(summaryText);
@@ -506,10 +506,10 @@ private async Task OnRestoreWarningRequested()
var dialog = new ContentDialog
{
- Title = _res.GetString("ImportMergeTitle"),
+ Title = _resourceLoader.GetString("ImportMergeTitle"),
Content = panel,
PrimaryButtonText = "OK",
- CloseButtonText = _res.GetString("RestoreWarningCancel"),
+ CloseButtonText = _resourceLoader.GetString("RestoreWarningCancel"),
DefaultButton = ContentDialogButton.Primary,
XamlRoot = XamlRoot
};
@@ -529,37 +529,37 @@ private async Task OnRestoreWarningRequested()
private async Task OnImportCompleted(ImportResult result)
{
var lines = new System.Text.StringBuilder();
- if (result.PasswordsImported > 0) lines.AppendLine(string.Format(_res.GetString("ImportSummaryPasswords"), result.PasswordsImported));
- if (result.CardsImported > 0) lines.AppendLine(string.Format(_res.GetString("ImportSummaryCards"), result.CardsImported));
- if (result.IdentitiesImported > 0) lines.AppendLine(string.Format(_res.GetString("ImportSummaryIdentities"), result.IdentitiesImported));
- if (result.NotesImported > 0) lines.AppendLine(string.Format(_res.GetString("ImportSummaryNotes"), result.NotesImported));
- if (result.Skipped > 0) lines.AppendLine(string.Format(_res.GetString("ImportSummarySkipped"), result.Skipped));
+ if (result.PasswordsImported > 0) lines.AppendLine(string.Format(_resourceLoader.GetString("ImportSummaryPasswords"), result.PasswordsImported));
+ if (result.CardsImported > 0) lines.AppendLine(string.Format(_resourceLoader.GetString("ImportSummaryCards"), result.CardsImported));
+ if (result.IdentitiesImported > 0) lines.AppendLine(string.Format(_resourceLoader.GetString("ImportSummaryIdentities"), result.IdentitiesImported));
+ if (result.NotesImported > 0) lines.AppendLine(string.Format(_resourceLoader.GetString("ImportSummaryNotes"), result.NotesImported));
+ if (result.Skipped > 0) lines.AppendLine(string.Format(_resourceLoader.GetString("ImportSummarySkipped"), result.Skipped));
- await ShowInfoDialogAsync(_res.GetString("ImportSummaryTitle"), lines.ToString().TrimEnd());
+ await ShowInfoDialogAsync(_resourceLoader.GetString("ImportSummaryTitle"), lines.ToString().TrimEnd());
}
private async Task OnBackupCompleted(string path)
{
await ShowInfoDialogAsync(
- _res.GetString("BackupSuccessTitle"),
- _res.GetString("BackupSuccessMessage"));
+ _resourceLoader.GetString("BackupSuccessTitle"),
+ _resourceLoader.GetString("BackupSuccessMessage"));
}
private async Task OnRestoreCompleted()
{
await ShowInfoDialogAsync(
- _res.GetString("RestoreSuccessTitle"),
- _res.GetString("RestoreSuccessMessage"));
+ _resourceLoader.GetString("RestoreSuccessTitle"),
+ _resourceLoader.GetString("RestoreSuccessMessage"));
}
private async Task OnOperationError(string errorCode)
{
var message = errorCode switch
{
- "WRONG_PASSWORD" => _res.GetString("RestoreErrorWrongPw"),
- "INVALID_FILE" => _res.GetString("RestoreErrorInvalid"),
+ "WRONG_PASSWORD" => _resourceLoader.GetString("RestoreErrorWrongPw"),
+ "INVALID_FILE" => _resourceLoader.GetString("RestoreErrorInvalid"),
_ => errorCode
};
- await ShowInfoDialogAsync(_res.GetString("ImportErrorTitle"), message);
+ await ShowInfoDialogAsync(_resourceLoader.GetString("ImportErrorTitle"), message);
}
}