generator UI elements

This commit is contained in:
Kyle Spearrin 2019-05-13 14:43:23 -04:00
parent 28473dd85f
commit 018a7c9f96
3 changed files with 351 additions and 42 deletions

View file

@ -22,35 +22,174 @@
Order="Secondary" /> Order="Secondary" />
</ContentPage.ToolbarItems> </ContentPage.ToolbarItems>
<StackLayout Spacing="20"> <ContentPage.Resources>
<StackLayout StyleClass="box"> <ResourceDictionary>
<controls:MonoLabel <u:InverseBoolConverter x:Key="inverseBool" />
Text="{Binding Password}" </ResourceDictionary>
Margin="0, 20" </ContentPage.Resources>
StyleClass="text-lg"
HorizontalOptions="Center" /> <ScrollView>
<StackLayout Orientation="Horizontal"> <StackLayout Spacing="20">
<Button Text="{u:I18n RegeneratePassword}" <StackLayout StyleClass="box">
HorizontalOptions="FillAndExpand" <controls:MonoLabel
Clicked="Regenerate_Clicked"></Button> Text="{Binding Password}"
<Button Text="{u:I18n CopyPassword}" Margin="0, 20"
HorizontalOptions="FillAndExpand" StyleClass="text-lg"
Clicked="Copy_Clicked"></Button> HorizontalOptions="Center" />
<StackLayout Orientation="Horizontal">
<Button Text="{u:I18n RegeneratePassword}"
HorizontalOptions="FillAndExpand"
Clicked="Regenerate_Clicked"></Button>
<Button Text="{u:I18n CopyPassword}"
HorizontalOptions="FillAndExpand"
Clicked="Copy_Clicked"></Button>
</StackLayout>
</StackLayout> </StackLayout>
<StackLayout StyleClass="box-row-header"> <StackLayout StyleClass="box">
<Label Text="{u:I18n Options}" <StackLayout StyleClass="box-row-header">
StyleClass="box-header, box-header-platform" /> <Label Text="{u:I18n Options}"
</StackLayout> StyleClass="box-header, box-header-platform" />
<StackLayout StyleClass="box-row, box-row-input"> </StackLayout>
<Label <StackLayout StyleClass="box-row, box-row-input">
Text="{u:I18n Type}" <Label
StyleClass="box-label" /> Text="{u:I18n Type}"
<Picker StyleClass="box-label" />
ItemsSource="{Binding TypeOptions, Mode=OneTime}" <Picker
SelectedIndex="{Binding TypeSelectedIndex}" ItemsSource="{Binding TypeOptions, Mode=OneTime}"
StyleClass="box-value" /> SelectedIndex="{Binding TypeSelectedIndex}"
StyleClass="box-value" />
</StackLayout>
<StackLayout Spacing="0"
Padding="0"
IsVisible="{Binding IsPassword, Converter={StaticResource inverseBool}}">
<StackLayout StyleClass="box-row, box-row-stepper">
<Label
Text="{u:I18n NumberOfWords}"
StyleClass="box-label, box-label-regular"
VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center" />
<Label
Text="{Binding NumWords}"
StyleClass="box-label, box-sub-label"
HorizontalOptions="FillAndExpand"
HorizontalTextAlignment="End"
VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center" />
<Stepper
Value="{Binding NumWords}"
Minimum="3"
Maximum="20"
Increment="1" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
<StackLayout StyleClass="box-row, box-row-input">
<Label
Text="{u:I18n WordSeparator}"
StyleClass="box-label" />
<Entry
Text="{Binding WordSeparator}"
StyleClass="box-value" />
</StackLayout>
</StackLayout>
<StackLayout Spacing="0" Padding="0" IsVisible="{Binding IsPassword}">
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="A-Z"
StyleClass="box-label, box-label-regular"
HorizontalOptions="StartAndExpand" />
<Switch
IsToggled="{Binding Uppercase}"
StyleClass="box-value"
HorizontalOptions="End" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="a-z"
StyleClass="box-label, box-label-regular"
HorizontalOptions="StartAndExpand" />
<Switch
IsToggled="{Binding Lowercase}"
StyleClass="box-value"
HorizontalOptions="End" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="0-9"
StyleClass="box-label, box-label-regular"
HorizontalOptions="StartAndExpand" />
<Switch
IsToggled="{Binding Number}"
StyleClass="box-value"
HorizontalOptions="End" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="!@#$%^&amp;*"
StyleClass="box-label, box-label-regular"
HorizontalOptions="StartAndExpand" />
<Switch
IsToggled="{Binding Special}"
StyleClass="box-value"
HorizontalOptions="End" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
<StackLayout StyleClass="box-row, box-row-stepper">
<Label
Text="{u:I18n MinNumbers}"
StyleClass="box-label, box-label-regular"
VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center" />
<Label
Text="{Binding MinNumber}"
StyleClass="box-label, box-sub-label"
HorizontalOptions="FillAndExpand"
HorizontalTextAlignment="End"
VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center" />
<Stepper
Value="{Binding MinNumber}"
Minimum="0"
Maximum="5"
Increment="1" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
<StackLayout StyleClass="box-row, box-row-stepper">
<Label
Text="{u:I18n MinSpecial}"
StyleClass="box-label, box-label-regular"
VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center" />
<Label
Text="{Binding MinSpecial}"
StyleClass="box-label, box-sub-label"
HorizontalOptions="FillAndExpand"
HorizontalTextAlignment="End"
VerticalOptions="FillAndExpand"
VerticalTextAlignment="Center" />
<Stepper
Value="{Binding MinSpecial}"
Minimum="0"
Maximum="5"
Increment="1" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="{u:I18n AvoidAmbiguousCharacters}"
StyleClass="box-label, box-label-regular"
HorizontalOptions="StartAndExpand" />
<Switch
IsToggled="{Binding AvoidAmbiguous}"
StyleClass="box-value"
HorizontalOptions="End" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
</StackLayout>
</StackLayout> </StackLayout>
</StackLayout> </StackLayout>
</StackLayout> </ScrollView>
</pages:BaseContentPage> </pages:BaseContentPage>

View file

@ -2,9 +2,7 @@
using Bit.Core.Abstractions; using Bit.Core.Abstractions;
using Bit.Core.Models.Domain; using Bit.Core.Models.Domain;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Bit.App.Pages namespace Bit.App.Pages
@ -17,7 +15,18 @@ namespace Bit.App.Pages
private PasswordGenerationOptions _options; private PasswordGenerationOptions _options;
private string _password; private string _password;
private bool _isPassword; private bool _isPassword;
private bool _uppercase;
private bool _lowercase;
private bool _number;
private bool _special;
private bool _avoidAmbiguous;
private int _minNumber;
private int _minSpecial;
private int _length;
private int _numWords;
private string _wordSeparator;
private int _typeSelectedIndex; private int _typeSelectedIndex;
private bool _doneIniting;
public GeneratorPageViewModel() public GeneratorPageViewModel()
{ {
@ -42,10 +51,134 @@ namespace Bit.App.Pages
set => SetProperty(ref _isPassword, value); set => SetProperty(ref _isPassword, value);
} }
public PasswordGenerationOptions Options public int Length
{ {
get => _options; get => _length;
set => SetProperty(ref _options, value); set
{
if(SetProperty(ref _length, value))
{
_options.Length = value;
var task = SaveOptionsAsync();
}
}
}
public bool Uppercase
{
get => _uppercase;
set
{
if(SetProperty(ref _uppercase, value))
{
_options.Uppercase = value;
var task = SaveOptionsAsync();
}
}
}
public bool Lowercase
{
get => _lowercase;
set
{
if(SetProperty(ref _lowercase, value))
{
_options.Lowercase = value;
var task = SaveOptionsAsync();
}
}
}
public bool Number
{
get => _number;
set
{
if(SetProperty(ref _number, value))
{
_options.Number = value;
var task = SaveOptionsAsync();
}
}
}
public bool Special
{
get => _special;
set
{
if(SetProperty(ref _special, value))
{
_options.Special = value;
var task = SaveOptionsAsync();
}
}
}
public bool AvoidAmbiguous
{
get => _avoidAmbiguous;
set
{
if(SetProperty(ref _avoidAmbiguous, value))
{
_options.Ambiguous = !value;
var task = SaveOptionsAsync();
}
}
}
public int MinNumber
{
get => _minNumber;
set
{
if(SetProperty(ref _minNumber, value))
{
_options.MinNumber = value;
var task = SaveOptionsAsync();
}
}
}
public int MinSpecial
{
get => _minSpecial;
set
{
if(SetProperty(ref _minSpecial, value))
{
_options.MinSpecial = value;
var task = SaveOptionsAsync();
}
}
}
public int NumWords
{
get => _numWords;
set
{
if(SetProperty(ref _numWords, value))
{
_options.NumWords = value;
var task = SaveOptionsAsync();
}
}
}
public string WordSeparator
{
get => _wordSeparator;
set
{
if(SetProperty(ref _wordSeparator, value))
{
_options.WordSeparator = value;
var task = SaveOptionsAsync();
}
}
} }
public int TypeSelectedIndex public int TypeSelectedIndex
@ -55,29 +188,37 @@ namespace Bit.App.Pages
{ {
if(SetProperty(ref _typeSelectedIndex, value)) if(SetProperty(ref _typeSelectedIndex, value))
{ {
TypeChanged(); IsPassword = value == 0;
var task = SaveOptionsAsync();
} }
} }
} }
public async Task InitAsync() public async Task InitAsync()
{ {
Options = await _passwordGenerationService.GetOptionsAsync(); _options = await _passwordGenerationService.GetOptionsAsync();
TypeSelectedIndex = Options.Type == "passphrase" ? 1 : 0; LoadFromOptions();
Password = await _passwordGenerationService.GeneratePasswordAsync(Options); Password = await _passwordGenerationService.GeneratePasswordAsync(_options);
await _passwordGenerationService.AddHistoryAsync(Password); await _passwordGenerationService.AddHistoryAsync(Password);
_doneIniting = true;
} }
public async Task RegenerateAsync() public async Task RegenerateAsync()
{ {
Password = await _passwordGenerationService.GeneratePasswordAsync(Options); Password = await _passwordGenerationService.GeneratePasswordAsync(_options);
await _passwordGenerationService.AddHistoryAsync(Password); await _passwordGenerationService.AddHistoryAsync(Password);
} }
public async Task SaveOptionsAsync(bool regenerate = true) public async Task SaveOptionsAsync(bool regenerate = true)
{ {
_passwordGenerationService.NormalizeOptions(Options); if(!_doneIniting)
await _passwordGenerationService.SaveOptionsAsync(Options); {
return;
}
SetOptions();
_passwordGenerationService.NormalizeOptions(_options);
await _passwordGenerationService.SaveOptionsAsync(_options);
LoadFromOptions();
if(regenerate) if(regenerate)
{ {
await RegenerateAsync(); await RegenerateAsync();
@ -90,11 +231,33 @@ namespace Bit.App.Pages
_platformUtilsService.ShowToast("success", null, AppResources.CopiedPassword); _platformUtilsService.ShowToast("success", null, AppResources.CopiedPassword);
} }
public async void TypeChanged() private void LoadFromOptions()
{ {
AvoidAmbiguous = !_options.Ambiguous.GetValueOrDefault();
TypeSelectedIndex = _options.Type == "passphrase" ? 1 : 0;
IsPassword = TypeSelectedIndex == 0; IsPassword = TypeSelectedIndex == 0;
Options.Type = IsPassword ? "password" : "passphrase"; MinNumber = _options.MinNumber.GetValueOrDefault();
await SaveOptionsAsync(); MinSpecial = _options.MinSpecial.GetValueOrDefault();
Special = _options.Special.GetValueOrDefault();
Number = _options.Number.GetValueOrDefault();
NumWords = _options.NumWords.GetValueOrDefault();
WordSeparator = _options.WordSeparator;
Uppercase = _options.Uppercase.GetValueOrDefault();
Lowercase = _options.Lowercase.GetValueOrDefault();
}
private void SetOptions()
{
_options.Ambiguous = !AvoidAmbiguous;
_options.Type = TypeSelectedIndex == 1 ? "passphrase" : "password";
_options.MinNumber = MinNumber;
_options.MinSpecial = MinSpecial;
_options.Special = Special;
_options.NumWords = NumWords;
_options.Number = Number;
_options.WordSeparator = WordSeparator;
_options.Uppercase = Uppercase;
_options.Lowercase = Lowercase;
} }
} }
} }

View file

@ -257,6 +257,13 @@
<Setter Property="Orientation" <Setter Property="Orientation"
Value="Horizontal" /> Value="Horizontal" />
</Style> </Style>
<Style TargetType="StackLayout"
Class="box-row-stepper">
<Setter Property="Orientation"
Value="Horizontal" />
<Setter Property="Spacing"
Value="10" />
</Style>
<Style TargetType="Button" <Style TargetType="Button"
ApplyToDerivedTypes="True" ApplyToDerivedTypes="True"
Class="box-row-button"> Class="box-row-button">