generated password history page

This commit is contained in:
Kyle Spearrin 2019-05-14 09:01:07 -04:00
parent 4dfd8b6985
commit cc7ccf921b
9 changed files with 199 additions and 4 deletions

View file

@ -38,6 +38,9 @@
<Compile Update="Pages\Generator\GeneratorPage.xaml.cs">
<DependentUpon>GeneratorPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Generator\GeneratorHistoryPage.xaml.cs">
<DependentUpon>GeneratorHistoryPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\AttachmentsPage.xaml.cs">
<DependentUpon>AttachmentsPage.xaml</DependentUpon>
</Compile>

View file

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.GeneratorHistoryPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:domain="clr-namespace:Bit.Core.Models.Domain;assembly=BitwardenCore"
x:DataType="pages:GeneratorHistoryPageViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages:GeneratorHistoryPageViewModel />
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" />
<u:DateTimeConverter x:Key="dateTime" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Clear}"
Clicked="Clear_Clicked"
Order="Secondary"
x:Name="_clearItem" />
</ContentPage.ToolbarItems>
<StackLayout x:Name="_mainLayout">
<Label IsVisible="{Binding ShowNoData}"
Text="{u:I18n NoPasswordsToList}"
Margin="20, 0"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
HorizontalTextAlignment="Center"></Label>
<ListView x:Name="_listView"
IsVisible="{Binding ShowNoData, Converter={StaticResource inverseBool}}"
ItemsSource="{Binding History}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
CachingStrategy="RecycleElement"
StyleClass="list, list-platform">
<ListView.ItemTemplate>
<DataTemplate x:DataType="domain:GeneratedPasswordHistory">
<ViewCell>
<Grid
StyleClass="list-row, list-row-platform"
Padding="10"
RowSpacing="0"
ColumnSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<controls:MonoLabel LineBreakMode="CharacterWrap"
Grid.Column="0"
Grid.Row="0"
StyleClass="list-title, list-title-platform"
Text="{Binding Password, Mode=OneWay}" />
<Label LineBreakMode="TailTruncation"
Grid.Column="0"
Grid.Row="1"
StyleClass="list-subtitle, list-subtitle-platform"
Text="{Binding Date, Mode=OneWay, Converter={StaticResource dateTime}}" />
<controls:FaButton
StyleClass="list-row-button, list-row-button-platform"
Text="&#xf0ea;"
Command="{Binding BindingContext.CopyCommand, Source={x:Reference _page}}"
CommandParameter="{Binding .}"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</pages:BaseContentPage>

View file

@ -0,0 +1,30 @@
using System;
namespace Bit.App.Pages
{
public partial class GeneratorHistoryPage : BaseContentPage
{
private GeneratorHistoryPageViewModel _vm;
public GeneratorHistoryPage()
{
InitializeComponent();
SetActivityIndicator();
_vm = BindingContext as GeneratorHistoryPageViewModel;
_vm.Page = this;
}
protected override async void OnAppearing()
{
base.OnAppearing();
await LoadOnAppearedAsync(_mainLayout, true, async () => {
await _vm.InitAsync();
});
}
private async void Clear_Clicked(object sender, EventArgs e)
{
await _vm.ClearAsync();
}
}
}

View file

@ -0,0 +1,58 @@
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Models.Domain;
using Bit.Core.Utilities;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class GeneratorHistoryPageViewModel : BaseViewModel
{
private readonly IPlatformUtilsService _platformUtilsService;
private readonly IPasswordGenerationService _passwordGenerationService;
private bool _showNoData;
public GeneratorHistoryPageViewModel()
{
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_passwordGenerationService = ServiceContainer.Resolve<IPasswordGenerationService>(
"passwordGenerationService");
PageTitle = AppResources.PasswordHistory;
History = new ExtendedObservableCollection<GeneratedPasswordHistory>();
CopyCommand = new Command<GeneratedPasswordHistory>(CopyAsync);
}
public Command CopyCommand { get; set; }
public ExtendedObservableCollection<GeneratedPasswordHistory> History { get; set; }
public bool ShowNoData
{
get => _showNoData;
set => SetProperty(ref _showNoData, value);
}
public async Task InitAsync()
{
var history = await _passwordGenerationService.GetHistoryAsync();
History.ResetWithRange(history ?? new List<GeneratedPasswordHistory>());
ShowNoData = History.Count == 0;
}
public async Task ClearAsync()
{
History.ResetWithRange(new List<GeneratedPasswordHistory>());
await _passwordGenerationService.ClearAsync();
}
private async void CopyAsync(GeneratedPasswordHistory ph)
{
await _platformUtilsService.CopyToClipboardAsync(ph.Password);
_platformUtilsService.ShowToast("info", null,
string.Format(AppResources.ValueHasBeenCopied, AppResources.Password));
}
}
}

View file

@ -1,4 +1,5 @@
using System;
using Xamarin.Forms;
namespace Bit.App.Pages
{
@ -44,9 +45,10 @@ namespace Bit.App.Pages
_selectAction?.Invoke(_vm.Password);
}
private void History_Clicked(object sender, EventArgs e)
private async void History_Clicked(object sender, EventArgs e)
{
var page = new GeneratorHistoryPage();
await Navigation.PushModalAsync(new NavigationPage(page));
}
}
}

View file

@ -870,6 +870,15 @@ namespace Bit.App.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Clear.
/// </summary>
public static string Clear {
get {
return ResourceManager.GetString("Clear", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Close.
/// </summary>

View file

@ -1456,4 +1456,8 @@
<data name="WordSeparator" xml:space="preserve">
<value>Word Separator</value>
</data>
<data name="Clear" xml:space="preserve">
<value>Clear</value>
<comment>To clear something out. example: To clear browser history.</comment>
</data>
</root>

View file

@ -16,7 +16,7 @@ namespace Bit.App.Utilities
{
return string.Empty;
}
var d = (DateTime)value;
var d = ((DateTime)value).ToLocalTime();
return string.Format("{0} {1}", d.ToShortDateString(), d.ToShortTimeString());
}

View file

@ -248,12 +248,12 @@ namespace Bit.Core.Services
return;
}
var currentHistory = await GetHistoryAsync();
// Prevent duplicates
if(MatchesPrevious(password, currentHistory))
{
return;
}
currentHistory.Insert(0, new GeneratedPasswordHistory { Password = password, Date = DateTime.UtcNow });
// Remove old items.
if(currentHistory.Count > MaxPasswordsInHistory)
{