diff --git a/src/App/App.csproj b/src/App/App.csproj index 45f805654..a979c09be 100644 --- a/src/App/App.csproj +++ b/src/App/App.csproj @@ -38,6 +38,9 @@ GeneratorPage.xaml + + GeneratorHistoryPage.xaml + AttachmentsPage.xaml diff --git a/src/App/Pages/Generator/GeneratorHistoryPage.xaml b/src/App/Pages/Generator/GeneratorHistoryPage.xaml new file mode 100644 index 000000000..7bd473634 --- /dev/null +++ b/src/App/Pages/Generator/GeneratorHistoryPage.xaml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/App/Pages/Generator/GeneratorHistoryPage.xaml.cs b/src/App/Pages/Generator/GeneratorHistoryPage.xaml.cs new file mode 100644 index 000000000..914afa87e --- /dev/null +++ b/src/App/Pages/Generator/GeneratorHistoryPage.xaml.cs @@ -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(); + } + } +} diff --git a/src/App/Pages/Generator/GeneratorHistoryPageViewModel.cs b/src/App/Pages/Generator/GeneratorHistoryPageViewModel.cs new file mode 100644 index 000000000..ad7f59195 --- /dev/null +++ b/src/App/Pages/Generator/GeneratorHistoryPageViewModel.cs @@ -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("platformUtilsService"); + _passwordGenerationService = ServiceContainer.Resolve( + "passwordGenerationService"); + + PageTitle = AppResources.PasswordHistory; + History = new ExtendedObservableCollection(); + CopyCommand = new Command(CopyAsync); + } + + public Command CopyCommand { get; set; } + public ExtendedObservableCollection 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()); + ShowNoData = History.Count == 0; + } + + public async Task ClearAsync() + { + History.ResetWithRange(new List()); + await _passwordGenerationService.ClearAsync(); + } + + private async void CopyAsync(GeneratedPasswordHistory ph) + { + await _platformUtilsService.CopyToClipboardAsync(ph.Password); + _platformUtilsService.ShowToast("info", null, + string.Format(AppResources.ValueHasBeenCopied, AppResources.Password)); + } + } +} diff --git a/src/App/Pages/Generator/GeneratorPage.xaml.cs b/src/App/Pages/Generator/GeneratorPage.xaml.cs index a31c5fa35..a30a619b3 100644 --- a/src/App/Pages/Generator/GeneratorPage.xaml.cs +++ b/src/App/Pages/Generator/GeneratorPage.xaml.cs @@ -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)); } } } diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs index 42400d59c..d273e376f 100644 --- a/src/App/Resources/AppResources.Designer.cs +++ b/src/App/Resources/AppResources.Designer.cs @@ -870,6 +870,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Clear. + /// + public static string Clear { + get { + return ResourceManager.GetString("Clear", resourceCulture); + } + } + /// /// Looks up a localized string similar to Close. /// diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx index 500d50953..0e2e858f0 100644 --- a/src/App/Resources/AppResources.resx +++ b/src/App/Resources/AppResources.resx @@ -1456,4 +1456,8 @@ Word Separator + + Clear + To clear something out. example: To clear browser history. + \ No newline at end of file diff --git a/src/App/Utilities/DateTimeConverter.cs b/src/App/Utilities/DateTimeConverter.cs index bcd9f0258..6022caf2d 100644 --- a/src/App/Utilities/DateTimeConverter.cs +++ b/src/App/Utilities/DateTimeConverter.cs @@ -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()); } diff --git a/src/Core/Services/PasswordGenerationService.cs b/src/Core/Services/PasswordGenerationService.cs index f85beb502..f7c95d080 100644 --- a/src/Core/Services/PasswordGenerationService.cs +++ b/src/Core/Services/PasswordGenerationService.cs @@ -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) {