diff --git a/src/App/App.csproj b/src/App/App.csproj index 9f835f135..71b8f9f32 100644 --- a/src/App/App.csproj +++ b/src/App/App.csproj @@ -37,6 +37,9 @@ GeneratorPage.xaml + + PasswordHistoryPage.xaml + ViewPage.xaml diff --git a/src/App/Pages/Vault/PasswordHistoryPage.xaml b/src/App/Pages/Vault/PasswordHistoryPage.xaml new file mode 100644 index 000000000..4adc60f61 --- /dev/null +++ b/src/App/Pages/Vault/PasswordHistoryPage.xaml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/App/Pages/Vault/PasswordHistoryPage.xaml.cs b/src/App/Pages/Vault/PasswordHistoryPage.xaml.cs new file mode 100644 index 000000000..48fb9a570 --- /dev/null +++ b/src/App/Pages/Vault/PasswordHistoryPage.xaml.cs @@ -0,0 +1,26 @@ +using System; + +namespace Bit.App.Pages +{ + public partial class PasswordHistoryPage : BaseContentPage + { + private PasswordHistoryPageViewModel _vm; + + public PasswordHistoryPage(string cipherId) + { + InitializeComponent(); + SetActivityIndicator(); + _vm = BindingContext as PasswordHistoryPageViewModel; + _vm.Page = this; + _vm.CipherId = cipherId; + } + + protected override async void OnAppearing() + { + base.OnAppearing(); + await LoadOnAppearedAsync(_mainLayout, true, async () => { + await _vm.InitAsync(); + }); + } + } +} diff --git a/src/App/Pages/Vault/PasswordHistoryPageViewModel.cs b/src/App/Pages/Vault/PasswordHistoryPageViewModel.cs new file mode 100644 index 000000000..49a25495e --- /dev/null +++ b/src/App/Pages/Vault/PasswordHistoryPageViewModel.cs @@ -0,0 +1,53 @@ +using Bit.App.Resources; +using Bit.Core.Abstractions; +using Bit.Core.Models.View; +using Bit.Core.Utilities; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xamarin.Forms; + +namespace Bit.App.Pages +{ + public class PasswordHistoryPageViewModel : BaseViewModel + { + private readonly IPlatformUtilsService _platformUtilsService; + private readonly ICipherService _cipherService; + + private bool _showNoData; + + public PasswordHistoryPageViewModel() + { + _platformUtilsService = ServiceContainer.Resolve("platformUtilsService"); + _cipherService = ServiceContainer.Resolve("cipherService"); + + PageTitle = AppResources.PasswordHistory; + History = new ExtendedObservableCollection(); + CopyCommand = new Command(CopyAsync); + } + + public Command CopyCommand { get; set; } + public string CipherId { get; set; } + public ExtendedObservableCollection History { get; set; } + + public bool ShowNoData + { + get => _showNoData; + set => SetProperty(ref _showNoData, value); + } + + public async Task InitAsync() + { + var cipher = await _cipherService.GetAsync(CipherId); + var decCipher = await cipher.DecryptAsync(); + History.ResetWithRange(decCipher.PasswordHistory ?? new List()); + ShowNoData = History.Count == 0; + } + + private async void CopyAsync(PasswordHistoryView ph) + { + await _platformUtilsService.CopyToClipboardAsync(ph.Password); + _platformUtilsService.ShowToast("info", null, + string.Format(AppResources.ValueHasBeenCopied, AppResources.Password)); + } + } +} diff --git a/src/App/Pages/Vault/ViewPage.xaml b/src/App/Pages/Vault/ViewPage.xaml index 26bea6f75..a13a91355 100644 --- a/src/App/Pages/Vault/ViewPage.xaml +++ b/src/App/Pages/Vault/ViewPage.xaml @@ -584,10 +584,18 @@ StyleClass="box-footer-label" /> diff --git a/src/App/Pages/Vault/ViewPage.xaml.cs b/src/App/Pages/Vault/ViewPage.xaml.cs index c626da79b..dadc6c836 100644 --- a/src/App/Pages/Vault/ViewPage.xaml.cs +++ b/src/App/Pages/Vault/ViewPage.xaml.cs @@ -1,6 +1,7 @@ using Bit.Core.Abstractions; using Bit.Core.Utilities; using System.Collections.Generic; +using Xamarin.Forms; namespace Bit.App.Pages { @@ -46,5 +47,10 @@ namespace Bit.App.Pages _broadcasterService.Unsubscribe(nameof(ViewPage)); _vm.CleanUp(); } + + private async void PasswordHistory_Tapped(object sender, System.EventArgs e) + { + await Navigation.PushModalAsync(new NavigationPage(new PasswordHistoryPage(_vm.CipherId))); + } } } diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs index c5d60c0a0..3a66e5db8 100644 --- a/src/App/Resources/AppResources.Designer.cs +++ b/src/App/Resources/AppResources.Designer.cs @@ -2472,6 +2472,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to No passwords to list.. + /// + public static string NoPasswordsToList { + get { + return ResourceManager.GetString("NoPasswordsToList", resourceCulture); + } + } + /// /// Looks up a localized string similar to Notes. /// diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx index 763df10c4..317605182 100644 --- a/src/App/Resources/AppResources.resx +++ b/src/App/Resources/AppResources.resx @@ -1393,4 +1393,7 @@ Types + + No passwords to list. + \ No newline at end of file diff --git a/src/App/Styles/Android.xaml b/src/App/Styles/Android.xaml index b7aa9a338..0479f13b0 100644 --- a/src/App/Styles/Android.xaml +++ b/src/App/Styles/Android.xaml @@ -44,6 +44,14 @@ + diff --git a/src/App/Styles/Base.xaml b/src/App/Styles/Base.xaml index 935fe0612..bf1835120 100644 --- a/src/App/Styles/Base.xaml +++ b/src/App/Styles/Base.xaml @@ -162,6 +162,20 @@ + diff --git a/src/App/Utilities/DateTimeConverter.cs b/src/App/Utilities/DateTimeConverter.cs new file mode 100644 index 000000000..bcd9f0258 --- /dev/null +++ b/src/App/Utilities/DateTimeConverter.cs @@ -0,0 +1,29 @@ +using System; +using Xamarin.Forms; + +namespace Bit.App.Utilities +{ + public class DateTimeConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, + System.Globalization.CultureInfo culture) + { + if(targetType != typeof(string)) + { + throw new InvalidOperationException("The target must be a string."); + } + if(value == null) + { + return string.Empty; + } + var d = (DateTime)value; + return string.Format("{0} {1}", d.ToShortDateString(), d.ToShortTimeString()); + } + + public object ConvertBack(object value, Type targetType, object parameter, + System.Globalization.CultureInfo culture) + { + throw new NotSupportedException(); + } + } +}