diff --git a/src/Android/Android.csproj b/src/Android/Android.csproj
index 2f7df60bd..cb50c5a5c 100644
--- a/src/Android/Android.csproj
+++ b/src/Android/Android.csproj
@@ -123,7 +123,9 @@
+
+
@@ -131,6 +133,7 @@
+
@@ -176,6 +179,7 @@
+
@@ -183,6 +187,7 @@
+
diff --git a/src/Android/Renderers/ExtendedDatePickerRenderer.cs b/src/Android/Renderers/ExtendedDatePickerRenderer.cs
new file mode 100644
index 000000000..263171b3b
--- /dev/null
+++ b/src/Android/Renderers/ExtendedDatePickerRenderer.cs
@@ -0,0 +1,50 @@
+using System.ComponentModel;
+using Android.Content;
+using Android.Views;
+using Bit.App.Controls;
+using Bit.Droid.Renderers;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Android;
+
+[assembly: ExportRenderer(typeof(ExtendedDatePicker), typeof(ExtendedDatePickerRenderer))]
+namespace Bit.Droid.Renderers
+{
+ public class ExtendedDatePickerRenderer : DatePickerRenderer
+ {
+ public ExtendedDatePickerRenderer(Context context)
+ : base(context) { }
+
+ protected override void OnElementChanged(ElementChangedEventArgs e)
+ {
+ base.OnElementChanged(e);
+ if (Control != null && Element is ExtendedDatePicker element)
+ {
+ // center text
+ Control.Gravity = GravityFlags.CenterHorizontal;
+
+ // use placeholder until NullableDate set
+ if (!element.NullableDate.HasValue)
+ {
+ Control.Text = element.PlaceHolder;
+ }
+ }
+ }
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == DatePicker.DateProperty.PropertyName ||
+ e.PropertyName == DatePicker.FormatProperty.PropertyName)
+ {
+ if (Control != null && Element is ExtendedDatePicker element)
+ {
+ if (Element.Format == element.PlaceHolder)
+ {
+ Control.Text = element.PlaceHolder;
+ return;
+ }
+ }
+ }
+ base.OnElementPropertyChanged(sender, e);
+ }
+ }
+}
diff --git a/src/Android/Renderers/ExtendedTimePickerRenderer.cs b/src/Android/Renderers/ExtendedTimePickerRenderer.cs
new file mode 100644
index 000000000..5b38a3034
--- /dev/null
+++ b/src/Android/Renderers/ExtendedTimePickerRenderer.cs
@@ -0,0 +1,50 @@
+using System.ComponentModel;
+using Android.Content;
+using Android.Views;
+using Bit.App.Controls;
+using Bit.Droid.Renderers;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Android;
+
+[assembly: ExportRenderer(typeof(ExtendedTimePicker), typeof(ExtendedTimePickerRenderer))]
+namespace Bit.Droid.Renderers
+{
+ public class ExtendedTimePickerRenderer : TimePickerRenderer
+ {
+ public ExtendedTimePickerRenderer(Context context)
+ : base(context) { }
+
+ protected override void OnElementChanged(ElementChangedEventArgs e)
+ {
+ base.OnElementChanged(e);
+ if (Control != null && Element is ExtendedTimePicker element)
+ {
+ // center text
+ Control.Gravity = GravityFlags.CenterHorizontal;
+
+ // use placeholder until NullableTime set
+ if (!element.NullableTime.HasValue)
+ {
+ Control.Text = element.PlaceHolder;
+ }
+ }
+ }
+
+ protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == TimePicker.TimeProperty.PropertyName ||
+ e.PropertyName == TimePicker.FormatProperty.PropertyName)
+ {
+ if (Control != null && Element is ExtendedTimePicker element)
+ {
+ if (Element.Format == element.PlaceHolder)
+ {
+ Control.Text = element.PlaceHolder;
+ return;
+ }
+ }
+ }
+ base.OnElementPropertyChanged(sender, e);
+ }
+ }
+}
diff --git a/src/Android/Renderers/SendViewCellRenderer.cs b/src/Android/Renderers/SendViewCellRenderer.cs
new file mode 100644
index 000000000..4842c37af
--- /dev/null
+++ b/src/Android/Renderers/SendViewCellRenderer.cs
@@ -0,0 +1,199 @@
+using System;
+using System.ComponentModel;
+using Android.App;
+using Android.Content;
+using Android.Graphics;
+using Android.Util;
+using Android.Views;
+using Android.Widget;
+using Bit.App.Controls;
+using Bit.App.Utilities;
+using Bit.Droid.Renderers;
+using FFImageLoading.Work;
+using Xamarin.Forms;
+using Xamarin.Forms.Platform.Android;
+using Button = Android.Widget.Button;
+using Color = Android.Graphics.Color;
+using View = Android.Views.View;
+
+[assembly: ExportRenderer(typeof(SendViewCell), typeof(SendViewCellRenderer))]
+namespace Bit.Droid.Renderers
+{
+ public class SendViewCellRenderer : ViewCellRenderer
+ {
+ private static Typeface _faTypeface;
+ private static Typeface _miTypeface;
+ private static Color _textColor;
+ private static Color _mutedColor;
+ private static Color _disabledIconColor;
+ private static bool _usingLightTheme;
+
+ private AndroidSendCell _cell;
+
+ protected override View GetCellCore(Cell item, View convertView,
+ ViewGroup parent, Context context)
+ {
+ // TODO expand beyond light/dark detection once we support custom theme switching without app restart
+ var themeChanged = _usingLightTheme != ThemeManager.UsingLightTheme;
+ if (_faTypeface == null)
+ {
+ _faTypeface = Typeface.CreateFromAsset(context.Assets, "FontAwesome.ttf");
+ }
+ if (_miTypeface == null)
+ {
+ _miTypeface = Typeface.CreateFromAsset(context.Assets, "MaterialIcons_Regular.ttf");
+ }
+ if (_textColor == default(Color) || themeChanged)
+ {
+ _textColor = ThemeManager.GetResourceColor("TextColor").ToAndroid();
+ }
+ if (_mutedColor == default(Color) || themeChanged)
+ {
+ _mutedColor = ThemeManager.GetResourceColor("MutedColor").ToAndroid();
+ }
+ if (_disabledIconColor == default(Color) || themeChanged)
+ {
+ _disabledIconColor = ThemeManager.GetResourceColor("DisabledIconColor").ToAndroid();
+ }
+ _usingLightTheme = ThemeManager.UsingLightTheme;
+
+ var sendCell = item as SendViewCell;
+ _cell = convertView as AndroidSendCell;
+ if (_cell == null)
+ {
+ _cell = new AndroidSendCell(context, sendCell, _faTypeface, _miTypeface);
+ }
+ else
+ {
+ _cell.SendViewCell.PropertyChanged -= CellPropertyChanged;
+ }
+ sendCell.PropertyChanged += CellPropertyChanged;
+ _cell.UpdateCell(sendCell);
+ _cell.UpdateColors(_textColor, _mutedColor, _disabledIconColor);
+ return _cell;
+ }
+
+ public void CellPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ var sendCell = sender as SendViewCell;
+ _cell.SendViewCell = sendCell;
+ if (e.PropertyName == SendViewCell.SendProperty.PropertyName)
+ {
+ _cell.UpdateCell(sendCell);
+ }
+ }
+ }
+
+ public class AndroidSendCell : LinearLayout, INativeElementView
+ {
+ private readonly Typeface _faTypeface;
+ private readonly Typeface _miTypeface;
+
+ private IScheduledWork _currentTask;
+
+ public AndroidSendCell(Context context, SendViewCell sendView, Typeface faTypeface, Typeface miTypeface)
+ : base(context)
+ {
+ SendViewCell = sendView;
+ _faTypeface = faTypeface;
+ _miTypeface = miTypeface;
+
+ var view = (context as Activity).LayoutInflater.Inflate(Resource.Layout.SendViewCell, null);
+ Icon = view.FindViewById(Resource.Id.SendCellIcon);
+ Name = view.FindViewById(Resource.Id.SendCellName);
+ SubTitle = view.FindViewById(Resource.Id.SendCellSubTitle);
+ HasPasswordIcon = view.FindViewById(Resource.Id.SendCellHasPasswordIcon);
+ MaxAccessCountReachedIcon = view.FindViewById(Resource.Id.SendCellMaxAccessCountReachedIcon);
+ ExpiredIcon = view.FindViewById(Resource.Id.SendCellExpiredIcon);
+ PendingDeleteIcon = view.FindViewById(Resource.Id.SendCellPendingDeleteIcon);
+ MoreButton = view.FindViewById