mirror of
https://github.com/bitwarden/android.git
synced 2024-12-24 18:08:26 +03:00
generator UI elements
This commit is contained in:
parent
28473dd85f
commit
018a7c9f96
3 changed files with 351 additions and 42 deletions
|
@ -22,35 +22,174 @@
|
|||
Order="Secondary" />
|
||||
</ContentPage.ToolbarItems>
|
||||
|
||||
<StackLayout Spacing="20">
|
||||
<StackLayout StyleClass="box">
|
||||
<controls:MonoLabel
|
||||
Text="{Binding Password}"
|
||||
Margin="0, 20"
|
||||
StyleClass="text-lg"
|
||||
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>
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<u:InverseBoolConverter x:Key="inverseBool" />
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
|
||||
<ScrollView>
|
||||
<StackLayout Spacing="20">
|
||||
<StackLayout StyleClass="box">
|
||||
<controls:MonoLabel
|
||||
Text="{Binding Password}"
|
||||
Margin="0, 20"
|
||||
StyleClass="text-lg"
|
||||
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 StyleClass="box-row-header">
|
||||
<Label Text="{u:I18n Options}"
|
||||
StyleClass="box-header, box-header-platform" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
Text="{u:I18n Type}"
|
||||
StyleClass="box-label" />
|
||||
<Picker
|
||||
ItemsSource="{Binding TypeOptions, Mode=OneTime}"
|
||||
SelectedIndex="{Binding TypeSelectedIndex}"
|
||||
StyleClass="box-value" />
|
||||
<StackLayout StyleClass="box">
|
||||
<StackLayout StyleClass="box-row-header">
|
||||
<Label Text="{u:I18n Options}"
|
||||
StyleClass="box-header, box-header-platform" />
|
||||
</StackLayout>
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
Text="{u:I18n Type}"
|
||||
StyleClass="box-label" />
|
||||
<Picker
|
||||
ItemsSource="{Binding TypeOptions, Mode=OneTime}"
|
||||
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="!@#$%^&*"
|
||||
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>
|
||||
</ScrollView>
|
||||
|
||||
</pages:BaseContentPage>
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Models.Domain;
|
||||
using Bit.Core.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
|
@ -17,7 +15,18 @@ namespace Bit.App.Pages
|
|||
private PasswordGenerationOptions _options;
|
||||
private string _password;
|
||||
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 bool _doneIniting;
|
||||
|
||||
public GeneratorPageViewModel()
|
||||
{
|
||||
|
@ -42,10 +51,134 @@ namespace Bit.App.Pages
|
|||
set => SetProperty(ref _isPassword, value);
|
||||
}
|
||||
|
||||
public PasswordGenerationOptions Options
|
||||
public int Length
|
||||
{
|
||||
get => _options;
|
||||
set => SetProperty(ref _options, value);
|
||||
get => _length;
|
||||
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
|
||||
|
@ -55,29 +188,37 @@ namespace Bit.App.Pages
|
|||
{
|
||||
if(SetProperty(ref _typeSelectedIndex, value))
|
||||
{
|
||||
TypeChanged();
|
||||
IsPassword = value == 0;
|
||||
var task = SaveOptionsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task InitAsync()
|
||||
{
|
||||
Options = await _passwordGenerationService.GetOptionsAsync();
|
||||
TypeSelectedIndex = Options.Type == "passphrase" ? 1 : 0;
|
||||
Password = await _passwordGenerationService.GeneratePasswordAsync(Options);
|
||||
_options = await _passwordGenerationService.GetOptionsAsync();
|
||||
LoadFromOptions();
|
||||
Password = await _passwordGenerationService.GeneratePasswordAsync(_options);
|
||||
await _passwordGenerationService.AddHistoryAsync(Password);
|
||||
_doneIniting = true;
|
||||
}
|
||||
|
||||
public async Task RegenerateAsync()
|
||||
{
|
||||
Password = await _passwordGenerationService.GeneratePasswordAsync(Options);
|
||||
Password = await _passwordGenerationService.GeneratePasswordAsync(_options);
|
||||
await _passwordGenerationService.AddHistoryAsync(Password);
|
||||
}
|
||||
|
||||
public async Task SaveOptionsAsync(bool regenerate = true)
|
||||
{
|
||||
_passwordGenerationService.NormalizeOptions(Options);
|
||||
await _passwordGenerationService.SaveOptionsAsync(Options);
|
||||
if(!_doneIniting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SetOptions();
|
||||
_passwordGenerationService.NormalizeOptions(_options);
|
||||
await _passwordGenerationService.SaveOptionsAsync(_options);
|
||||
LoadFromOptions();
|
||||
if(regenerate)
|
||||
{
|
||||
await RegenerateAsync();
|
||||
|
@ -90,11 +231,33 @@ namespace Bit.App.Pages
|
|||
_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;
|
||||
Options.Type = IsPassword ? "password" : "passphrase";
|
||||
await SaveOptionsAsync();
|
||||
MinNumber = _options.MinNumber.GetValueOrDefault();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -257,6 +257,13 @@
|
|||
<Setter Property="Orientation"
|
||||
Value="Horizontal" />
|
||||
</Style>
|
||||
<Style TargetType="StackLayout"
|
||||
Class="box-row-stepper">
|
||||
<Setter Property="Orientation"
|
||||
Value="Horizontal" />
|
||||
<Setter Property="Spacing"
|
||||
Value="10" />
|
||||
</Style>
|
||||
<Style TargetType="Button"
|
||||
ApplyToDerivedTypes="True"
|
||||
Class="box-row-button">
|
||||
|
|
Loading…
Reference in a new issue