Release v2.0.0 — Cluster 5 UX, full localization, TOTP/HIBP polish & fixes#47
Merged
Conversation
Cluster 5 (T5.1–T5.19) ships the second wave of UX improvements for PassKey 2.0
plus 5 rounds of T5.GATE collaudo fixes on top.
Headline additions
- T5.1–T5.2: IToastService/ToastService — serial queue, bottom-right InfoBar,
auto-dismiss 3s/5s/manual, inline action button. Migrated Save/Delete/Copy
toasts across the 4 list VMs; removed the legacy SavedTip TeachingTip and
ListViewHelpers.cs.
- T5.5: IAutoLockService/AutoLockService — 1s tick on UI thread, Win32
GetLastInputInfo, lock-at-expiry, 60s/30s countdown toast with "Stay active".
- T5.10: ActivityLogViewModel + ActivityLogView ("Cronologia") + CSV export.
- T5.18: WelcomeView third option "Restore from backup".
- T5.19: backup filename with date PassKey_Backup_yyyyMMdd.pkbak.
- T5.6: inline validation (red border + "Required field") across the 4 Detail
ViewModels; per-field IsXxxEmpty initialised on ResetFieldsForNew.
- T5.8: EmptyStateControl enriched (illustration + per-list custom copy + actions).
- T5.4: "forgot password" flow in LoginView — zero-knowledge dialog + restore
backup / new vault paths. Added IVaultStateService.InitializeWithVaultAsync.
- T5.17: "Empty vault" in Impostazioni → Sicurezza (double confirm + master pwd).
Polish, accessibility, settings
- T5.7: hover effect on credit card (final form theme-aware accent — see GATE r4).
- T5.11: AutomationProperties.LiveSetting="Polite" on greeting/stat/InfoBar.
- T5.12: SettingsView reorganised flat (SettingsCard + section headers).
- T5.13: browser extension onboarding dialog.
- T5.14: localisation pass — 30+ resw keys × 6 languages.
- T5.15: quick-delete icon on list rows.
- T5.16: Audit Vault — threshold alignment with Dashboard.
T5.GATE collaudo (5 rounds, all fixes in this commit)
- Hotfix post-installer: COMException 0x80073B17 in IdentityDetailView /
SecureNoteDetailView when saving — bare ResourceLoader.GetString("ButtonSave")
converted to slash notation ("ButtonSave/Text") to match the .resw key renamed
by bug 9c.
- Round 1 (7 fixes): Ctrl+H help shortcut; search-popup orphan defer via
DispatcherQueue; language-restart single-instance race via --restart flag;
hover card border; fade-in card via ItemsRepeater; Activity Log back button;
"Sblocco/Creazione in corso" localised; Identity .resw key rename +
SearchIdentities.PlaceholderText + orphan x:Uid removal.
- Round 2: section-switch freeze (VM state survives view recreation in ShellView
— UpdateDetailPanel/UpdateDetailContent now called explicitly in SetViewModel
of all 4 list views, plus unsubscribe-before-subscribe); Ctrl+? reverted to
Ctrl+H (OEM-2 key not accessible on Italian layout); Identity localisation
gaps (AddIdentity → AddIdentity.Text; panel titles PwPanelTitle*,
CardPanelTitle*, IdPanelTitle*, NotePanelTitle* — new resw keys ×6 languages,
bypass vm.PanelTitle in detail views).
- Round 3: fade-in card switched to Loaded-deferred Storyboard pattern
(ElementPrepared fires before the element is in the visual tree).
- Round 4: hover border theme-aware — lighten card accent on dark theme, darken
on light theme (±90 per RGB channel, clamp).
- Round 5: PAN masked in list view (security) — new CreditCardEntry
.MaskedCardNumber computed property mirroring ExpiryFormatted pattern.
.gitignore: + .claude/ (claude-code workspace artefacts, per-developer) +
pm-export/ (password-manager test exports — real plaintext credentials).
Stats
- 70 files changed (61 modified, 1 deleted, 8 new).
- Build: 0 errors / 0 warnings (dotnet build -p:Platform=x64).
- Installer end-to-end verified through 5 collaudo rounds.
Follow-up items deferred post-GATE (tracked in piano-revisione-correzione-
miglioramento.md): FU1 email format validation; FU2 Ctrl+N stub handler;
FU3 unsupported/encrypted import warnings (Bitwarden + KeePass); FU4 Bitwarden
importer data loss (passport/license/ssn); FU5 IdentityEntry extension + i18n;
FU6 CsvImporter robustness; FU7 OnePuxImporter crash on email-as-object +
locale-independent matching; FU8 Activity Log scroll position. PR
feat/2.0/main → main scheduled after FU closure.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…pages
ShellView.NewItem_Invoked was a stub (args.Handled = true with no action) even
though Ctrl+N is advertised in tooltips ("Nuova carta (Ctrl+N)") and in HelpView.
- Added public InvokeAddNew() to the four list views (Passwords, Cards,
Identities, SecureNotes); each delegates to its VM's AddNewCommand.
- AddButton_Click now delegates to InvokeAddNew() to avoid duplication.
- ShellView.NewItem_Invoked dispatches on the current ShellContent.Content and
routes the shortcut to the active list page. Non-list pages (Dashboard,
Generator, Verifier, Settings, Help, Activity Log) are an intentional no-op.
Post-T5.GATE follow-up FU2. Build 0/0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Identity email field accepted obviously invalid input (mailtest.com, mailtest, mail@test., mail@testcom) with no feedback. Added a lenient, inline, NON-blocking warning — saving stays allowed because email is optional. - IdentityDetailViewModel: new IsEmailFormatSuspect observable property, computed in OnEmailChanged (true only when something is typed and it doesn't look like an email). Does NOT touch CanSave. Helper IsPlausibleEmail does a lenient check (single '@' not first/last, domain dot not first/last) — not a strict RFC 5322 validator. Reset to false in ResetFieldsForNew. - IdentityDetailView: inline hint below the Email field using SystemFillColorCautionBrush (amber, not the red error colour), bound to IsEmailFormatSuspect via BoolToVisibility. - 6× .resw: FieldEmailFormatWarning.Text (555 keys aligned across languages). Post-T5.GATE follow-up FU1. Build 0/0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d-trip Returning from the activity-log viewer to Settings dropped the user at the top of the page instead of where they had clicked "Cronologia attività" (near the bottom, in the Info section). - SettingsView.xaml: named the root ScrollViewer (RootScroller). - SettingsView: GetScrollOffset() reads the current vertical offset; RestoreScrollOffset(offset) re-applies it via ChangeView, deferred through the dispatcher (and Loaded when needed) because a freshly-created view hasn't completed layout yet and an immediate ChangeView would clamp to zero. - ShellView: _settingsScrollOffset field (the Settings page is recreated on every navigation, so the offset can't live on the view). OnSettingsNavigateToActivityLog captures it before leaving; OnActivityLogBackRequested restores it on the new SettingsView. The double NavigateToSettings (direct + via SelectionChanged) is a no-op the second time since CurrentPage is an ObservableProperty re-assigned the same VM instance, so SetVm runs once. Post-T5.GATE follow-up FU8. Build 0/0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Verified against real exports (Firefox, KeePass) during T5.GATE testing.
(a) Title fallback to URL host: Firefox exports have no title/name column and
identify logins by URL only, so entries imported anonymously. When the title
is missing/empty the importer now derives it from the URL host
(https://accounts.google.com/ -> accounts.google.com). Applied after the
skip-empty check so the skip still judges raw fields.
(b) Header alias coverage: new NormalizeHeader lowercases, trims, treats
underscores as spaces and collapses whitespace, so "login_name", "Login Name"
and "login name" all match one alias. Added KeePass aliases: "account" -> Title,
"login name" -> Username, "web site" -> Url. KeePass CSV
("Account","Login Name","Web Site","Comments") now imports complete instead of
nearly empty.
Semantic fix: "login_name" previously mapped to Title; "Login Name" is KeePass's
username field, so it now maps to Username (no existing test covered the old
behaviour).
Tests: 216/216 (+4 FU6: Firefox host fallback, KeePass spaced headers,
titleless-no-url, alongside the 10 existing).
Post-T5.GATE follow-up FU6.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tings page Repeated backup/restore/import operations made dialogs (master-password prompt, import-format chooser, merge strategy) and the file picker appear once, then twice, then three times, and so on. Root cause: SettingsView.SetViewModel subscribed 12 VM events (PropertyChanged, ThemeChangeRequested, Backup/Restore/Import password & format & merge prompts, completion and error callbacks) without ever detaching them. SettingsViewModel is a persistent singleton in ShellViewModel while SettingsView is recreated on every navigation, so each return to the page stacked another 12 handlers on the same VM. When the VM raised an event, every accumulated handler fired — N dialogs, and N runs of the import flow that opens the file picker right after those events. Fix: extracted SubscribeVmEvents/UnsubscribeVmEvents; SetViewModel does a defensive unsubscribe, subscribes, and registers Unloaded += OnUnloaded; OnUnloaded detaches all 12 events when the view is unloaded (navigated away). The persistent VM no longer retains handlers from discarded views. The defensive '-=' alone was insufficient (dead views' handlers are different instances) — the Unloaded detach is the fix. Verified Settings is the only persistent view subscribing dialog-raising VM events; the four list views share the same anti-pattern but only on PropertyChanged with idempotent effects (no visible symptom) — tracked as FU10. Post-T5.GATE follow-up FU9. Build 0/0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…dent mapping
Verified on a real 1Password .1pux export during T5.GATE testing.
(a) [critical] Email-as-object crash. OnePuxFieldValue.Email is string?, but current
1Password exports store the email as an object
{ "email_address": "...", "provider": null }. System.Text.Json couldn't convert
the object to a string and threw, aborting the ENTIRE import (every recent export
carries this in its default "Starter Kit" identity, so 1PUX import was broken out
of the box). Added OnePuxEmailConverter that tolerates both the legacy string and
the object form. MapItem is now wrapped in try/catch so one malformed item can't
abort the whole import (defence-in-depth).
(b) Locale-independent mapping. MapToIdentity/MapToCreditCard matched on the localized
field title ("first name", "cvv"), so a non-English export (e.g. Italian "Nome",
"Titolare") wasn't mapped. Added Id to OnePuxSectionField and match on the stable,
language-independent id (firstname, lastname, email, ccnum, cvv, cardholder, …) with
a title fallback for older exports and existing tests.
Tests: 219/219 (+3 FU7: email-as-object reproduces the real crash, identity-via-id,
card-via-id). AOT publish clean -> the JsonConverter is source-gen compatible.
Post-T5.GATE follow-up FU7.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…X refinements
Robustness (verified on real Bitwarden/KeePass files):
- New ImportFileException whose Message is a ready-to-display, user-facing string
(the existing ImportDataAsync try/catch surfaces it directly).
- Bitwarden encrypted export: BitwardenImporter detects "encrypted": true and throws
a clear message instead of silently importing an empty vault.
- Bitwarden ZIP ("with attachments"): ImportOrchestrator detects the ZIP magic bytes,
extracts data.json and imports it as Bitwarden JSON (ignoring attachments/). The
Bitwarden picker now accepts .json and .zip.
- KeePass 1.x (.kdb): detected by its signature (5th byte 0x65 vs KDBX 0x67) -> a
dedicated "convert to .kdbx" message. The KeePass picker now also accepts .kdb so
the file is selectable and the message can be shown. Any other KDBX open failure
(wrong password, invalid file) is wrapped in a readable message.
Import-flow UX refinements (raised during collaudo):
- Order: ask for the KDBX password AFTER the file is chosen, not before, so the prompt
refers to a file the user actually selected and a cancelled picker wastes no entry.
- Format dialog labels now show accepted extensions: "CSV generico (.csv)",
"KeePass 2.x (.kdbx)", "1Password (.1pux)", "Bitwarden (.json / .zip)".
- KDBX password dialog keeps "OK" disabled until a password is typed.
- Help -> FAQ "How do I import…" enriched with the full format/extension details,
including what is NOT importable (encrypted Bitwarden, KeePass 1.x) and how to
convert — translated across all 6 languages.
FilePickerService gains a multi-extension PickOpenFileAsync overload.
Tests: 221/221 (+2 FU3: encrypted -> exception, plaintext -> normal import).
Post-T5.GATE follow-up FU3. Build 0/0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Enriches IdentityEntry with three fields inspired by Bitwarden/1Password identity
records: Middle name, Company and Username.
- IdentityEntry: + MiddleName, Company, Username (backward-compatible defaults).
- IdentityDetailViewModel: + three observable properties, wired through
ResetFieldsForNew / LoadFromEntry / CreateNewEntry / ApplyToEntry.
- IdentityDetailView: Middle name between First and Last name; Company and Username
after Phone, in the Personal Data section. Tab order updated.
- 6× .resw: FieldMiddleName.Text, FieldCompany.Text and FieldIdentityUsername.Text
(558 keys aligned), with semantic translations.
Note: the username key is FieldIdentityUsername, NOT FieldUsername — the latter
already exists for the password login field ("Email / User ID") and reusing it would
mislabel the identity field.
FU5(b) "international localisation" was already satisfied: the existing identity
labels are semantically localised per country (Provincia -> Bundesland/Distrito,
Regione -> Comunidad autónoma, Carta d'identità -> DNI/Personalausweis/Cartão de
cidadão, Tessera sanitaria -> Carte vitale), so no further work was needed there.
Post-T5.GATE follow-up FU5. Build 0/0, tests 221/221.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…lace edit Editing an existing identity left its list card showing the old values until the page was revisited. ApplyFilterAndSort does Entries.Clear()+Add() with the SAME object references (the edit mutates the entry in place), so the GridView recycles the container for the identical reference without re-running ContainerContentChanging — which is what populates the identity cards' computed fields (avatar initial, full name, formatted phone). The other lists are unaffected because they use direct bindings. Fix: in IdentitiesListView, when the detail panel closes (IsDetailOpen -> false), rebind ItemsSource (RefreshListContainers) to force a full container regeneration so the edited card reflects the change without revisiting the page. Post-T5.GATE follow-up FU11. Build 0/0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The vault audit (Verifica → Vault) walked the vault sequentially, one HIBP call at a time with a 200ms courtesy delay between calls. With ~113 passwords it took ~45s; at 1000 it would take ~6 minutes, showing a frozen "0" the whole time. Parallelisation (WatchtowerScanService): - RunScanAsync rewritten from a sequential for-loop + Task.Delay throttle to Parallel.ForEachAsync with MaxDegreeOfParallelism = HibpConcurrency (8) when HIBP is enabled (1 when disabled — the remaining work is purely local). The HIBP range (k-anonymity) endpoint is CDN-backed and built for volume, so bounded concurrency is safe. Thread-safe aggregation via ConcurrentBag + Interlocked. The strength analyzer is stateless and the HIBP HttpClient is a shared singleton. Estimated 1000-password scan: ~6 min -> ~19s. Live progress: - IWatchtowerScanService.Progress changed from Action<double> to Action<int,int> (scanned, total). Only PasswordVerifierViewModel subscribed; the dashboard is unaffected. - PasswordVerifierViewModel gains ScannedCount/TotalToScan; AuditProgress is now 0-100. - PasswordVerifierView repurposes the existing determinate VaultScoreRing as a live progress ring during the scan — the arc grows and the centre shows the live "X / N" count — then restores the final score when the scan completes. The separate indeterminate spinner is disabled. Known side effect: issue lists (compromised/weak/duplicate) are now in arbitrary order (ConcurrentBag) instead of vault order — acceptable, they are grouped by category. Post-T5.GATE follow-up FU12. Build 0/0, tests 221/221. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The BitwardenIdentity DTO declared only 10 of the ~18 fields Bitwarden exports for an
identity, so middleName, company, username, ssn, passportNumber, licenseNumber and
address3 were silently lost on import — the worst being passport and licence, whose
destination fields already existed on IdentityEntry.
- BitwardenIdentity DTO: + MiddleName, Username, Company, Ssn, PassportNumber,
LicenseNumber, Address3.
- MapIdentity now maps:
middleName -> MiddleName (FU5 field)
company -> Company (FU5 field)
username -> Username (FU5 field)
ssn -> HealthCardNumber (Codice Fiscale / Tessera Sanitaria for IT users)
passportNumber -> PassportNumber
licenseNumber -> DrivingLicenseNumber
address3 -> folded into Street with address1/address2
CombineAddress now joins all three address lines. "title" (Mr/Sig.) stays unmapped,
consistent with FU5 dropping the Title field.
Verified on a real Bitwarden export: passport AA1234BB, licence CC1234DD, codice
fiscale JHSROS92H10H264C and username now import correctly.
Tests: 222/222 (+1 FU4 covering all extended fields).
Post-T5.GATE follow-up FU4 (final FU). Build 0/0.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ders Categoria A (bare-key → .Text, valori già tradotti): - PageIdentities/PageNotes (titoli pagina) - HelpView: 41 chiavi bare → .Text (guide, FAQ, scorciatoie, PageHelp) - ButtonAddNote (pulsante Aggiungi note) - EmptyEditorHint (hint editor note, nuova chiave ×6) Categoria B (x:Uid + 9 nuove chiavi ×6 lingue): - Placeholder note (Password/Identity detail) via chiave condivisa PlaceholderNotes - Placeholder campo Password (Password detail) - Header "Chiave Base32" (TotpSecretReadout) - Placeholder master password Setup (×2) - Placeholder + nota offline Verifier - "Escludi caratteri ambigui" (Generator) - RequiredFieldLegendIdentity (split da RequiredFieldLegend: testi divergenti Carte/Identità) CreditCardDetailView non toccato: CardNotesBox.PlaceholderText già presente. resw allineati a 569 chiavi ×6. Build 0/0, test 222/222. Collaudato EN+IT. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Generator: hero card fixed Width=560 (no longer grows with password length, which dragged the options layout). Password on a single line clipped via a scroll-disabled ScrollViewer + right-edge LinearGradientBrush fade (transparent -> CardBackgroundFillColorDefault, theme-aware). Full value via Copy. - Verifier: Password tab StackPanel fixed Width=640 (no longer stretches to the whole window nor shrinks to content). Vault tab untouched. Build 0/0, test 222/222. Collaudato EN+IT. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Restore the original name-based delete dialog using the already-translated
(but orphaned) keys DeleteConfirmTitle/DeleteConfirmMessage/DeleteButton/CancelButton (×6 langs).
- BaseDetailViewModel.DeleteAsync: build dialog via ResourceLoader + the 4 keys.
Removed dead/hardcoded methods: GetDeleteDialogTitle (abstract) + the 3 IT virtuals
GetDeleteDialogContent/GetDeletePrimaryButtonText/GetDeleteCloseButtonText.
- 4 DetailViewModels: removed GetDeleteDialogTitle overrides ("Elimina password/carta/…").
- 4 ListViewModels (quick-delete): replaced IT literals with the same 4 keys.
No new resw keys (reuse). Build 0/0, test 222/222. Collaudato EN+IT (detail + list paths).
Fallback display names ("Carta senza nome" etc.) deferred to C-f.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
11 new resw keys ×6 langs: - Tray context menu (MainWindow): TrayMenuShow/Lock/Exit (x:Name + ResourceLoader in ctor; Window XAML has no x:Uid resource map, so localized in code-behind). - Close-confirmation dialog (MainWindow): TrayCloseContent/Minimize/Exit (+ reuse CancelButton). - Manual 2FA-key dialog (PasswordDetailView): Totp2faDialogTitle/Body, TotpSeedPlaceholder, SaveButton (+ reuse CancelButton). - WelcomeView: 2× "OK" -> ButtonOk. resw aligned at 580 ×6. Build 0/0, test 222/222. Collaudato EN+IT. Deferred: TOTP tooltip "Chiave Base32 non valida" -> C-f; "Startup error" -> QUAL-01. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
SecureNotesListViewModel static helpers (added a static ResourceLoader):
- GetCategoryName: 10 note categories (Generale..Altro) -> 10 resw keys ×6 langs.
- GetRelativeDate: "Adesso/{n} min fa/{n} ore fa/Ieri/{n}g fa" -> localized with placeholders;
date format culture now follows the selected language (NoteDateCulture key) instead of
hardcoded it-IT, so month names match the UI language.
16 new resw keys ×6 (aligned at 596). Build 0/0, test 222/222. Collaudato EN+IT.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AddIdentity.Text had a literal "+ " prefix in all 6 langs while the button already renders a "+" FontIcon (E710), causing a doubled "+ + Add identity". Stripped the prefix to match the Passwords/Cards add buttons. resw values only (aligned at 596). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
i18n (14 new resw keys ×6, aligned at 610): - Filter "All categories" + announce, section headers Pinned/Notes, pinned a11y status, no-results announce, char/word count + announce, unsaved/saving/saved announces, pin/unpin names. - Category filter "All categories" gets a neutral grey dot so it aligns with the coloured category dots (was a large dot-to-text gap). - Filter button tooltip + accessible name localized (NoteFilterTooltip) via code-behind. Layout redesign (per user mock-up): - Master panel header now shows only the page title + filter icon (title NoWrap → fits on a single line in every language; previously wrapped in all but English). - Search box + Add button moved to a top-right toolbar in the detail panel. Build 0/0, test 222/222. Collaudato EN+IT+DE/FR. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SecureNoteDetailView: add a Cancel button to the footer (Delete · Pin · — · Cancel · Save). Reuses ButtonCancel; the Cancelled action was already wired to CloseEditor in the list VM. - ButtonAddNote label now includes the noun: "Add note"/"Aggiungi nota" (was bare "Add"). - UI-02 (harmonize add-button labels to the "Add X" convention across all four lists): AddPasswordLabel "New password" -> "Add password", AddCardLabel "New card" -> "Add card" (×6 langs). Identities/Notes already used "Add X". resw aligned at 610. Build 0/0, test 222/222. Collaudato EN+IT+DE. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…dicator UI-03: Passwords/Cards/Identities search box MaxWidth 300 -> 280, matching Dashboard and Secure Notes (consistent search width across all pages). UI-04: colour the NavigationView selection indicator per category, matching the Dashboard colour coding — Passwords #0078D4, Cards #8764B8, Identities #00B294, Notes #FFB900 (per-item NavigationViewSelectionIndicatorForeground overrides). Non-category pages (Dashboard/Generator/Verifier/Help/Settings/Lock) use a theme-reactive neutral grey defined in the theme dictionaries (Light #5F5F5F, Dark #A6A6A6) for proper contrast in both themes. Build 0/0, test 222/222. Collaudato light+dark. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GeneratorView static crack-time helpers (added a static ResourceLoader):
- GetCrackTimeLabel / LocalizeCrackTimeString: instant/seconds/centuries/millennia +
{n} minutes/hours/days/years -> 8 resw keys ×6.
- Announce on generate/copy localized (GeneratorPwGenerated / GeneratorPwCopied).
10 new resw keys ×6 (aligned at 620). Build 0/0, test 222/222. Localization collaudata EN+IT.
Note: separate Generator quality issues (dark-theme letter colour, recent-passwords box,
crack-time bucketing, missing visible copy feedback) tracked next.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
#1 Copy feedback: GeneratorViewModel injects IToastService -> shows "Copied" toast on password/history copy (consistent with other pages); history copy tooltip localized. #3 Dark-theme password syntax colours: code-behind resolved brushes via Application.Current.Resources[...] which is NOT theme-aware for ThemeDictionaries keys. Added ThemeBrush(key) (resolves by ActualTheme) + re-render on ActualThemeChanged. #5 Recent-passwords boxes: moved to theme-aware XAML Styles (ThemeResource); inactive strength segments use ClearValue to revert to the XAML ThemeResource. #4 Fade: WinUI 3 has no OpacityMask (WMC0011) and the overlay-gradient double-drew on the semi-transparent card in dark theme -> replaced with a clean hard clip. #2 Crack-time: refined high-end buckets (thousand/million/billion years + "over a trillion years") so it no longer jumps straight from years to millennia. 4 resw keys swapped ×6. Build 0/0, test 222/222. Collaudato light+dark. (Verifier crack-time localization: C-c2.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…uggestions, issues)
- New shared Helpers/CrackTimeFormatter: single crack-time localization used by both the
Generator and the Verifier (Generator refactored to use it; removed its duplicate methods).
- Verifier crack-time now localized (was raw "trillionyears").
- Strength label reuses the existing Strength* keys (was hardcoded "Molto forte" etc.).
- Expander headers "Compromised/Weak/Reused passwords (N)" -> formatted resw keys.
- 7 improvement suggestions localized.
- Issue rows "(untitled)", "{n} breaches", "reused" localized.
13 new resw keys ×6 (aligned at 635). Build 0/0, test 222/222. Collaudato EN+IT.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tions Import errors now use error CODES (Core/Orchestrator stay i18n-free), mapped to localized strings in SettingsView.OnOperationError (same pattern as WRONG_PASSWORD/INVALID_FILE): - BitwardenImporter (Core): encrypted export -> IMPORT_BW_ENCRYPTED - ImportOrchestrator: BW zip missing data.json -> IMPORT_BW_ZIP; .1pux missing export.data -> IMPORT_1PUX (now ImportFileException); KeePass 1.x -> IMPORT_KEEPASS_1X; open failure -> IMPORT_KEEPASS_OPEN - SettingsViewModel: no recognizable entries -> IMPORT_NO_ENTRIES - File-picker descriptions (Bitwarden/KeePass) localized 8 new resw keys ×6 (aligned at 643). Build 0/0, test 222/222 (updated BitwardenImporter test to assert the error code). Collaudato EN+IT with crafted fixture files. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… fixes i18n (15 new resw keys ×6, aligned at 658): - TOTP error feedback (no QR / not otpauth / empty clipboard / invalid Base32 / icon too large) - Login errors (reuse LoginIncorrectPassword + new LoginUnlockFailed) - SetupView strength labels (reuse Strength*), error button, generic create-error message - Shell update-available InfoBar title, ActivityLog CSV filename, CardCategory.Online - Fallback display names (Card/Identity/Note) — BaseDetailViewModel._res made protected Quality fixes folded in: - SetupView no longer dumps ex.ToString() (stack trace) to the UI — shows a generic localized message and logs via Debug (QUAL-01). - TOTP/icon error feedback converted from hover-only ToolTipService tooltips to visible toasts (ToastSeverity.Warning) — they were effectively invisible before. - DashboardViewModel: removed dead hardcoded Italian default labels (overwritten by code-behind). Final sweep: no user-facing Italian literals remain (only a comment + dead PanelTitle/P2). Build 0/0, test 222/222. Collaudato EN+IT. Closes Category C / the bulk of LOC-01 i18n. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Added CenterOnScreen() (called from the MainWindow constructor): positions the window at the centre of the WorkArea of the display it is created on (DisplayArea.GetFromWindowId + AppWindow.Move). Multi-monitor aware (DisplayAreaFallback.Nearest); centres only at startup, not on every tray-restore, so a user-moved window keeps its position. Build 0/0, test 222/222. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…t brush - App.xaml.cs: browser IPC startup failure now logged via Debug.WriteLine (was empty catch). - DashboardView.xaml.cs: invalid recent-item URL now logged (was empty catch). - PasswordDetailView.xaml: TOTP countdown ProgressRing Foreground used the SystemAccentColor *Color* on a Brush property -> switched to AccentFillColorDefaultBrush (proper theme brush). Build 0/0, test 222/222. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ssage SettingsViewModel backup/restore/import generic catches surfaced the raw framework ex.Message (often English, may leak internals). Now they log via Debug.WriteLine and show a generic localized message (OperationGenericError / OPERATION_FAILED), mapped in SettingsView + WelcomeView. Import keeps a dedicated catch (ImportFileException) BEFORE the generic one so the localized import error codes are preserved. 1 new resw key ×6 (aligned at 659). Build 0/0, test 222/222. Collaudato EN+IT (import-specific messages intact; generic error via unsupported-version .pkbak fixture). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- GeneratorViewModel: removed unused GenerateAndCopy command (no XAML binding) + orphaned ButtonGenerateAndCopy resw key. - IdentitiesListViewModel: removed unused CopyEmail/CopyPhone commands (no UI). - PasswordVerifierView: removed AuditLoadingRing ProgressRing (never activated) + the code that disabled it. Kept Identities sort logic (functional, not dead). Build 0/0, test 222/222. No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Passwords/Cards/Identities search boxes used MaxWidth + HorizontalAlignment=Right in a star column, which made the AutoSuggestBox size to its content (placeholder when empty, then shrinking to the typed text and growing per character). Switched to a fixed Width=280 so the box stays a stable 280px regardless of content, matching Dashboard and Secure Notes. Build 0/0, test 222/222. Collaudato. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…a x:Uid Validates the x:Uid attached-property localization technique at runtime, including ToolTipService.ToolTip (Uid.[using:Microsoft.UI.Xaml.Controls]ToolTipService.ToolTip). ActivityLog Back/Export buttons: removed inline IT, added x:Uid + 3 resw keys ×6. Build 0/0, test 222/222. Tooltip confirmed localized at runtime (EN+IT). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
OnWindowClosing showed the close-confirmation ContentDialog via a direct ShowAsync(), bypassing the shared dialog queue. If another ContentDialog was open (or the X was clicked again), WinUI threw "Only a single ContentDialog can be open at any time" as an unhandled exception. Now the close prompt is routed through IDialogQueueService.EnqueueAndWait (serialized with all other dialogs) and guarded by a _closePromptOpen re-entrancy flag. Build 0/0, test 222/222. Collaudato (normal close, repeated X, close while a dialog is open). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LOC-02 full rollout: localize remaining hardcoded strings (tooltips, AutomationProperties, placeholders) across Dashboard, Shell, Welcome, Settings, Generator, Login, Setup, Verifier and the list/detail views via x:Uid, with matching resw keys in all 6 languages. Gate v2.0.0 cluster fixes: - i18n: localized placeholders for Identity (15), Password (3) and the credit-card PIN field; example data localized per language (G1/G2/G6). - i18n: password Save button uses resources instead of hardcoded "Salva"/"Salvataggio..." (G5). - ux: remove the redundant category colour dot in the Secure Note editor (U1). - ux: auto-lock shows a 10s "stay active" warning for the 30s tier, consistent with the longer tiers (U2). - extensions (Chrome+Firefox): fix invisible action icons — setSvgIcon parsed inline SVG as image/svg+xml without an xmlns, leaving icons in the null namespace; now parsed as text/html. Copy actions always visible with clear affordance (U3). - cleanup: remove dead PanelTitle/GetPanelTitle code from the detail VMs. Verified: build x64 0/0, tests 222/222, localization audit clean, manual Gate v2.0.0 pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ifier (U4)
System theme brushes fetched via Application.Current.Resources (e.g.
TextFillColorSecondaryBrush) do not honour the active theme and always
returned the light variant, making secondary text and the "reused" dots in
the Verifier "Vault" tab unreadable on dark backgrounds.
- add theme-aware MutedTextBrush (Light/Dark) to ThemeColors.xaml
- PasswordVerifierView: use MutedTextBrush; strength-bar empty track now
reverts to the XAML {ThemeResource} via ClearValue (matches GeneratorView)
- same latent bug fixed in SecureNotesListView (category filter dot) and
EmptyStateControl (badge fallback)
Build 0/0, tests 222/222.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the March/v1.x Italian screenshots with fresh English-UI captures from the v2.0.0 build (Cluster 3/4/5 features, localization, new look). Drop the granular settings/help sub-screenshots that were unreferenced. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…nsions) - PassKey.Desktop.csproj: 1.0.17 -> 2.0.0 (Version/Assembly/File) - Installer/PassKey.iss: AppVersion 1.0.17 -> 2.0.0 - README download links -> v2.0.0 - chrome/firefox manifests: 1.0.0 -> 1.0.1 (ships the U3 popup icon fix) Build 0/0, tests 222/222. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Update dashboard, password and card screenshots on pass-key.it to the v2.0.0 English-UI build. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PassKey v2.0.0
Major release on top of clusters 1–4 (already on
main).Highlights
x:Uid; localized placeholders (Identity/Password/PIN, example data per language); localized save button; dead panel-title code removed.Verification
🤖 Generated with Claude Code