Remove all complexity from lockscreen.
MODIFY
WalletWasabi.Gui/Controls/LockScreen/LockScreenViewModelBase.cs
WalletWasabi.Gui/Controls/LockScreen/LockScreenViewModelBase.cs
-using System;
using ReactiveUI;
+using Splat;
using System.Reactive.Disposables;
-using WalletWasabi.Helpers;
using System.Reactive.Linq;
using WalletWasabi.Gui.ViewModels;
-using Splat;
namespace WalletWasabi.Gui.Controls.LockScreen
{
public abstract class LockScreenViewModelBase : ViewModelBase
{
private bool _isLocked;
+ private bool _canSlide;
+
private CompositeDisposable Disposables { get; }
public LockScreenViewModelBase()
@@ -35,12 +35,21 @@ namespace WalletWasabi.Gui.Controls.LockScreen
OnInitialise(Disposables);
}
+ public bool CanSlide
+ {
+ get { return _canSlide; }
+ set { this.RaiseAndSetIfChanged(ref _canSlide, value); }
+ }
+
public bool IsLocked
{
get => _isLocked;
set => this.RaiseAndSetIfChanged(ref _isLocked, value);
}
- protected abstract void OnInitialise(CompositeDisposable disposables);
+ protected virtual void OnInitialise(CompositeDisposable disposables)
+ {
+
+ }
}
}

MODIFY
WalletWasabi.Gui/Controls/LockScreen/PinLockScreenView.xaml
WalletWasabi.Gui/Controls/LockScreen/PinLockScreenView.xaml
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:WalletWasabi.Gui.Controls;assembly=WalletWasabi.Gui"
xmlns:lockscreen="clr-namespace:WalletWasabi.Gui.Controls.LockScreen;assembly=WalletWasabi.Gui"
- x:Class="WalletWasabi.Gui.Controls.LockScreen.PinLockScreenView"
- IsLocked="{Binding IsLocked}">
- <lockscreen:PinLockScreenView.Styles>
- <Style Selector="lockscreen|PinLockScreenView[IsLocked=true] Grid.Shade">
- <Style.Animations>
- <Animation FillMode="Both" Duration="0:0:1.5" Easing="QuarticEaseInOut">
- <KeyFrame Cue="0%">
- <Setter Property="IsVisible" Value="True" />
- <Setter Property="TranslateTransform.Y" Value="-100" />
- <Setter Property="Opacity" Value="0" />
- </KeyFrame>
- <KeyFrame Cue="100%">
- <Setter Property="Opacity" Value="1" />
- <Setter Property="TranslateTransform.Y" Value="0" />
- <Setter Property="IsVisible" Value="True" />
- </KeyFrame>
- </Animation>
- </Style.Animations>
- </Style>
- <Style Selector="lockscreen|PinLockScreenView[IsLocked=false] Grid.Shade">
- <Style.Animations>
- <Animation FillMode="Both" Duration="0:0:1.5" Easing="QuarticEaseInOut">
- <KeyFrame Cue="99%">
- <Setter Property="IsVisible" Value="True" />
- </KeyFrame>
- <KeyFrame Cue="100%">
- <Setter Property="IsVisible" Value="False" />
- <Setter Property="Opacity" Value="0" />
- <Setter Property="TranslateTransform.Y" Value="-100" />
- </KeyFrame>
- </Animation>
- </Style.Animations>
- </Style>
- </lockscreen:PinLockScreenView.Styles>
- <Grid>
- <Grid Classes="Shade" Background="{DynamicResource ThemeBackgroundBrush}">
+ x:Class="WalletWasabi.Gui.Controls.LockScreen.PinLockScreenView">
+ <Grid Background="{DynamicResource ThemeBackgroundBrush}">
<controls:GroupBox VerticalAlignment="Center" HorizontalAlignment="Center" TextBlock.FontSize="25" Padding="20" Margin="10">
<DockPanel LastChildFill="True">
<controls:TogglePasswordBox x:Name="InputField" Text="{Binding PinInput}" Width="300" DockPanel.Dock="Top" Margin="4 0 4 20" Watermark="PIN" />
</DockPanel>
</controls:GroupBox>
</Grid>
- </Grid>
</lockscreen:PinLockScreenView>

MODIFY
WalletWasabi.Gui/Controls/LockScreen/PinLockScreenView.xaml.cs
WalletWasabi.Gui/Controls/LockScreen/PinLockScreenView.xaml.cs
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
-using Avalonia;
-using Avalonia.Input;
-using ReactiveUI;
-using System.Reactive.Linq;
-using System;
-using Avalonia.LogicalTree;
namespace WalletWasabi.Gui.Controls.LockScreen
{
public class PinLockScreenView : UserControl
{
- public static readonly DirectProperty<PinLockScreenView, bool> IsLockedProperty =
- AvaloniaProperty.RegisterDirect<PinLockScreenView, bool>(nameof(IsLocked), o => o.IsLocked, (o, v) => o.IsLocked = v);
-
- private bool _isLocked;
-
- public bool IsLocked
- {
- get => _isLocked;
- set => SetAndRaise(IsLockedProperty, ref _isLocked, value);
- }
-
- public PinLockScreenView() : base()
+ public PinLockScreenView()
{
InitializeComponent();
-
- var inputField = this.FindControl<TogglePasswordBox>("InputField");
-
- this.WhenAnyValue(x => x.IsLocked)
- .Where(x => x)
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(_ =>
- {
- inputField.Text = string.Empty;
- inputField.Focus();
- });
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
-
- protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
- {
- base.OnAttachedToVisualTree(e);
-
- // When the control first created on AppStart set the Focus of the password box.
- // If you just simply set the Focus without delay it won't work.
- Observable
- .Interval(TimeSpan.FromSeconds(1))
- .Take(1)
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(_ =>
- {
- var inputField = this.FindControl<TogglePasswordBox>("InputField");
- inputField.Focus();
- });
- }
}
}

MODIFY
WalletWasabi.Gui/Controls/LockScreen/PinLockScreenViewModel.cs
WalletWasabi.Gui/Controls/LockScreen/PinLockScreenViewModel.cs
-using WalletWasabi.Gui.ViewModels;
-using WalletWasabi.Helpers;
+using ReactiveUI;
+using Splat;
using System;
using System.Reactive;
-using ReactiveUI;
-using System.Reactive.Disposables;
using System.Reactive.Linq;
using WalletWasabi.Gui.Helpers;
+using WalletWasabi.Helpers;
using WalletWasabi.Logging;
-using Splat;
namespace WalletWasabi.Gui.Controls.LockScreen
{
@@ -75,11 +73,6 @@ namespace WalletWasabi.Gui.Controls.LockScreen
.Subscribe(_ => PinInput = string.Empty);
}
- protected override void OnInitialise(CompositeDisposable disposables)
- {
- var global = Locator.Current.GetService<Global>();
- }
-
public string PinInput
{
get => _pinInput;

MODIFY
WalletWasabi.Gui/Controls/LockScreen/SlideLock.cs
WalletWasabi.Gui/Controls/LockScreen/SlideLock.cs
-using System;
-using System.Threading.Tasks;
using Avalonia;
using Avalonia.Animation;
using Avalonia.Animation.Easings;
@@ -7,6 +5,7 @@ using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Styling;
using Avalonia.Utilities;
+using System;
namespace WalletWasabi.Gui.Controls.LockScreen
{
@@ -17,29 +16,12 @@ namespace WalletWasabi.Gui.Controls.LockScreen
private bool _isLocked;
private Animation _closeAnimation;
private Animation _openAnimation;
+ private bool _canSlide;
+ private double _threshold;
- // Threshold
-
- // Trigger animations to slide up and down
-
- // enable or disable mouse control
-
- public static readonly DirectProperty<SlideLockScreenView, bool> IsLockedProperty =
- AvaloniaProperty.RegisterDirect<SlideLockScreenView, bool>(nameof(IsLocked), o => o.IsLocked, (o, v) => o.IsLocked = v);
-
- public bool IsLocked
- {
- get => _isLocked;
- set => SetAndRaise(IsLockedProperty, ref _isLocked, value);
- }
-
- public static readonly StyledProperty<double> ValueProperty =
- AvaloniaProperty.Register<SlideLock, double>(nameof(Value));
-
- public double Value
+ static SlideLock()
{
- get => GetValue(ValueProperty);
- set => SetValue(ValueProperty, value);
+ AffectsArrange<SlideLock>(ValueProperty);
}
public SlideLock()
@@ -49,23 +31,11 @@ namespace WalletWasabi.Gui.Controls.LockScreen
_closeAnimation = new Animation
{
- Duration = TimeSpan.FromSeconds(2.0),
+ Duration = TimeSpan.FromSeconds(1),
Easing = new BounceEaseOut(),
FillMode = FillMode.Both,
Children =
{
- new KeyFrame
- {
- Setters =
- {
- new Setter
- {
- Property = SlideLock.ValueProperty,
- Value = 0d
- }
- },
- Cue = new Cue(0d)
- },
new KeyFrame
{
Setters =
@@ -83,7 +53,7 @@ namespace WalletWasabi.Gui.Controls.LockScreen
_openAnimation = new Animation
{
- Duration = TimeSpan.FromSeconds(2.0),
+ Duration = TimeSpan.FromSeconds(1),
Easing = new QuadraticEaseInOut(),
FillMode = FillMode.Both,
Children =
@@ -102,11 +72,55 @@ namespace WalletWasabi.Gui.Controls.LockScreen
}
}
};
+
+ this.GetObservable(IsLockedProperty)
+ .Subscribe(async x =>
+ {
+ if (x)
+ {
+ await _closeAnimation.RunAsync(this);
+ }
+ else
+ {
+ await _openAnimation.RunAsync(this);
+ }
+ });
}
- static SlideLock()
+ public static readonly DirectProperty<SlideLock, bool> CanSlideProperty =
+ AvaloniaProperty.RegisterDirect<SlideLock, bool>(nameof(CanSlide), o => o.CanSlide, (o, v) => o.CanSlide = v);
+
+ public bool CanSlide
{
- AffectsArrange<SlideLock>(ValueProperty);
+ get => _canSlide;
+ set => SetAndRaise(CanSlideProperty, ref _canSlide, value);
+ }
+
+ public static readonly DirectProperty<SlideLock, double> ThresholdProperty =
+ AvaloniaProperty.RegisterDirect<SlideLock, double>(nameof(Threshold), o => o.Threshold, (o,v)=> o.Threshold = v);
+
+ public double Threshold
+ {
+ get => _threshold;
+ set => SetAndRaise(ThresholdProperty, ref _threshold, value);
+ }
+
+ public static readonly DirectProperty<SlideLock, bool> IsLockedProperty =
+ AvaloniaProperty.RegisterDirect<SlideLock, bool>(nameof(IsLocked), o => o.IsLocked, (o, v) => o.IsLocked = v);
+
+ public bool IsLocked
+ {
+ get => _isLocked;
+ set => SetAndRaise(IsLockedProperty, ref _isLocked, value);
+ }
+
+ public static readonly StyledProperty<double> ValueProperty =
+ AvaloniaProperty.Register<SlideLock, double>(nameof(Value));
+
+ public double Value
+ {
+ get => GetValue(ValueProperty);
+ set => SetValue(ValueProperty, value);
}
protected override Size ArrangeOverride(Size finalSize)
@@ -118,26 +132,38 @@ namespace WalletWasabi.Gui.Controls.LockScreen
return result;
}
- protected override async void OnTemplateApplied(TemplateAppliedEventArgs e)
+ protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
base.OnTemplateApplied(e);
_thumb = e.NameScope.Find<Thumb>("PART_Thumb");
_container = e.NameScope.Find<Grid>("PART_Container");
+ this.GetObservable(CanSlideProperty)
+ .Subscribe(x =>
+ {
+ _thumb.IsHitTestVisible = x;
+ });
+
_thumb.DragDelta += OnThumb_DragDelta;
_thumb.DragCompleted += OnThumb_DragCompleted;
-
- await _closeAnimation.RunAsync(this);
}
private void OnThumb_DragCompleted(object sender, Avalonia.Input.VectorEventArgs e)
{
- if(Value <= 75)
+ if (CanSlide)
{
+ if (Value <= Threshold)
+ {
+ IsLocked = false;
_openAnimation.RunAsync(this);
}
+ else
+ {
+ _closeAnimation.RunAsync(this);
+ }
+ }
}
private double DistanceToValue(double distance)
@@ -151,6 +177,8 @@ namespace WalletWasabi.Gui.Controls.LockScreen
}
private void OnThumb_DragDelta(object sender, Avalonia.Input.VectorEventArgs e)
+ {
+ if (CanSlide)
{
var deltaValue = DistanceToValue(e.Vector.Y);
@@ -158,3 +186,4 @@ namespace WalletWasabi.Gui.Controls.LockScreen
}
}
}
+}

MODIFY
WalletWasabi.Gui/Controls/LockScreen/SlideLockScreenView.xaml.cs
WalletWasabi.Gui/Controls/LockScreen/SlideLockScreenView.xaml.cs
-using System;
-using System.Collections.Generic;
-using Avalonia.Media;
-using Avalonia.Input;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
-using Avalonia.Controls.Primitives;
-using ReactiveUI;
-using Avalonia;
-using System.Reactive.Linq;
-using System.Reactive.Disposables;
namespace WalletWasabi.Gui.Controls.LockScreen
{
public class SlideLockScreenView : UserControl
{
- public static readonly DirectProperty<SlideLockScreenView, bool> IsLockedProperty =
- AvaloniaProperty.RegisterDirect<SlideLockScreenView, bool>(nameof(IsLocked), o => o.IsLocked, (o, v) => o.IsLocked = v);
-
- private bool _isLocked;
-
- public bool IsLocked
- {
- get => _isLocked;
- set => SetAndRaise(IsLockedProperty, ref _isLocked, value);
- }
-
- public static readonly DirectProperty<SlideLockScreenView, double> OffsetProperty =
- AvaloniaProperty.RegisterDirect<SlideLockScreenView, double>(nameof(Offset), o => o.Offset, (o, v) => o.Offset = v);
-
- private double _offset;
-
- public double Offset
- {
- get => _offset;
- set => SetAndRaise(OffsetProperty, ref _offset, value);
- }
-
- public static readonly DirectProperty<SlideLockScreenView, bool> DoneAnimatingProperty =
- AvaloniaProperty.RegisterDirect<SlideLockScreenView, bool>(nameof(DoneAnimating), o => o.DoneAnimating, (o, v) => o.DoneAnimating = v);
-
- private bool _doneAnimating;
-
- public bool DoneAnimating
- {
- get => _doneAnimating;
- set => SetAndRaise(DoneAnimatingProperty, ref _doneAnimating, value);
- }
-
- private TranslateTransform TargetTransform { get; } = new TranslateTransform();
- private Thumb DragThumb { get; }
-
public SlideLockScreenView()
{
InitializeComponent();
-
- DragThumb = this.FindControl<Thumb>("PART_DragThumb");
- this.FindControl<Grid>("Shade").RenderTransform = TargetTransform;
-
- DataContextChanged += delegate
- {
- if (DataContext is SlideLockScreenViewModel)
- {
- OnDataContextChanged();
- }
- };
-
- this.GetObservable(OffsetProperty)
- .Subscribe(x =>
- {
- if (Bounds.Height > 0)
- {
- Opacity = ((Bounds.Height - -x) / Bounds.Height);
- }
- });
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
-
- public void OnDataContextChanged()
- {
- var vm = DataContext as SlideLockScreenViewModel;
-
- this.WhenAnyValue(x => x.Offset)
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(x => TargetTransform.Y = x)
- ;//.DisposeWith(vm.Disposables);
-
- this.WhenAnyValue(x => x.Bounds)
- .Select(x => x.Height)
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(x => vm.BoundsHeight = x)
- ;//.DisposeWith(vm.Disposables);
-
- this.WhenAnyValue(x => x.DoneAnimating)
- .Where(x => x)
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(_ => vm.StateChanged = false)
- ;//.DisposeWith(vm.Disposables);
-
- Observable.FromEventPattern(DragThumb, nameof(DragThumb.DragCompleted))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(_ => vm.IsUserDragging = false)
- ;//.DisposeWith(vm.Disposables);
-
- Observable.FromEventPattern(DragThumb, nameof(DragThumb.DragStarted))
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(_ => vm.IsUserDragging = true)
- ;//.DisposeWith(vm.Disposables);
-
- Observable.FromEventPattern<VectorEventArgs>(DragThumb, nameof(DragThumb.DragDelta))
- .Where(e => e.EventArgs.Vector.Y < 0)
- .Select(e => e.EventArgs.Vector.Y)
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(x => vm.Offset = x)
- ;//.DisposeWith(vm.Disposables);
-
- vm.WhenAnyValue(x => x.StateChanged)
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(x =>
- {
- if (x)
- {
- Classes.Add("statechanged");
- }
- else
- {
- Classes.Remove("statechanged");
- }
- })
- ;//.DisposeWith(vm.Disposables);
-
- Clock.ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(vm.OnClockTick)
- ;//.DisposeWith(vm.Disposables);
- }
}
}

MODIFY
WalletWasabi.Gui/Controls/LockScreen/SlideLockScreenViewModel.cs
WalletWasabi.Gui/Controls/LockScreen/SlideLockScreenViewModel.cs
-using WalletWasabi.Gui.ViewModels;
-using WalletWasabi.Helpers;
-using System;
-using ReactiveUI;
-using System.Reactive.Disposables;
-using System.Reactive.Linq;
-using Avalonia;
-
namespace WalletWasabi.Gui.Controls.LockScreen
{
public class SlideLockScreenViewModel : LockScreenViewModelBase
{
- private enum SlideLockState
- {
- Idle,
- UserIsDragging,
- UserDragPassedThreshold
- }
-
- private SlideLockState _state = SlideLockState.Idle;
-
-
- private bool _isUserDragging;
-
- public bool IsUserDragging
- {
- get => _isUserDragging;
- set => this.RaiseAndSetIfChanged(ref _isUserDragging, value);
- }
-
- private double _boundsHeight;
-
- public double BoundsHeight
- {
- get => _boundsHeight;
- set => this.RaiseAndSetIfChanged(ref _boundsHeight, value);
- }
-
- private double _targetOffset;
-
- public double TargetOffset
- {
- get => _targetOffset;
- set => this.RaiseAndSetIfChanged(ref _targetOffset, value);
- }
-
- public double Threshold => BoundsHeight * ThresholdPercent;
-
- private double _targetOpacity;
-
- public double TargetOpacity
- {
- get => _targetOpacity;
- set => this.RaiseAndSetIfChanged(ref _targetOpacity, value);
- }
-
- private double _offset;
-
- public double Offset
- {
- get => _offset;
- set => this.RaiseAndSetIfChanged(ref _offset, value);
- }
-
- private bool _stateChanged;
-
- public bool StateChanged
- {
- get => _stateChanged;
- set => this.RaiseAndSetIfChanged(ref _stateChanged, value);
- }
-
public readonly double ThresholdPercent = 1 / 6d;
- public readonly double Stiffness = 0.12d;
-
- protected override void OnInitialise(CompositeDisposable disposables)
- {
- this.WhenAnyValue(x => x.TargetOffset)
- .DistinctUntilChanged()
- .ObserveOn(RxApp.MainThreadScheduler)
- .Subscribe(_ =>
- {
- StateChanged = false;
- StateChanged = true;
- })
- .DisposeWith(disposables);
- }
-
- internal void OnClockTick(TimeSpan _)
- {
- switch (_state)
- {
- case SlideLockState.Idle:
- if (IsUserDragging)
+ public SlideLockScreenViewModel()
{
- _state = SlideLockState.UserIsDragging;
- return;
- }
-
- if (IsLocked)
- {
- TargetOffset = 0;
- TargetOpacity = 1;
- Offset *= 1 - Stiffness;
- }
- else
- {
- TargetOpacity = 0;
- TargetOffset = -BoundsHeight;
- }
-
- break;
-
- case SlideLockState.UserIsDragging:
- if (!IsUserDragging)
- {
- _state = Math.Abs(Offset) > Threshold ? SlideLockState.UserDragPassedThreshold : SlideLockState.Idle;
- }
- break;
-
- case SlideLockState.UserDragPassedThreshold:
- IsLocked = false;
- _state = SlideLockState.Idle;
- break;
- }
+ CanSlide = true;
}
}
}

Remove all complexity from lockscreen.