diff --git a/src/App/App.csproj b/src/App/App.csproj index b242631d4..a57043e39 100644 --- a/src/App/App.csproj +++ b/src/App/App.csproj @@ -60,6 +60,7 @@ + diff --git a/src/App/Controls/ExtendedEntry.cs b/src/App/Controls/ExtendedEntry.cs index a6e1c0bb9..62b8270cd 100644 --- a/src/App/Controls/ExtendedEntry.cs +++ b/src/App/Controls/ExtendedEntry.cs @@ -47,7 +47,6 @@ namespace Bit.App.Controls set { SetValue(MaxLengthProperty, value); } } - public ReturnType? ReturnType { get; set; } public bool? Autocorrect { get; set; } public bool DisableAutocapitalize { get; set; } diff --git a/src/App/Controls/PinControl.cs b/src/App/Controls/PinControl.cs new file mode 100644 index 000000000..8b9a11907 --- /dev/null +++ b/src/App/Controls/PinControl.cs @@ -0,0 +1,45 @@ +using System; +using Bit.App.Models.Page; +using Xamarin.Forms; + +namespace Bit.App.Controls +{ + public class PinControl + { + private Action _pinEnteredAction; + + public PinControl(Action pinEnteredAction) + { + _pinEnteredAction = pinEnteredAction; + + Label = new Label + { + HorizontalTextAlignment = TextAlignment.Center, + FontSize = 30, + TextColor = Color.FromHex("333333"), + FontFamily = "Courier" + }; + Label.SetBinding(Label.TextProperty, s => s.LabelText); + + Entry = new ExtendedEntry + { + Keyboard = Keyboard.Numeric, + IsVisible = false, + MaxLength = 4 + }; + Entry.SetBinding(Xamarin.Forms.Entry.TextProperty, s => s.PIN); + Entry.TextChanged += PinEntry_TextChanged; + } + + private void PinEntry_TextChanged(object sender, TextChangedEventArgs e) + { + if(e.NewTextValue.Length >= 4) + { + _pinEnteredAction(); + } + } + + public Label Label { get; set; } + public ExtendedEntry Entry { get; set; } + } +} diff --git a/src/App/Models/Page/PinPageModel.cs b/src/App/Models/Page/PinPageModel.cs index d3819a877..e04e59755 100644 --- a/src/App/Models/Page/PinPageModel.cs +++ b/src/App/Models/Page/PinPageModel.cs @@ -6,33 +6,32 @@ namespace Bit.App.Models.Page { public class PinPageModel : INotifyPropertyChanged { - private string _labelText; - private List _pin; - - public PinPageModel() - { - LabelText = "_ _ _ _"; - PIN = new List(); - } + private string _pin = string.Empty; public event PropertyChangedEventHandler PropertyChanged; public string LabelText { - get { return _labelText; } - set + get { - _labelText = value; - PropertyChanged(this, new PropertyChangedEventArgs(nameof(LabelText))); + var newText = string.Empty; + for(int i = 0; i < 4; i++) + { + newText += _pin.Length <= i ? "- " : "● "; + } + + return newText.TrimEnd(); } } - public List PIN + + public string PIN { get { return _pin; } set { _pin = value; PropertyChanged(this, new PropertyChangedEventArgs(nameof(PIN))); + PropertyChanged(this, new PropertyChangedEventArgs(nameof(LabelText))); } } } diff --git a/src/App/Pages/LockPinPage.cs b/src/App/Pages/LockPinPage.cs index 2e22b672f..b8960d0fa 100644 --- a/src/App/Pages/LockPinPage.cs +++ b/src/App/Pages/LockPinPage.cs @@ -8,6 +8,8 @@ using XLabs.Ioc; using Plugin.Settings.Abstractions; using System.Collections.Generic; using Bit.App.Models.Page; +using Bit.App.Controls; +using System.Diagnostics; namespace Bit.App.Pages { @@ -27,43 +29,11 @@ namespace Bit.App.Pages } public PinPageModel Model { get; set; } = new PinPageModel(); + public PinControl PinControl { get; set; } public void Init() { - var label = new Label - { - HorizontalTextAlignment = TextAlignment.Center, - FontSize = 40, - TextColor = Color.FromHex("333333") - }; - label.SetBinding(Label.TextProperty, s => s.LabelText); - - var grid = new Grid(); - grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); - grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); - grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); - grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); - - grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); - grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); - grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) }); - - Action updateLabelAction = new Action(UpdateLabel); - grid.Children.Add(new PinButton("1", this, updateLabelAction), 0, 0); - grid.Children.Add(new PinButton("2", this, updateLabelAction), 1, 0); - grid.Children.Add(new PinButton("3", this, updateLabelAction), 2, 0); - - grid.Children.Add(new PinButton("4", this, updateLabelAction), 0, 1); - grid.Children.Add(new PinButton("5", this, updateLabelAction), 1, 1); - grid.Children.Add(new PinButton("6", this, updateLabelAction), 2, 1); - - grid.Children.Add(new PinButton("7", this, updateLabelAction), 0, 2); - grid.Children.Add(new PinButton("8", this, updateLabelAction), 1, 2); - grid.Children.Add(new PinButton("9", this, updateLabelAction), 2, 2); - - grid.Children.Add(new Label(), 0, 3); - grid.Children.Add(new PinButton("0", this, updateLabelAction), 1, 3); - grid.Children.Add(new DeleteButton(this, updateLabelAction), 2, 3); + PinControl = new PinControl(PinEntered); var logoutButton = new Button { @@ -76,7 +46,7 @@ namespace Bit.App.Pages { Padding = new Thickness(30, 40), Spacing = 10, - Children = { label, grid, logoutButton } + Children = { PinControl.Label, PinControl.Entry, logoutButton } }; Title = "Verify PIN"; @@ -87,6 +57,22 @@ namespace Bit.App.Pages protected override void OnAppearing() { base.OnAppearing(); + PinControl.Entry.Focus(); + } + + protected void PinEntered() + { + if(Model.PIN == "1234") + { + PinControl.Entry.Unfocus(); + Navigation.PopModalAsync(); + } + else + { + _userDialogs.Alert("Invalid PIN. Try again."); + Model.PIN = string.Empty; + PinControl.Entry.Focus(); + } } private async Task LogoutAsync() @@ -100,60 +86,5 @@ namespace Bit.App.Pages await Navigation.PopModalAsync(); Application.Current.MainPage = new LoginNavigationPage(); } - - private void UpdateLabel() - { - var newText = string.Empty; - for(int i = 0; i < 4; i++) - { - if(Model.PIN.Count <= i) - { - newText += "_ "; - } - else - { - newText += "* "; - } - } - - Model.LabelText = newText.TrimEnd(); - } - - public class PinButton : Button - { - public PinButton(string text, LockPinPage page, Action updateLabelAction) - { - Text = text; - Command = new Command(() => - { - if(page.Model.PIN.Count >= 4) - { - return; - } - - page.Model.PIN.Add(text); - updateLabelAction(); - }); - CommandParameter = text; - } - } - - public class DeleteButton : Button - { - public DeleteButton(LockPinPage page, Action updateLabelAction) - { - Text = "Delete"; - Command = new Command(() => - { - if(page.Model.PIN.Count == 0) - { - return; - } - - page.Model.PIN.RemoveAt(page.Model.PIN.Count - 1); - updateLabelAction(); - }); - } - } } } diff --git a/src/iOS/Controls/ExtendedEntryRenderer.cs b/src/iOS/Controls/ExtendedEntryRenderer.cs index 241479dd5..fbc2403e0 100644 --- a/src/iOS/Controls/ExtendedEntryRenderer.cs +++ b/src/iOS/Controls/ExtendedEntryRenderer.cs @@ -23,6 +23,7 @@ namespace Bit.iOS.Controls { SetBorder(view); SetMaxLength(view); + UpdateKeyboard(); if(view.DisableAutocapitalize) { @@ -79,6 +80,10 @@ namespace Bit.iOS.Controls { SetBorder(view); } + else if(e.PropertyName == Xamarin.Forms.InputView.KeyboardProperty.PropertyName) + { + UpdateKeyboard(); + } } private void SetBorder(ExtendedEntry view) @@ -112,5 +117,17 @@ namespace Bit.iOS.Controls return newLength <= view.MaxLength; }; } + + private void UpdateKeyboard() + { + if(Element.Keyboard == Keyboard.Numeric) + { + Control.KeyboardType = UIKeyboardType.NumberPad; + } + else + { + Control.ApplyKeyboard(Element.Keyboard); + } + } } }