From d77a39b98c1459c72fe3997cf48b791c332d86fe Mon Sep 17 00:00:00 2001 From: Artem Bugaev Date: Sun, 1 Mar 2026 17:28:19 +0300 Subject: [PATCH 1/3] Added timer blocking --- .../ViewModels/RepositoryWindowViewModel.cs | 69 +++++++++++++++++++ src/KeyKeeper/Views/RepositoryWindow.axaml | 25 ++++++- src/KeyKeeper/Views/RepositoryWindow.axaml.cs | 16 ++++- 3 files changed, 106 insertions(+), 4 deletions(-) diff --git a/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs b/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs index 6626261..4db29c9 100644 --- a/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs +++ b/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs @@ -1,13 +1,19 @@ using System; using System.Threading.Tasks; +using Avalonia.Threading; using KeyKeeper.PasswordStore; namespace KeyKeeper.ViewModels; public partial class RepositoryWindowViewModel : ViewModelBase { + private static readonly TimeSpan LockTimeout = TimeSpan.FromMinutes(5); + private object currentPage; private IPassStore passStore; + private DispatcherTimer? _lockTimer; + private DateTime _timerStart; + private string _lockTimerDisplay = string.Empty; public Func ShowErrorPopup; @@ -17,6 +23,12 @@ public partial class RepositoryWindowViewModel : ViewModelBase set { currentPage = value; OnPropertyChanged(nameof(CurrentPage)); } } + public string LockTimerDisplay + { + get => _lockTimerDisplay; + private set { _lockTimerDisplay = value; OnPropertyChanged(nameof(LockTimerDisplay)); } + } + public RepositoryWindowViewModel(IPassStore store) { passStore = store; @@ -31,13 +43,70 @@ public partial class RepositoryWindowViewModel : ViewModelBase SwitchToLocked(); } + /// + /// Ñáðàñûâàåò òàéìåð áëîêèðîâêè (âûçûâàåòñÿ ïðè ëþáîé àêòèâíîñòè ïîëüçîâàòåëÿ). + /// + public void ResetLockTimer() + { + if (_lockTimer != null && _lockTimer.IsEnabled) + _timerStart = DateTime.UtcNow; + } + private void SwitchToUnlocked() { CurrentPage = new UnlockedRepositoryViewModel(passStore); + StartLockTimer(); } private void SwitchToLocked() { + StopLockTimer(); CurrentPage = new LockedRepositoryViewModel(passStore, this); } + + private void StartLockTimer() + { + StopLockTimer(); + _timerStart = DateTime.UtcNow; + _lockTimer = new DispatcherTimer + { + Interval = TimeSpan.FromSeconds(1) + }; + _lockTimer.Tick += OnLockTimerTick; + _lockTimer.Start(); + UpdateTimerDisplay(); + } + + private void StopLockTimer() + { + if (_lockTimer != null) + { + _lockTimer.Tick -= OnLockTimerTick; + _lockTimer.Stop(); + _lockTimer = null; + } + LockTimerDisplay = string.Empty; + } + + private void OnLockTimerTick(object? sender, EventArgs e) + { + var elapsed = DateTime.UtcNow - _timerStart; + var remaining = LockTimeout - elapsed; + + if (remaining <= TimeSpan.Zero) + { + StopLockTimer(); + passStore.Lock(); + UpdateLockStatus(); + return; + } + + UpdateTimerDisplay(remaining); + } + + private void UpdateTimerDisplay(TimeSpan? remaining = null) + { + var r = remaining ?? LockTimeout; + LockTimerDisplay = $"{r:mm\\:ss}"; + } } \ No newline at end of file diff --git a/src/KeyKeeper/Views/RepositoryWindow.axaml b/src/KeyKeeper/Views/RepositoryWindow.axaml index 1bf3b0d..7aaaf65 100644 --- a/src/KeyKeeper/Views/RepositoryWindow.axaml +++ b/src/KeyKeeper/Views/RepositoryWindow.axaml @@ -25,7 +25,30 @@ FontSize="32" FontWeight="Bold" HorizontalAlignment="Left" - Margin="0,0,0,20"/> + Margin="0,0,0,8"/> + + + + + + + + + Date: Tue, 24 Mar 2026 22:13:59 +0300 Subject: [PATCH 2/3] fix timer ticking while adding a password --- src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs | 4 ++-- src/KeyKeeper/Views/RepositoryWindow.axaml.cs | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs b/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs index 4db29c9..77d810b 100644 --- a/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs +++ b/src/KeyKeeper/ViewModels/RepositoryWindowViewModel.cs @@ -64,7 +64,7 @@ public partial class RepositoryWindowViewModel : ViewModelBase CurrentPage = new LockedRepositoryViewModel(passStore, this); } - private void StartLockTimer() + public void StartLockTimer() { StopLockTimer(); _timerStart = DateTime.UtcNow; @@ -77,7 +77,7 @@ public partial class RepositoryWindowViewModel : ViewModelBase UpdateTimerDisplay(); } - private void StopLockTimer() + public void StopLockTimer() { if (_lockTimer != null) { diff --git a/src/KeyKeeper/Views/RepositoryWindow.axaml.cs b/src/KeyKeeper/Views/RepositoryWindow.axaml.cs index 227c950..ffdc527 100644 --- a/src/KeyKeeper/Views/RepositoryWindow.axaml.cs +++ b/src/KeyKeeper/Views/RepositoryWindow.axaml.cs @@ -41,8 +41,13 @@ public partial class RepositoryWindow : Window if (DataContext is RepositoryWindowViewModel vm_ && vm_.CurrentPage is UnlockedRepositoryViewModel vm) { EntryEditWindow dialog = new(); + + vm_.StopLockTimer(); + await dialog.ShowDialog(this); + vm_.StartLockTimer(); + if (dialog.EditedEntry != null) vm.AddEntry(dialog.EditedEntry); } From f851d62a2b9e32d673d02eff8ad7a51347a53db0 Mon Sep 17 00:00:00 2001 From: Slavasil Date: Tue, 24 Mar 2026 23:01:15 +0300 Subject: [PATCH 3/3] make timer stop while editing passwords --- src/KeyKeeper/Views/RepositoryWindow.axaml.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/KeyKeeper/Views/RepositoryWindow.axaml.cs b/src/KeyKeeper/Views/RepositoryWindow.axaml.cs index a12b662..6e39894 100644 --- a/src/KeyKeeper/Views/RepositoryWindow.axaml.cs +++ b/src/KeyKeeper/Views/RepositoryWindow.axaml.cs @@ -118,8 +118,13 @@ public partial class RepositoryWindow : Window EntryEditWindow dialog = new(); dialog.SetEntry(selectedEntry); + + vm_.StopLockTimer(); + await dialog.ShowDialog(this); + vm_.StartLockTimer(); + if (dialog.EditedEntry != null) { vm.UpdateEntry(dialog.EditedEntry); @@ -165,7 +170,9 @@ public partial class RepositoryWindow : Window { EntryEditWindow dialog = new(); dialog.SetEntry(pwd); + vm.StopLockTimer(); await dialog.ShowDialog(this); + vm.StartLockTimer(); if (dialog.EditedEntry != null) { pageVm.UpdateEntry(dialog.EditedEntry);