diff --git a/src/App/Controls/AuthenticatorViewCell/AuthenticatorViewCell.xaml b/src/App/Controls/AuthenticatorViewCell/AuthenticatorViewCell.xaml
new file mode 100644
index 000000000..4d4e82554
--- /dev/null
+++ b/src/App/Controls/AuthenticatorViewCell/AuthenticatorViewCell.xaml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/App/Controls/AuthenticatorViewCell/AuthenticatorViewCell.xaml.cs b/src/App/Controls/AuthenticatorViewCell/AuthenticatorViewCell.xaml.cs
new file mode 100644
index 000000000..871c8a424
--- /dev/null
+++ b/src/App/Controls/AuthenticatorViewCell/AuthenticatorViewCell.xaml.cs
@@ -0,0 +1,71 @@
+using System;
+using Bit.Core.Models.View;
+using Xamarin.Forms;
+
+namespace Bit.App.Controls
+{
+ public partial class AuthenticatorViewCell : ExtendedGrid
+ {
+ public static readonly BindableProperty CipherProperty = BindableProperty.Create(
+ nameof(Cipher), typeof(CipherView), typeof(AuthenticatorViewCell), default(CipherView), BindingMode.OneWay);
+
+ public static readonly BindableProperty WebsiteIconsEnabledProperty = BindableProperty.Create(
+ nameof(WebsiteIconsEnabled), typeof(bool?), typeof(AuthenticatorViewCell));
+
+ public static readonly BindableProperty ButtonCommandProperty = BindableProperty.Create(
+ nameof(ButtonCommand), typeof(Command), typeof(AuthenticatorViewCell));
+
+ public AuthenticatorViewCell()
+ {
+ InitializeComponent();
+ }
+
+ public bool? WebsiteIconsEnabled
+ {
+ get => (bool)GetValue(WebsiteIconsEnabledProperty);
+ set => SetValue(WebsiteIconsEnabledProperty, value);
+ }
+
+ public CipherView Cipher
+ {
+ get => GetValue(CipherProperty) as CipherView;
+ set => SetValue(CipherProperty, value);
+ }
+
+ public Command ButtonCommand
+ {
+ get => GetValue(ButtonCommandProperty) as Command;
+ set => SetValue(ButtonCommandProperty, value);
+ }
+
+ protected override void OnPropertyChanged(string propertyName = null)
+ {
+ base.OnPropertyChanged(propertyName);
+ if (propertyName == CipherProperty.PropertyName)
+ {
+ if (Cipher == null)
+ {
+ return;
+ }
+ BindingContext = new AuthenticatorViewCellViewModel(Cipher, WebsiteIconsEnabled ?? false);
+ }
+ else if (propertyName == WebsiteIconsEnabledProperty.PropertyName)
+ {
+ if (Cipher == null)
+ {
+ return;
+ }
+ ((AuthenticatorViewCellViewModel)BindingContext).WebsiteIconsEnabled = WebsiteIconsEnabled ?? false;
+ }
+ }
+
+ private void MoreButton_Clicked(object sender, EventArgs e)
+ {
+ var cipher = ((sender as MiButton)?.BindingContext as AuthenticatorViewCellViewModel)?.Cipher;
+ if (cipher != null)
+ {
+ ButtonCommand?.Execute(cipher);
+ }
+ }
+ }
+}
diff --git a/src/App/Controls/AuthenticatorViewCell/AuthenticatorViewCellViewModel.cs b/src/App/Controls/AuthenticatorViewCell/AuthenticatorViewCellViewModel.cs
new file mode 100644
index 000000000..0010e6a3b
--- /dev/null
+++ b/src/App/Controls/AuthenticatorViewCell/AuthenticatorViewCellViewModel.cs
@@ -0,0 +1,69 @@
+using Bit.App.Utilities;
+using Bit.Core.Models.View;
+using Bit.Core.Utilities;
+using Xamarin.Forms;
+
+namespace Bit.App.Controls
+{
+ public class AuthenticatorViewCellViewModel : ExtendedViewModel
+ {
+ private CipherView _cipher;
+ private string _totpCodeFormatted = "938928";
+ private string _totpSec;
+ private bool _websiteIconsEnabled;
+ private string _iconImageSource = string.Empty;
+
+ public AuthenticatorViewCellViewModel(CipherView cipherView, bool websiteIconsEnabled)
+ {
+ Cipher = cipherView;
+ WebsiteIconsEnabled = websiteIconsEnabled;
+ }
+
+ public Command CopyCommand { get; set; }
+
+ public CipherView Cipher
+ {
+ get => _cipher;
+ set => SetProperty(ref _cipher, value);
+ }
+
+ public string TotpCodeFormatted
+ {
+ get => _totpCodeFormatted;
+ set => SetProperty(ref _totpCodeFormatted, value);
+ }
+
+ public string TotpSec
+ {
+ get => _totpSec;
+ set => SetProperty(ref _totpSec, value);
+ }
+
+ public bool WebsiteIconsEnabled
+ {
+ get => _websiteIconsEnabled;
+ set => SetProperty(ref _websiteIconsEnabled, value);
+ }
+
+ public bool ShowIconImage
+ {
+ get => WebsiteIconsEnabled
+ && !string.IsNullOrWhiteSpace(Cipher.Login?.Uri)
+ && IconImageSource != null;
+ }
+
+ public string IconImageSource
+ {
+ get
+ {
+ if (_iconImageSource == string.Empty) // default value since icon source can return null
+ {
+ _iconImageSource = IconImageHelper.GetLoginIconImage(Cipher);
+ }
+ return _iconImageSource;
+ }
+
+ }
+ }
+}
+
diff --git a/src/App/Pages/Authenticator/AuthenticatorPage.xaml b/src/App/Pages/Authenticator/AuthenticatorPage.xaml
index 933183ba8..6632216c8 100644
--- a/src/App/Pages/Authenticator/AuthenticatorPage.xaml
+++ b/src/App/Pages/Authenticator/AuthenticatorPage.xaml
@@ -20,6 +20,12 @@
SelectionMode="Single"
SelectionChanged="RowSelected"
StyleClass="list, list-platform">
+
+
+
+
+
+
diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs
index 931ef84f3..bde127d61 100644
--- a/src/App/Resources/AppResources.Designer.cs
+++ b/src/App/Resources/AppResources.Designer.cs
@@ -3761,6 +3761,12 @@ namespace Bit.App.Resources {
}
}
+ public static string RequestOTP {
+ get {
+ return ResourceManager.GetString("RequestOTP", resourceCulture);
+ }
+ }
+
public static string SendCode {
get {
return ResourceManager.GetString("SendCode", resourceCulture);