Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Screen Lock implementation #1681

Merged
merged 71 commits into from Jul 23, 2019
Merged
Show file tree
Hide file tree
Changes from 66 commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
d6a25e7
Initial Implementation of Lock Screens.
jmacato Jul 1, 2019
c30192f
Cont'd implementation of slide lock..
jmacato Jul 2, 2019
f978386
Fix indent.
jmacato Jul 2, 2019
f1aa8c2
Add "Lock Screen" menu item
jmacato Jul 2, 2019
880e21e
Change easing to Quadtratic.
jmacato Jul 2, 2019
4030359
Add necessary UiConfig fields.
jmacato Jul 2, 2019
2fc2460
fix LockScreenCommands.
jmacato Jul 2, 2019
bb31fd2
Added LockScreenViewModel and a Simple lock screen for debugging purp…
jmacato Jul 2, 2019
be045df
Made the simple lock work
jmacato Jul 2, 2019
17ea5b4
Some fixes to SimpleLock
jmacato Jul 2, 2019
f3c26de
Fix lock screen persistence.
jmacato Jul 3, 2019
4419641
Basic infra for shuttling changes from UiConfig to Screen locks is done.
jmacato Jul 3, 2019
cb3f5af
Stray newline
jmacato Jul 3, 2019
8b09321
Fix codefactor issues
jmacato Jul 3, 2019
c9d5fb5
Fix SlideLock and add initial PINLock skeleton code.
jmacato Jul 3, 2019
29d559a
Disable menu when screenlocked.
jmacato Jul 3, 2019
5bd615f
Fix slidelock hittest
jmacato Jul 3, 2019
a580e2b
Implement PIN verification
jmacato Jul 3, 2019
bd7d301
Fix buggy hit testing.
jmacato Jul 6, 2019
6227694
Scaffold settings controls for screen lock
jmacato Jul 6, 2019
a46c983
Make better logic for handling PIN hash and determining what screen l…
jmacato Jul 7, 2019
d58ab23
More work on screen lock settings.
jmacato Jul 7, 2019
997c61d
Try adding validation on PIN entry
jmacato Jul 7, 2019
b3ce973
Remove unused SimpleLock.
jmacato Jul 11, 2019
7e45225
Rename LockScreenImpl to LockScreenBase since the former's name doesn…
jmacato Jul 11, 2019
4c77274
Fix CodeFactor issues.
jmacato Jul 11, 2019
98bb140
Fix merge conflicts from upstream.
jmacato Jul 11, 2019
efb4144
Use Observables for drag events.
jmacato Jul 11, 2019
fb75746
make LockScreen class public and rename lockscreenimpl.
jmacato Jul 13, 2019
f921429
Set Guard
jmacato Jul 13, 2019
ae7079e
Observe on main thread.
jmacato Jul 13, 2019
70be4a6
Convert 4spaces to tab
jmacato Jul 13, 2019
edaa175
Observe on main thread part 2.
jmacato Jul 13, 2019
67646d6
Update binding.
jmacato Jul 16, 2019
cf10e3e
PIN settings now fully functional.
jmacato Jul 16, 2019
2dd952c
Moving to MVVM part 1.
jmacato Jul 16, 2019
700d46d
Reimplemented locks as DataTemplates to abide more to MVVM principles…
jmacato Jul 17, 2019
7068232
Fix tabs and address CodeFactor issues.
jmacato Jul 17, 2019
1b54f66
Slide lock fully functional.
jmacato Jul 17, 2019
494bd10
Merge branch 'master' into pr/1681-screen-lock-implementation
nopara73 Jul 17, 2019
b2e40e6
CodeMaid
nopara73 Jul 17, 2019
a82c12e
Address review in SlideLock.
jmacato Jul 17, 2019
774f48e
Remove throttle in Pin lock check.
jmacato Jul 17, 2019
c886323
Add numbers on pin keypad
jmacato Jul 17, 2019
efe4cff
Only allow numbers on PIN entry.
jmacato Jul 17, 2019
f4e20ce
Address CodeFactor.
jmacato Jul 17, 2019
754ce6d
Focus on PIN input when locked;
jmacato Jul 17, 2019
925fbdb
Make SlideLock slide up when unlocking. Add a visual indicator below …
jmacato Jul 20, 2019
1c6cb9d
Merge branch 'master' into lockscreen-impl
nopara73 Jul 22, 2019
c259717
CodeMaid
nopara73 Jul 22, 2019
3bd8bee
fix xaml
nopara73 Jul 22, 2019
a358d1e
Make PIN capitalization C#-i.
nopara73 Jul 22, 2019
ce01bdb
Implement PIN settings properly.
nopara73 Jul 22, 2019
634b1fa
Put lockscreencommand into exitcommands
nopara73 Jul 22, 2019
8d0b10c
Simplify exception catching
nopara73 Jul 22, 2019
b547072
Change exit group to system group
nopara73 Jul 22, 2019
cbeba64
Exit1
nopara73 Jul 22, 2019
439fef5
cleanup trash
nopara73 Jul 22, 2019
a758c6a
CodeMaid
molnard Jul 22, 2019
0eadefe
Code clean
molnard Jul 23, 2019
7094fc7
Code clean
molnard Jul 23, 2019
ca2ea3b
Fix bug with Back button
molnard Jul 23, 2019
d17b4f6
Set the focus of passwordbox after app start.
molnard Jul 23, 2019
af1a414
Do not change focus on buttonpress.
molnard Jul 23, 2019
ce228eb
nitpicking
nopara73 Jul 23, 2019
25cebb5
Use Exit string on menuItem instead of Exi1
molnard Jul 23, 2019
8c14f17
Update comment
nopara73 Jul 23, 2019
bd8fa2a
Fix type fast => no validation
molnard Jul 23, 2019
8dd62f5
Fix mac deadlock.
molnard Jul 23, 2019
4dec275
Move Lock Screen button out of MainMenu
molnard Jul 23, 2019
5f8aa8a
Fix default order
molnard Jul 23, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions WalletWasabi.Gui/Controls/LockScreen/ILockScreenViewModel.cs
@@ -0,0 +1,8 @@
using System;

namespace WalletWasabi.Gui.Controls.LockScreen
{
public interface ILockScreenViewModel : IDisposable
{
}
}
14 changes: 14 additions & 0 deletions WalletWasabi.Gui/Controls/LockScreen/LockScreen.xaml
@@ -0,0 +1,14 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:lockscreen="clr-namespace:WalletWasabi.Gui.Controls.LockScreen;assembly=WalletWasabi.Gui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
IsHitTestVisible="{Binding IsLocked}">
<UserControl.DataTemplates>
<DataTemplate DataType="{x:Type lockscreen:PinLockScreenViewModel}">
<lockscreen:PinLockScreen />
</DataTemplate>
<DataTemplate DataType="{x:Type lockscreen:SlideLockScreenViewModel}">
<lockscreen:SlideLockScreen />
</DataTemplate>
</UserControl.DataTemplates>
<ContentControl Content="{Binding ActiveLockScreen}" />
</UserControl>
22 changes: 22 additions & 0 deletions WalletWasabi.Gui/Controls/LockScreen/LockScreen.xaml.cs
@@ -0,0 +1,22 @@
using System;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;

namespace WalletWasabi.Gui.Controls.LockScreen
{
public class LockScreen : UserControl
{
public LockScreen() : base()
{
InitializeComponent();
}

private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
74 changes: 74 additions & 0 deletions WalletWasabi.Gui/Controls/LockScreen/LockScreenViewModel.cs
@@ -0,0 +1,74 @@
using System;
using ReactiveUI;
using System.Reactive.Disposables;
using WalletWasabi.Helpers;
using System.Reactive.Linq;
using WalletWasabi.Gui.ViewModels;

namespace WalletWasabi.Gui.Controls.LockScreen
{
public class LockScreenViewModel : ViewModelBase
{
private CompositeDisposable Disposables { get; }

public Global Global { get; }

public LockScreenViewModel(Global global)
{
Global = Guard.NotNull(nameof(Global), global);
Disposables = new CompositeDisposable();
}

private ILockScreenViewModel _activeLockScreen;

public ILockScreenViewModel ActiveLockScreen
{
get => _activeLockScreen;
set => this.RaiseAndSetIfChanged(ref _activeLockScreen, value);
}

private ObservableAsPropertyHelper<string> _pinHash;
public string PinHash => _pinHash?.Value ?? default;

private bool _isLocked;

public bool IsLocked
{
get => _isLocked;
set => this.RaiseAndSetIfChanged(ref _isLocked, value);
}

public void Initialize()
{
Global.UiConfig.WhenAnyValue(x => x.LockScreenActive)
.ObserveOn(RxApp.MainThreadScheduler)
.BindTo(this, y => y.IsLocked)
.DisposeWith(Disposables);

this.WhenAnyValue(x => x.IsLocked)
.ObserveOn(RxApp.MainThreadScheduler)
.BindTo(Global.UiConfig, y => y.LockScreenActive)
.DisposeWith(Disposables);

_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);
}
else
{
ActiveLockScreen = new SlideLockScreenViewModel(this);
}
}
}
}
68 changes: 68 additions & 0 deletions WalletWasabi.Gui/Controls/LockScreen/PinLockScreen.xaml
@@ -0,0 +1,68 @@
<lockscreen:PinLockScreen xmlns="https://github.com/avaloniaui"
xmlns:controls="clr-namespace:WalletWasabi.Gui.Controls;assembly=WalletWasabi.Gui"
xmlns:lockscreen="clr-namespace:WalletWasabi.Gui.Controls.LockScreen;assembly=WalletWasabi.Gui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
IsLocked="{Binding IsLocked}">
<lockscreen:PinLockScreen.Styles>

<Style Selector="Grid.Shade">
<Setter Property="Opacity" Value="0" />
<Setter Property="TranslateTransform.Y" Value="-100" />
</Style>

<Style Selector="lockscreen|PinLockScreen[IsLocked=true] Grid.Shade">
<Style.Animations>
<Animation FillMode="Both" Duration="0:0:1.5" Easing="QuarticEaseInOut">
<KeyFrame Cue="100%">
<Setter Property="Opacity" Value="1" />
<Setter Property="TranslateTransform.Y" Value="0" />
</KeyFrame>
</Animation>
</Style.Animations>
</Style>

<Style Selector="lockscreen|PinLockScreen[IsLocked=false] Grid.Shade">
<Style.Animations>
<Animation FillMode="Both" Duration="0:0:1.5" Easing="QuarticEaseInOut">
<KeyFrame Cue="100%">
<Setter Property="Opacity" Value="0" />
<Setter Property="TranslateTransform.Y" Value="-100" />
</KeyFrame>
</Animation>
</Style.Animations>
</Style>
</lockscreen:PinLockScreen.Styles>
<Grid>
<Grid Classes="Shade" Background="{DynamicResource ThemeBackgroundBrush}">
<controls:GroupBox VerticalAlignment="Center" HorizontalAlignment="Center" TextBlock.FontSize="25" Padding="20" Margin="10">
<DockPanel LastChildFill ="True">
<controls:NoparaPasswordBox x:Name="InputField" Password="{Binding PinInput}" Width="300" DockPanel.Dock="Top" Margin="4 0 4 20" Watermark="PIN" UseFloatingWatermark="True" />
<Grid DockPanel.Dock="Bottom">
<TextBlock Text="Wrong PIN!"
Margin="0,12,0,0" VerticalAlignment="Center" FontSize="20" Classes="warningMessage" IsVisible="{Binding WarningMessageVisible}" />
</Grid>
<Grid RowDefinitions="*,*,*,*" ColumnDefinitions="*,*,*">
<Grid.Styles>
<Style Selector="Button">
<Setter Property="Margin" Value="4" />
<Setter Property="Focusable" Value="False" />
</Style>
</Grid.Styles>
<Button Grid.Row="0" Grid.Column="0" Content="7" Command="{Binding KeyPadCommand}" CommandParameter="7" />
<Button Grid.Row="0" Grid.Column="1" Content="8" Command="{Binding KeyPadCommand}" CommandParameter="8" />
<Button Grid.Row="0" Grid.Column="2" Content="9" Command="{Binding KeyPadCommand}" CommandParameter="9" />
<Button Grid.Row="1" Grid.Column="0" Content="4" Command="{Binding KeyPadCommand}" CommandParameter="4" />
<Button Grid.Row="1" Grid.Column="1" Content="5" Command="{Binding KeyPadCommand}" CommandParameter="5" />
<Button Grid.Row="1" Grid.Column="2" Content="6" Command="{Binding KeyPadCommand}" CommandParameter="6" />
<Button Grid.Row="2" Grid.Column="0" Content="1" Command="{Binding KeyPadCommand}" CommandParameter="1" />
<Button Grid.Row="2" Grid.Column="1" Content="2" Command="{Binding KeyPadCommand}" CommandParameter="2" />
<Button Grid.Row="2" Grid.Column="2" Content="3" Command="{Binding KeyPadCommand}" CommandParameter="3" />
<Button Grid.Row="3" Grid.Column="0" Content="CLEAR" Command="{Binding KeyPadCommand}" CommandParameter="CLEAR" />
<Button Grid.Row="3" Grid.Column="1" Content="0" Command="{Binding KeyPadCommand}" CommandParameter="0" />
<Button Grid.Row="3" Grid.Column="2" Content="BACK" Command="{Binding KeyPadCommand}" CommandParameter="BACK" />
</Grid>
</DockPanel>
</controls:GroupBox>
</Grid>
</Grid>
</lockscreen:PinLockScreen>
61 changes: 61 additions & 0 deletions WalletWasabi.Gui/Controls/LockScreen/PinLockScreen.xaml.cs
@@ -0,0 +1,61 @@
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 PinLockScreen : UserControl
{
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 bool IsLocked
{
get => _isLocked;
set => SetAndRaise(IsLockedProperty, ref _isLocked, value);
}

public PinLockScreen() : base()
{
InitializeComponent();

var inputField = this.FindControl<NoparaPasswordBox>("InputField");

this.WhenAnyValue(x => x.IsLocked)
.Where(x => x)
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(x => inputField.Focus());
}

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(x =>
{
var inputField = this.FindControl<NoparaPasswordBox>("InputField");
inputField.Focus();
});
}

private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}
99 changes: 99 additions & 0 deletions WalletWasabi.Gui/Controls/LockScreen/PinLockScreenViewModel.cs
@@ -0,0 +1,99 @@
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
{
public class PinLockScreenViewModel : ViewModelBase, ILockScreenViewModel
{
private LockScreenViewModel _parentVM;

private CompositeDisposable Disposables { get; }

public ReactiveCommand<string, Unit> KeyPadCommand { get; }

private 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) =>
{
if (arg == "BACK")
jmacato marked this conversation as resolved.
Show resolved Hide resolved
{
if (PinInput.Length > 0)
{
PinInput = PinInput.Substring(0, PinInput.Length - 1);
WarningMessageVisible = false;
}
}
else if (arg == "CLEAR")
{
PinInput = string.Empty;
WarningMessageVisible = false;
}
else
{
PinInput += arg;
}
});

this.WhenAnyValue(x => x.PinInput)
.Throttle(TimeSpan.FromSeconds(0.5))
.Select(Guard.Correct)
.Where(x => x != string.Empty)
.ObserveOn(RxApp.MainThreadScheduler)
.Do(x => 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()
{
Disposables?.Dispose();
}
}
}