Reimplemented locks as DataTemplates to abide more to MVVM principles. PIN lock working perfectly. SlideLock on progress.
MODIFY
WalletWasabi.Gui/Controls/LockScreen/LockScreen.xaml.cs
WalletWasabi.Gui/Controls/LockScreen/LockScreen.xaml.cs
@@ -8,6 +8,11 @@ namespace WalletWasabi.Gui.Controls.LockScreen
{
public class LockScreen : UserControl
{
+ public LockScreen() : base()
+ {
+ InitializeComponent();
+ }
+
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);

MODIFY
WalletWasabi.Gui/Controls/LockScreen/LockScreenViewModel.cs
WalletWasabi.Gui/Controls/LockScreen/LockScreenViewModel.cs
@@ -51,11 +51,14 @@ namespace WalletWasabi.Gui.Controls.LockScreen
_pinHash = Global.UiConfig
.WhenAnyValue(x => x.LockScreenPinHash)
.ObserveOn(RxApp.MainThreadScheduler)
+ .Do(x => CheckLockScreenType(x))
.ToProperty(this, x => x.PINHash);
}
private void CheckLockScreenType(string currentHash)
{
+ ActiveLockScreen?.Dispose();
+
if (currentHash != string.Empty)
{
ActiveLockScreen = new PinLockScreenViewModel(this);

MODIFY
WalletWasabi.Gui/Controls/LockScreen/PinLockScreen.xaml.cs
WalletWasabi.Gui/Controls/LockScreen/PinLockScreen.xaml.cs
@@ -17,60 +17,26 @@ namespace WalletWasabi.Gui.Controls.LockScreen
{
public class PinLockScreen : UserControl
{
- public Grid Shade { get; }
+ public static readonly DirectProperty<PinLockScreen, bool> IsLockedProperty =
+ AvaloniaProperty.RegisterDirect<PinLockScreen, bool>(nameof(IsLocked),
+ o => o.IsLocked,
+ (o, v) => o.IsLocked = v);
+ private bool _isLocked;
- public ReactiveCommand<string, Unit> KeyPadCommand { get; }
-
- private NoparaPasswordBox PinLockPwdBox;
-
- internal string PINHash { get; set; }
-
- public PinLockScreen() : base()
- {
- InitializeComponent();
-
- this.Shade = this.FindControl<Grid>("Shade");
- this.PinLockPwdBox = this.FindControl<NoparaPasswordBox>("PinLockPwdBox");
-
- PinLockPwdBox.WhenAnyValue(x => x.Password)
- .Select(Guard.Correct)
- .Where(x => x != string.Empty)
- .DistinctUntilChanged()
- .Throttle(TimeSpan.FromSeconds(1d))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(CheckPIN);
-
- KeyPadCommand = ReactiveCommand.Create<string>((arg) =>
+ public bool IsLocked
{
- PinLockPwdBox.Password += arg;
- });
+ get => _isLocked;
+ set => this.SetAndRaise(IsLockedProperty, ref _isLocked, value);
}
- private void CheckPIN(string obj)
- {
- var currentHash = HashHelpers.GenerateSha256Hash(obj);
- if (currentHash == PINHash)
+ public PinLockScreen() : base()
{
- PinLockPwdBox.Password = "";
- this.IsLocked = false;
- }
+ InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
-
- public override void DoLock()
- {
- Shade.Classes.Add("Locked");
- Shade.Classes.Remove("Unlocked");
- }
-
- public override void DoUnlock()
- {
- Shade.Classes.Add("Unlocked");
- Shade.Classes.Remove("Locked");
- }
}
}
\ No newline at end of file

MODIFY
WalletWasabi.Gui/Controls/LockScreen/PinLockScreenViewModel.cs
WalletWasabi.Gui/Controls/LockScreen/PinLockScreenViewModel.cs
using WalletWasabi.Gui.ViewModels;
using WalletWasabi.Helpers;
+using System;
+using System.Reactive;
+using ReactiveUI;
+using System.Reactive.Disposables;
+using System.Reactive.Linq;
namespace WalletWasabi.Gui.Controls.LockScreen
{
@@ -7,9 +12,69 @@ namespace WalletWasabi.Gui.Controls.LockScreen
{
private LockScreenViewModel _parentVM;
+ private CompositeDisposable Disposables { get; }
+
+ public ReactiveCommand<string, Unit> KeyPadCommand { get; }
+
+ private readonly ObservableAsPropertyHelper<bool> _isLocked;
+ public bool IsLocked => _isLocked?.Value ?? false;
+
+ private string _pinInput;
+ public string PinInput
+ {
+ get => _pinInput;
+ set => this.RaiseAndSetIfChanged(ref _pinInput, value);
+ }
+
+ private bool _warningMessageVisible;
+ public bool WarningMessageVisible
+ {
+ get => _warningMessageVisible;
+ set => this.RaiseAndSetIfChanged(ref _warningMessageVisible, value);
+ }
+
public PinLockScreenViewModel(LockScreenViewModel lockScreenViewModel)
{
_parentVM = Guard.NotNull(nameof(lockScreenViewModel), lockScreenViewModel);
+
+ Disposables = new CompositeDisposable();
+
+ KeyPadCommand = ReactiveCommand.Create<string>((arg) =>
+ {
+ PinInput += arg;
+ });
+
+ this.WhenAnyValue(x => x.PinInput)
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .Throttle(TimeSpan.FromSeconds(0.5))
+ .Select(Guard.Correct)
+ .Where(x => x != string.Empty)
+ .Do(x => this.WarningMessageVisible = false)
+ .DistinctUntilChanged()
+ .Subscribe(CheckPIN)
+ .DisposeWith(Disposables);
+
+ _isLocked = _parentVM.WhenAnyValue(x => x.IsLocked)
+ .ObserveOn(RxApp.MainThreadScheduler)
+ .ToProperty(this, x => x.IsLocked)
+ .DisposeWith(Disposables);
+ }
+
+ private void CheckPIN(string input)
+ {
+ if (_parentVM.PINHash == HashHelpers.GenerateSha256Hash(input))
+ {
+ _parentVM.IsLocked = false;
+ PinInput = string.Empty;
+ }
+ else
+ {
+ WarningMessageVisible = true;
+ }
+ }
+ public void Dispose()
+ {
+ this.Disposables?.Dispose();
}
}
}
\ No newline at end of file

MODIFY
WalletWasabi.Gui/Controls/LockScreen/SlideLockScreen.xaml.cs
WalletWasabi.Gui/Controls/LockScreen/SlideLockScreen.xaml.cs
@@ -12,10 +12,20 @@ using System.Reactive.Disposables;
namespace WalletWasabi.Gui.Controls.LockScreen
{
- internal class SlideLockScreen : UserControl
+ public class SlideLockScreen : UserControl
{
- private CompositeDisposable Disposables { get; set; }
- private Grid Shade;
+
+ public static readonly DirectProperty<SlideLockScreen, CompositeDisposable> DisposablesProperty =
+ AvaloniaProperty.RegisterDirect<SlideLockScreen, CompositeDisposable>(nameof(Disposables),
+ o => o.Disposables,
+ (o, v) => o.Disposables = v);
+ private CompositeDisposable _disposables;
+ public CompositeDisposable Disposables
+ {
+ get => _disposables;
+ set => this.SetAndRaise(DisposablesProperty, ref _disposables, value);
+ }
+
private Thumb DragThumb;
private TranslateTransform TargetTransform;
private bool UserDragInProgress, StopSpring;
@@ -35,11 +45,10 @@ namespace WalletWasabi.Gui.Controls.LockScreen
{
InitializeComponent();
- this.Shade = this.FindControl<Grid>("Shade");
this.DragThumb = this.FindControl<Thumb>("PART_DragThumb");
TargetTransform = new TranslateTransform();
- Shade.RenderTransform = TargetTransform;
+ this.RenderTransform = TargetTransform;
}
private void InitializeComponent()
@@ -61,17 +70,17 @@ namespace WalletWasabi.Gui.Controls.LockScreen
private void OnClockTick(TimeSpan CurrentTime)
{
- if (!UserDragInProgress & Math.Abs(Offset) > RealThreshold)
- {
- IsLocked = false;
- StopSpring = true;
- return;
- }
+ // if (!UserDragInProgress & Math.Abs(Offset) > RealThreshold)
+ // {
+ // IsLocked = false;
+ // StopSpring = true;
+ // return;
+ // }
- if (IsLocked & !UserDragInProgress & Offset != 0)
- {
- Offset *= 1 - Stiffness;
- }
+ // if (IsLocked & !UserDragInProgress & Offset != 0)
+ // {
+ // Offset *= 1 - Stiffness;
+ // }
}
private void OnDragStarted()
@@ -92,44 +101,45 @@ namespace WalletWasabi.Gui.Controls.LockScreen
UserDragInProgress = false;
}
- public override void DoLock()
- {
- Shade.Classes.Add("Locked");
- Shade.Classes.Remove("Unlocked");
- Offset = 0;
- UserDragInProgress = false;
- Disposables = new CompositeDisposable();
+ // public override void DoLock()
+ // {
+ // Shade.Classes.Add("Locked");
+ // Shade.Classes.Remove("Unlocked");
+ // Offset = 0;
+ // UserDragInProgress = false;
- Observable.FromEventPattern<VectorEventArgs>(DragThumb, nameof(DragThumb.DragCompleted))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(e => OnDragCompleted(e.EventArgs))
- .DisposeWith(Disposables);
+ // Disposables = new CompositeDisposable();
- Observable.FromEventPattern<VectorEventArgs>(DragThumb, nameof(DragThumb.DragDelta))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(e => OnDragDelta(e.EventArgs))
- .DisposeWith(Disposables);
+ // Observable.FromEventPattern<VectorEventArgs>(DragThumb, nameof(DragThumb.DragCompleted))
+ // .ObserveOn(RxApp.MainThreadScheduler)
+ // .Subscribe(e => OnDragCompleted(e.EventArgs))
+ // .DisposeWith(Disposables);
- Observable.FromEventPattern(DragThumb, nameof(DragThumb.DragStarted))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(e => OnDragStarted())
- .DisposeWith(Disposables);
+ // Observable.FromEventPattern<VectorEventArgs>(DragThumb, nameof(DragThumb.DragDelta))
+ // .ObserveOn(RxApp.MainThreadScheduler)
+ // .Subscribe(e => OnDragDelta(e.EventArgs))
+ // .DisposeWith(Disposables);
- this.WhenAnyValue(x => x.Bounds)
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(OnBoundsChange)
- .DisposeWith(Disposables);
+ // Observable.FromEventPattern(DragThumb, nameof(DragThumb.DragStarted))
+ // .ObserveOn(RxApp.MainThreadScheduler)
+ // .Subscribe(e => OnDragStarted())
+ // .DisposeWith(Disposables);
- Clock.Subscribe(OnClockTick)
- .DisposeWith(Disposables);
- }
+ // this.WhenAnyValue(x => x.Bounds)
+ // .ObserveOn(RxApp.MainThreadScheduler)
+ // .Subscribe(OnBoundsChange)
+ // .DisposeWith(Disposables);
- public override void DoUnlock()
- {
- Shade.Classes.Add("Unlocked");
- Shade.Classes.Remove("Locked");
- Disposables?.Dispose();
- }
+ // Clock.Subscribe(OnClockTick)
+ // .DisposeWith(Disposables);
+ // }
+
+ // public override void DoUnlock()
+ // {
+ // Shade.Classes.Add("Unlocked");
+ // Shade.Classes.Remove("Locked");
+ // Disposables?.Dispose();
+ // }
}
}

MODIFY
WalletWasabi.Gui/Controls/LockScreen/SlideLockScreenViewModel.cs
WalletWasabi.Gui/Controls/LockScreen/SlideLockScreenViewModel.cs
@@ -11,5 +11,9 @@ namespace WalletWasabi.Gui.Controls.LockScreen
{
_parentVM = Guard.NotNull(nameof(lockScreenViewModel), lockScreenViewModel);
}
+ public void Dispose()
+ {
+
+ }
}
}

MODIFY
WalletWasabi.Gui/Program.cs
WalletWasabi.Gui/Program.cs
@@ -10,6 +10,7 @@ using System.Threading.Tasks;
using WalletWasabi.Gui.CommandLine;
using WalletWasabi.Gui.ViewModels;
using WalletWasabi.Logging;
+using WalletWasabi.Gui.Controls.LockScreen;
namespace WalletWasabi.Gui
{

MODIFY
WalletWasabi.Gui/ViewModels/MainWindowViewModel.cs
WalletWasabi.Gui/ViewModels/MainWindowViewModel.cs
@@ -4,6 +4,7 @@ using AvalonStudio.Extensibility.Dialogs;
using AvalonStudio.Shell;
using ReactiveUI;
using System.Threading.Tasks;
+using WalletWasabi.Gui.Controls.LockScreen;
namespace WalletWasabi.Gui.ViewModels
{

Reimplemented locks as DataTemplates to abide more to MVVM principles. PIN lock working perfectly. SlideLock on progress.