diff --git a/src/Maui/Bitwarden/App.xaml.cs b/src/Maui/Bitwarden/App.xaml.cs
index 21daf9229..c1882d975 100644
--- a/src/Maui/Bitwarden/App.xaml.cs
+++ b/src/Maui/Bitwarden/App.xaml.cs
@@ -18,6 +18,7 @@ using Bit.Core.Utilities;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Controls;
using Microsoft.Maui;
+using Bit.App.Handlers;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace Bit.App
@@ -51,6 +52,7 @@ namespace Bit.App
public App(AppOptions appOptions)
{
+ App.SetupHandlers();
Options = appOptions ?? new AppOptions();
if (Options.IosExtension)
{
@@ -200,6 +202,21 @@ namespace Bit.App
});
}
+ private static void SetupHandlers()
+ {
+ new EntryHandlerMappings().Setup();
+ new EditorHandlerMappings().Setup();
+ new LabelHandlerMappings().Setup();
+ new PickerHandlerMappings().Setup();
+ new SearchBarHandlerMappings().Setup();
+ new SwitchHandlerMappings().Setup();
+ new DatePickerHandlerMappings().Setup();
+ new SliderHandlerMappings().Setup();
+ new StepperHandlerMappings().Setup();
+ new TimePickerHandlerMappings().Setup();
+ new ButtonHandlerMappings().Setup();
+ }
+
private async Task CheckPasswordlessLoginRequestsAsync()
{
if (!_isResumed)
diff --git a/src/Maui/Bitwarden/Bitwarden.csproj b/src/Maui/Bitwarden/Bitwarden.csproj
index 3f4fde0cf..6b2b490ba 100644
--- a/src/Maui/Bitwarden/Bitwarden.csproj
+++ b/src/Maui/Bitwarden/Bitwarden.csproj
@@ -304,6 +304,8 @@
+
+
@@ -316,6 +318,8 @@
+
+
diff --git a/src/Maui/Bitwarden/Controls/HybridWebView.cs b/src/Maui/Bitwarden/Controls/HybridWebView.cs
index 801d9b2f6..d292f7498 100644
--- a/src/Maui/Bitwarden/Controls/HybridWebView.cs
+++ b/src/Maui/Bitwarden/Controls/HybridWebView.cs
@@ -1,8 +1,4 @@
-using System;
-using Microsoft.Maui.Controls;
-using Microsoft.Maui;
-
-namespace Bit.App.Controls
+namespace Bit.App.Controls
{
public class HybridWebView : View
{
diff --git a/src/Maui/Bitwarden/Controls/IconButton.cs b/src/Maui/Bitwarden/Controls/IconButton.cs
index faa4ab8ed..0c9d106b2 100644
--- a/src/Maui/Bitwarden/Controls/IconButton.cs
+++ b/src/Maui/Bitwarden/Controls/IconButton.cs
@@ -1,6 +1,4 @@
using Bit.App.Effects;
-using Microsoft.Maui.Controls;
-using Microsoft.Maui;
namespace Bit.App.Controls
{
@@ -9,17 +7,7 @@ namespace Bit.App.Controls
public IconButton()
{
Padding = 0;
- // TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
- switch (Device.RuntimePlatform)
- {
- case Device.iOS:
- FontFamily = "bwi-font";
- break;
- case Device.Android:
- FontFamily = "bwi-font";
- break;
- }
-
+ FontFamily = "bwi-font";
Effects.Add(new RemoveFontPaddingEffect());
}
}
diff --git a/src/Maui/Bitwarden/Controls/IconLabel.cs b/src/Maui/Bitwarden/Controls/IconLabel.cs
index 3df6881ec..404e491e3 100644
--- a/src/Maui/Bitwarden/Controls/IconLabel.cs
+++ b/src/Maui/Bitwarden/Controls/IconLabel.cs
@@ -1,6 +1,4 @@
using Bit.App.Effects;
-using Microsoft.Maui.Controls;
-using Microsoft.Maui;
namespace Bit.App.Controls
{
@@ -10,17 +8,7 @@ namespace Bit.App.Controls
public IconLabel()
{
- // TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
- switch (Device.RuntimePlatform)
- {
- case Device.iOS:
- FontFamily = "bwi-font";
- break;
- case Device.Android:
- FontFamily = "bwi-font";
- break;
- }
-
+ FontFamily = "bwi-font";
Effects.Add(new RemoveFontPaddingEffect());
}
}
diff --git a/src/Maui/Bitwarden/Controls/MiButton.cs b/src/Maui/Bitwarden/Controls/MiButton.cs
index a181ab177..0618475d0 100644
--- a/src/Maui/Bitwarden/Controls/MiButton.cs
+++ b/src/Maui/Bitwarden/Controls/MiButton.cs
@@ -1,23 +1,15 @@
-using Microsoft.Maui.Controls;
-using Microsoft.Maui;
-
-namespace Bit.App.Controls
+namespace Bit.App.Controls
{
public class MiButton : Button
{
public MiButton()
{
Padding = 0;
- // TODO Xamarin.Forms.Device.RuntimePlatform is no longer supported. Use Microsoft.Maui.Devices.DeviceInfo.Platform instead. For more details see https://learn.microsoft.com/en-us/dotnet/maui/migration/forms-projects#device-changes
- switch (Device.RuntimePlatform)
- {
- case Device.iOS:
- FontFamily = "Material Icons";
- break;
- case Device.Android:
- FontFamily = "MaterialIcons_Regular";
- break;
- }
+#if ANDROID
+ FontFamily = "MaterialIcons_Regular";
+#else
+ FontFamily = "Material Icons";
+#endif
}
}
}
diff --git a/src/Maui/Bitwarden/Effects/FixedSizeEffect.cs b/src/Maui/Bitwarden/Effects/FixedSizeEffect.cs
index 7cfb83e97..7ca5beca7 100644
--- a/src/Maui/Bitwarden/Effects/FixedSizeEffect.cs
+++ b/src/Maui/Bitwarden/Effects/FixedSizeEffect.cs
@@ -20,7 +20,7 @@ namespace Bit.App.Effects
{
if (Element is Label label && Control is TextView textView)
{
- textView.SetTextSize(Android.Util.ComplexUnitType.Pt, (float)label.FontSize);
+ textView.SetTextSize(Android.Util.ComplexUnitType.Sp, (float)label.FontSize);
}
}
diff --git a/src/Maui/Bitwarden/Handlers/ButtonHandlerMappings.cs b/src/Maui/Bitwarden/Handlers/ButtonHandlerMappings.cs
new file mode 100644
index 000000000..a5a83001e
--- /dev/null
+++ b/src/Maui/Bitwarden/Handlers/ButtonHandlerMappings.cs
@@ -0,0 +1,9 @@
+namespace Bit.App.Handlers
+{
+ public partial class ButtonHandlerMappings
+ {
+ public void Setup() => SetupPlatform();
+
+ partial void SetupPlatform();
+ }
+}
diff --git a/src/Maui/Bitwarden/Handlers/DatePickerHandlerMappings.cs b/src/Maui/Bitwarden/Handlers/DatePickerHandlerMappings.cs
new file mode 100644
index 000000000..ebfc65a73
--- /dev/null
+++ b/src/Maui/Bitwarden/Handlers/DatePickerHandlerMappings.cs
@@ -0,0 +1,9 @@
+namespace Bit.App.Handlers
+{
+ public partial class DatePickerHandlerMappings
+ {
+ public void Setup() => SetupPlatform();
+
+ partial void SetupPlatform();
+ }
+}
diff --git a/src/Maui/Bitwarden/Handlers/EditorHandlerMappings.cs b/src/Maui/Bitwarden/Handlers/EditorHandlerMappings.cs
new file mode 100644
index 000000000..f98d21941
--- /dev/null
+++ b/src/Maui/Bitwarden/Handlers/EditorHandlerMappings.cs
@@ -0,0 +1,10 @@
+namespace Bit.App.Handlers
+{
+ public partial class EditorHandlerMappings
+ {
+ public void Setup() => SetupPlatform();
+
+ partial void SetupPlatform();
+ }
+}
+
diff --git a/src/Maui/Bitwarden/Handlers/EntryHandlerMappings.cs b/src/Maui/Bitwarden/Handlers/EntryHandlerMappings.cs
new file mode 100644
index 000000000..63a998490
--- /dev/null
+++ b/src/Maui/Bitwarden/Handlers/EntryHandlerMappings.cs
@@ -0,0 +1,9 @@
+namespace Bit.App.Handlers
+{
+ public partial class EntryHandlerMappings
+ {
+ public void Setup() => SetupPlatform();
+
+ partial void SetupPlatform();
+ }
+}
diff --git a/src/Maui/Bitwarden/Handlers/LabelHandlerMappings.cs b/src/Maui/Bitwarden/Handlers/LabelHandlerMappings.cs
new file mode 100644
index 000000000..4ef02c802
--- /dev/null
+++ b/src/Maui/Bitwarden/Handlers/LabelHandlerMappings.cs
@@ -0,0 +1,9 @@
+namespace Bit.App.Handlers
+{
+ public partial class LabelHandlerMappings
+ {
+ public void Setup() => SetupPlatform();
+
+ partial void SetupPlatform();
+ }
+}
diff --git a/src/Maui/Bitwarden/Handlers/PickerHandlerMappings.cs b/src/Maui/Bitwarden/Handlers/PickerHandlerMappings.cs
new file mode 100644
index 000000000..d293cfcab
--- /dev/null
+++ b/src/Maui/Bitwarden/Handlers/PickerHandlerMappings.cs
@@ -0,0 +1,9 @@
+namespace Bit.App.Handlers
+{
+ public partial class PickerHandlerMappings
+ {
+ public void Setup() => SetupPlatform();
+
+ partial void SetupPlatform();
+ }
+}
diff --git a/src/Maui/Bitwarden/Handlers/SearchBarHandlerMappings.cs b/src/Maui/Bitwarden/Handlers/SearchBarHandlerMappings.cs
new file mode 100644
index 000000000..4bef2add2
--- /dev/null
+++ b/src/Maui/Bitwarden/Handlers/SearchBarHandlerMappings.cs
@@ -0,0 +1,10 @@
+namespace Bit.App.Handlers
+{
+ public partial class SearchBarHandlerMappings
+ {
+ public void Setup() => SetupPlatform();
+
+ partial void SetupPlatform();
+ }
+}
+
diff --git a/src/Maui/Bitwarden/Handlers/SliderHandlerMappings.cs b/src/Maui/Bitwarden/Handlers/SliderHandlerMappings.cs
new file mode 100644
index 000000000..f630ed52f
--- /dev/null
+++ b/src/Maui/Bitwarden/Handlers/SliderHandlerMappings.cs
@@ -0,0 +1,9 @@
+namespace Bit.App.Handlers
+{
+ public partial class SliderHandlerMappings
+ {
+ public void Setup() => SetupPlatform();
+
+ partial void SetupPlatform();
+ }
+}
diff --git a/src/Maui/Bitwarden/Handlers/StepperHandlerMappings.cs b/src/Maui/Bitwarden/Handlers/StepperHandlerMappings.cs
new file mode 100644
index 000000000..0e5f67058
--- /dev/null
+++ b/src/Maui/Bitwarden/Handlers/StepperHandlerMappings.cs
@@ -0,0 +1,10 @@
+namespace Bit.App.Handlers
+{
+ public partial class StepperHandlerMappings
+ {
+ public void Setup() => SetupPlatform();
+
+ partial void SetupPlatform();
+ }
+}
+
diff --git a/src/Maui/Bitwarden/Handlers/SwitchHandlerMappings.cs b/src/Maui/Bitwarden/Handlers/SwitchHandlerMappings.cs
new file mode 100644
index 000000000..9b0067d69
--- /dev/null
+++ b/src/Maui/Bitwarden/Handlers/SwitchHandlerMappings.cs
@@ -0,0 +1,9 @@
+namespace Bit.App.Handlers
+{
+ public partial class SwitchHandlerMappings
+ {
+ public void Setup() => SetupPlatform();
+
+ partial void SetupPlatform();
+ }
+}
diff --git a/src/Maui/Bitwarden/Handlers/TimePickerHandlerMappings.cs b/src/Maui/Bitwarden/Handlers/TimePickerHandlerMappings.cs
new file mode 100644
index 000000000..7d9b952ce
--- /dev/null
+++ b/src/Maui/Bitwarden/Handlers/TimePickerHandlerMappings.cs
@@ -0,0 +1,9 @@
+namespace Bit.App.Handlers
+{
+ public partial class TimePickerHandlerMappings
+ {
+ public void Setup() => SetupPlatform();
+
+ partial void SetupPlatform();
+ }
+}
diff --git a/src/Maui/Bitwarden/Pages/Settings/SettingsPage/SettingsPageListItem.cs b/src/Maui/Bitwarden/Pages/Settings/SettingsPage/SettingsPageListItem.cs
index fb0d8d862..9817fcdac 100644
--- a/src/Maui/Bitwarden/Pages/Settings/SettingsPage/SettingsPageListItem.cs
+++ b/src/Maui/Bitwarden/Pages/Settings/SettingsPage/SettingsPageListItem.cs
@@ -19,8 +19,8 @@ namespace Bit.App.Pages
public Func ExecuteAsync { get; set; }
public bool SubLabelTextEnabled => SubLabel == AppResources.On;
- public string LineBreakMode => SubLabel == null ? "TailTruncation" : "";
- public bool ShowSubLabel => SubLabel.Length != 0;
+ public LineBreakMode LineBreakMode => SubLabel == null ? LineBreakMode.TailTruncation : LineBreakMode.NoWrap;
+ public bool ShowSubLabel => SubLabel != null && SubLabel.Length != 0;
public bool ShowTimeInput => Time != null;
public Color SubLabelColor => SubLabelTextEnabled ?
ThemeManager.GetResourceColor("SuccessColor") :
diff --git a/src/Maui/Bitwarden/Pages/Vault/CipherAddEditPage.xaml b/src/Maui/Bitwarden/Pages/Vault/CipherAddEditPage.xaml
index 717d4133f..8160df3d8 100644
--- a/src/Maui/Bitwarden/Pages/Vault/CipherAddEditPage.xaml
+++ b/src/Maui/Bitwarden/Pages/Vault/CipherAddEditPage.xaml
@@ -132,7 +132,7 @@
AutomationProperties.Name="{u:I18n Name}"
AutomationId="ItemNameEntry" />
-
+
@@ -308,10 +308,11 @@
AutomationProperties.Name="{u:I18n ScanQrTitle}"
/>
-
-
+
+
-
+
diff --git a/src/Maui/Bitwarden/Pages/Vault/CipherAddEditPageViewModel.cs b/src/Maui/Bitwarden/Pages/Vault/CipherAddEditPageViewModel.cs
index faa692f62..db584f683 100644
--- a/src/Maui/Bitwarden/Pages/Vault/CipherAddEditPageViewModel.cs
+++ b/src/Maui/Bitwarden/Pages/Vault/CipherAddEditPageViewModel.cs
@@ -51,8 +51,8 @@ namespace Bit.App.Pages
protected override string[] AdditionalPropertiesToRaiseOnCipherChanged => new string[]
{
- nameof(IsLogin),
nameof(IsIdentity),
+ nameof(IsLogin),
nameof(IsCard),
nameof(IsSecureNote),
nameof(ShowUris),
@@ -287,7 +287,7 @@ namespace Bit.App.Pages
nameof(ShowCollections)
});
}
- public bool ShowCollections => (!EditMode || CloneMode) && Cipher.OrganizationId != null;
+ public bool ShowCollections => (!EditMode || CloneMode) && Cipher?.OrganizationId != null;
public bool EditMode => !string.IsNullOrWhiteSpace(CipherId);
public bool ShowOwnershipOptions => !EditMode || CloneMode;
public bool OwnershipPolicyInEffect => ShowOwnershipOptions && !AllowPersonal;
@@ -298,15 +298,15 @@ namespace Bit.App.Pages
public bool IsCard => Cipher?.Type == CipherType.Card;
public bool IsSecureNote => Cipher?.Type == CipherType.SecureNote;
public bool IsFido2Key => Cipher?.Type == CipherType.Fido2Key;
- public bool ShowUris => IsLogin && Cipher.Login.HasUris;
- public bool ShowAttachments => Cipher.HasAttachments;
+ public bool ShowUris => IsLogin && Cipher != null && Cipher.Login.HasUris;
+ public bool ShowAttachments => Cipher != null && Cipher.HasAttachments;
public string ShowPasswordIcon => ShowPassword ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public string ShowCardNumberIcon => ShowCardNumber ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
public string ShowCardCodeIcon => ShowCardCode ? BitwardenIcons.EyeSlash : BitwardenIcons.Eye;
- public int PasswordFieldColSpan => Cipher.ViewPassword ? 1 : 4;
- public int TotpColumnSpan => Cipher.ViewPassword ? 1 : 2;
+ public int PasswordFieldColSpan => Cipher != null && Cipher.ViewPassword ? 1 : 4;
+ public int TotpColumnSpan => Cipher != null && Cipher.ViewPassword ? 1 : 2;
public bool AllowPersonal { get; set; }
- public bool PasswordPrompt => Cipher.Reprompt != CipherRepromptType.None;
+ public bool PasswordPrompt => Cipher != null && Cipher.Reprompt != CipherRepromptType.None;
public string PasswordVisibilityAccessibilityText => ShowPassword ? AppResources.PasswordIsVisibleTapToHide : AppResources.PasswordIsNotVisibleTapToShow;
public bool HasTotpValue => IsLogin && !string.IsNullOrEmpty(Cipher?.Login?.Totp);
public string SetupTotpText => $"{BitwardenIcons.Camera} {AppResources.SetupTotp}";
@@ -459,6 +459,12 @@ namespace Bit.App.Pages
}
_previousCipherId = CipherId;
+ MainThread.BeginInvokeOnMainThread(() =>
+ {
+ TriggerPropertyChanged(nameof(OwnershipOptions));
+ TriggerPropertyChanged(nameof(OwnershipSelectedIndex));
+ });
+
return true;
}
@@ -892,7 +898,7 @@ namespace Bit.App.Pages
private void TriggerCipherChanged()
{
- TriggerPropertyChanged(nameof(Cipher), AdditionalPropertiesToRaiseOnCipherChanged);
+ MainThread.BeginInvokeOnMainThread(() => TriggerPropertyChanged(nameof(Cipher), AdditionalPropertiesToRaiseOnCipherChanged));
}
private async Task CopyTotpClipboardAsync()
diff --git a/src/Maui/Bitwarden/Platforms/Android/Handlers/ButtonHandlerMappings.cs b/src/Maui/Bitwarden/Platforms/Android/Handlers/ButtonHandlerMappings.cs
new file mode 100644
index 000000000..bc48a7960
--- /dev/null
+++ b/src/Maui/Bitwarden/Platforms/Android/Handlers/ButtonHandlerMappings.cs
@@ -0,0 +1,18 @@
+using Bit.App.Controls;
+
+namespace Bit.App.Handlers
+{
+ public partial class ButtonHandlerMappings
+ {
+ partial void SetupPlatform()
+ {
+ Microsoft.Maui.Handlers.ButtonHandler.Mapper.AppendToMapping("CustomButtonHandler", (handler, button) =>
+ {
+ if (button is IconButton || button is MiButton)
+ {
+ handler.PlatformView.SetBackgroundResource(0);
+ }
+ });
+ }
+ }
+}
diff --git a/src/Maui/Bitwarden/Platforms/Android/Handlers/DatePickerHandlerMappings.cs b/src/Maui/Bitwarden/Platforms/Android/Handlers/DatePickerHandlerMappings.cs
new file mode 100644
index 000000000..e313e60f4
--- /dev/null
+++ b/src/Maui/Bitwarden/Platforms/Android/Handlers/DatePickerHandlerMappings.cs
@@ -0,0 +1,39 @@
+using Android.Views;
+using Bit.App.Controls;
+using Microsoft.Maui.Handlers;
+
+namespace Bit.App.Handlers
+{
+ public partial class DatePickerHandlerMappings
+ {
+ partial void SetupPlatform()
+ {
+ DatePickerHandler.Mapper.AppendToMapping("CustomDatePickerHandler", (handler, datePicker) =>
+ {
+ if (datePicker is ExtendedDatePicker extDatePicker)
+ {
+ // center text
+ handler.PlatformView.Gravity = GravityFlags.CenterHorizontal;
+
+ // use placeholder until NullableDate set
+ if (!extDatePicker.NullableDate.HasValue)
+ {
+ handler.PlatformView.Text = extDatePicker.PlaceHolder;
+ }
+ }
+ });
+
+ DatePickerHandler.Mapper.AppendToMapping(nameof(IDatePicker.Date), UpdateTextPlaceholderOnFormatLikePlacholder);
+
+ DatePickerHandler.Mapper.AppendToMapping(nameof(IDatePicker.Format), UpdateTextPlaceholderOnFormatLikePlacholder);
+ }
+
+ private void UpdateTextPlaceholderOnFormatLikePlacholder(IDatePickerHandler handler, IDatePicker datePicker)
+ {
+ if (datePicker is ExtendedDatePicker extDatePicker && extDatePicker.Format == extDatePicker.PlaceHolder)
+ {
+ handler.PlatformView.Text = extDatePicker.PlaceHolder;
+ }
+ }
+ }
+}
diff --git a/src/Maui/Bitwarden/Platforms/Android/Handlers/EditorHandlerMappings.cs b/src/Maui/Bitwarden/Platforms/Android/Handlers/EditorHandlerMappings.cs
new file mode 100644
index 000000000..a6349e59f
--- /dev/null
+++ b/src/Maui/Bitwarden/Platforms/Android/Handlers/EditorHandlerMappings.cs
@@ -0,0 +1,24 @@
+using Android.Views.InputMethods;
+using Bit.App.Droid.Utilities;
+
+namespace Bit.App.Handlers
+{
+ public partial class EditorHandlerMappings
+ {
+ partial void SetupPlatform()
+ {
+ Microsoft.Maui.Handlers.EditorHandler.Mapper.AppendToMapping("CustomEditorHandler", (handler, editor) =>
+ {
+ handler.PlatformView.SetPadding(handler.PlatformView.PaddingLeft, handler.PlatformView.PaddingTop - 10, handler.PlatformView.PaddingRight,
+ handler.PlatformView.PaddingBottom + 20);
+ handler.PlatformView.ImeOptions = handler.PlatformView.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
+ (ImeAction)ImeFlags.NoExtractUi;
+ });
+
+ Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(nameof(IEditor.TextColor), (handler, editor) =>
+ {
+ handler.PlatformView.BackgroundTintList = ThemeHelpers.GetStateFocusedColors();
+ });
+ }
+ }
+}
diff --git a/src/Maui/Bitwarden/Platforms/Android/Handlers/EntryHandlerMappings.cs b/src/Maui/Bitwarden/Platforms/Android/Handlers/EntryHandlerMappings.cs
new file mode 100644
index 000000000..4ac287295
--- /dev/null
+++ b/src/Maui/Bitwarden/Platforms/Android/Handlers/EntryHandlerMappings.cs
@@ -0,0 +1,63 @@
+using Android.Graphics;
+using Android.Text;
+using Android.Views.InputMethods;
+using Android.Widget;
+using Bit.App.Droid.Utilities;
+using Microsoft.Maui.Platform;
+
+namespace Bit.App.Handlers
+{
+ public partial class EntryHandlerMappings
+ {
+ partial void SetupPlatform()
+ {
+ Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("CustomEntryHandler", (handler, entry) =>
+ {
+ handler.PlatformView.SetPadding(handler.PlatformView.PaddingLeft, handler.PlatformView.PaddingTop - 10, handler.PlatformView.PaddingRight,
+ handler.PlatformView.PaddingBottom + 20);
+ handler.PlatformView.ImeOptions = handler.PlatformView.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
+ (ImeAction)ImeFlags.NoExtractUi;
+ });
+
+ Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(nameof(IEntry.TextColor), (handler, entry) =>
+ {
+ handler.PlatformView.BackgroundTintList = ThemeHelpers.GetStateFocusedColors();
+ });
+
+ Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping(nameof(IEntry.IsPassword), (handler, entry) =>
+ {
+ // Check if field type is text, otherwise ignore (numeric passwords, etc.)
+ handler.PlatformView.InputType = entry.Keyboard.ToInputType();
+ bool isText = (handler.PlatformView.InputType & InputTypes.ClassText) == InputTypes.ClassText,
+ isNumber = (handler.PlatformView.InputType & InputTypes.ClassNumber) == InputTypes.ClassNumber;
+ if (!isText && !isNumber)
+ {
+ return;
+ }
+
+ if (entry.IsPassword)
+ {
+ // Element is a password field, set inputType to TextVariationPassword which disables
+ // predictive text by default
+ handler.PlatformView.InputType = handler.PlatformView.InputType |
+ (isText ? InputTypes.TextVariationPassword : InputTypes.NumberVariationPassword);
+ }
+ else
+ {
+ // Element is not a password field, set inputType to TextVariationVisiblePassword to
+ // disable predictive text while still displaying the content.
+ handler.PlatformView.InputType = handler.PlatformView.InputType |
+ (isText ? InputTypes.TextVariationVisiblePassword : InputTypes.NumberVariationNormal);
+ }
+
+ // The workaround above forces a reset of the style properties, so we need to re-apply the font.
+ // see https://xamarin.github.io/bugzilla-archives/33/33666/bug.html
+ var typeface = Typeface.CreateFromAsset(handler.PlatformView.Context.Assets, "RobotoMono_Regular.ttf");
+ if (handler.PlatformView is TextView label)
+ {
+ label.Typeface = typeface;
+ }
+ });
+ }
+ }
+}
diff --git a/src/Maui/Bitwarden/Platforms/Android/Handlers/LabelHandlerMappings.cs b/src/Maui/Bitwarden/Platforms/Android/Handlers/LabelHandlerMappings.cs
new file mode 100644
index 000000000..868deab59
--- /dev/null
+++ b/src/Maui/Bitwarden/Platforms/Android/Handlers/LabelHandlerMappings.cs
@@ -0,0 +1,31 @@
+using Android.OS;
+using Bit.App.Controls;
+
+namespace Bit.App.Handlers
+{
+ public partial class LabelHandlerMappings
+ {
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "")]
+ partial void SetupPlatform()
+ {
+ Microsoft.Maui.Handlers.LabelHandler.Mapper.AppendToMapping("CustomLabelHandler", (handler, label) =>
+ {
+ if (label is CustomLabel customLabel && customLabel.FontWeight.HasValue && Build.VERSION.SdkInt >= BuildVersionCodes.P)
+ {
+ handler.PlatformView.Typeface = Android.Graphics.Typeface.Create(null, customLabel.FontWeight.Value, false);
+ return;
+ }
+
+ if (label is SelectableLabel)
+ {
+ handler.PlatformView.SetTextIsSelectable(true);
+ }
+ });
+
+ Microsoft.Maui.Handlers.LabelHandler.Mapper.AppendToMapping(nameof(ILabel.AutomationId), (handler, label) =>
+ {
+ handler.PlatformView.ContentDescription = label.AutomationId;
+ });
+ }
+ }
+}
diff --git a/src/Maui/Bitwarden/Platforms/Android/Handlers/PickerHandlerMappings.cs b/src/Maui/Bitwarden/Platforms/Android/Handlers/PickerHandlerMappings.cs
new file mode 100644
index 000000000..54bdac19d
--- /dev/null
+++ b/src/Maui/Bitwarden/Platforms/Android/Handlers/PickerHandlerMappings.cs
@@ -0,0 +1,21 @@
+using Bit.App.Droid.Utilities;
+
+namespace Bit.App.Handlers
+{
+ public partial class PickerHandlerMappings
+ {
+ partial void SetupPlatform()
+ {
+ Microsoft.Maui.Handlers.PickerHandler.Mapper.AppendToMapping("CustomPickerHandler", (handler, picker) =>
+ {
+ handler.PlatformView.SetPadding(handler.PlatformView.PaddingLeft, handler.PlatformView.PaddingTop - 10,
+ handler.PlatformView.PaddingRight, handler.PlatformView.PaddingBottom + 20);
+ });
+
+ Microsoft.Maui.Handlers.PickerHandler.Mapper.AppendToMapping(nameof(IPicker.TextColor), (handler, picker) =>
+ {
+ handler.PlatformView.BackgroundTintList = ThemeHelpers.GetStateFocusedColors();
+ });
+ }
+ }
+}
diff --git a/src/Maui/Bitwarden/Platforms/Android/Handlers/SearchBarHandlerMappings.cs b/src/Maui/Bitwarden/Platforms/Android/Handlers/SearchBarHandlerMappings.cs
new file mode 100644
index 000000000..a5473f69e
--- /dev/null
+++ b/src/Maui/Bitwarden/Platforms/Android/Handlers/SearchBarHandlerMappings.cs
@@ -0,0 +1,26 @@
+using Android.Views.InputMethods;
+
+namespace Bit.App.Handlers
+{
+ public partial class SearchBarHandlerMappings
+ {
+ partial void SetupPlatform()
+ {
+ Microsoft.Maui.Handlers.SearchBarHandler.Mapper.AppendToMapping("CustomSearchBarHandler", (handler, searchBar) =>
+ {
+ try
+ {
+ var magId = handler.PlatformView.Resources.GetIdentifier("android:id/search_mag_icon", null, null);
+ var magImage = (Android.Widget.ImageView)handler.PlatformView.FindViewById(magId);
+ magImage.LayoutParameters = new Android.Widget.LinearLayout.LayoutParams(0, 0);
+ }
+ catch { }
+ // TODO: [MAUI-Migration] [Check]
+ handler.PlatformView.ImeOptions = handler.PlatformView.ImeOptions | (int)ImeFlags.NoPersonalizedLearning |
+ (int)ImeFlags.NoExtractUi;
+ //Control.SetImeOptions(Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
+ // (ImeAction)ImeFlags.NoExtractUi);
+ });
+ }
+ }
+}
diff --git a/src/Maui/Bitwarden/Platforms/Android/Handlers/SliderHandlerMappings.cs b/src/Maui/Bitwarden/Platforms/Android/Handlers/SliderHandlerMappings.cs
new file mode 100644
index 000000000..a857de2cf
--- /dev/null
+++ b/src/Maui/Bitwarden/Platforms/Android/Handlers/SliderHandlerMappings.cs
@@ -0,0 +1,32 @@
+using Android.Graphics.Drawables;
+using AndroidX.Core.Content.Resources;
+using Bit.App.Controls;
+using Microsoft.Maui.Controls.Compatibility.Platform.Android;
+
+namespace Bit.App.Handlers
+{
+ public partial class SliderHandlerMappings
+ {
+ partial void SetupPlatform()
+ {
+ Microsoft.Maui.Handlers.SliderHandler.Mapper.AppendToMapping(nameof(ExtendedSlider.ThumbBorderColor), (handler, slider) =>
+ {
+ var t = ResourcesCompat.GetDrawable(handler.PlatformView.Resources, Resource.Drawable.slider_thumb, null);
+ if (t is GradientDrawable thumb && slider is ExtendedSlider extSlider)
+ {
+ // TODO: [MAUI-Migration]
+ //if (view.ThumbColor == Colors.Default)
+ //{
+ // thumb.SetColor(Colors.White.ToAndroid());
+ //}
+ //else
+ //{
+ thumb.SetColor(extSlider.ThumbColor.ToAndroid());
+ //}
+ thumb.SetStroke(3, extSlider.ThumbBorderColor.ToAndroid());
+ handler.PlatformView.SetThumb(thumb);
+ }
+ });
+ }
+ }
+}
diff --git a/src/Maui/Bitwarden/Platforms/Android/Handlers/StepperHandlerMappings.cs b/src/Maui/Bitwarden/Platforms/Android/Handlers/StepperHandlerMappings.cs
new file mode 100644
index 000000000..dc52fd66a
--- /dev/null
+++ b/src/Maui/Bitwarden/Platforms/Android/Handlers/StepperHandlerMappings.cs
@@ -0,0 +1,45 @@
+using Android.Graphics;
+using Android.OS;
+using Bit.App.Controls;
+using Microsoft.Maui.Controls.Compatibility.Platform.Android;
+
+namespace Bit.App.Handlers
+{
+ public partial class StepperHandlerMappings
+ {
+ partial void SetupPlatform()
+ {
+ Microsoft.Maui.Handlers.StepperHandler.Mapper.AppendToMapping(nameof(ExtendedStepper.StepperBackgroundColor), (handler, stepper) =>
+ {
+ if (stepper is ExtendedStepper extStepper)
+ {
+ if (Build.VERSION.SdkInt >= BuildVersionCodes.Q)
+ {
+ handler.PlatformView.GetChildAt(0)?.Background?.SetColorFilter(
+ new BlendModeColorFilter(extStepper.StepperBackgroundColor.ToAndroid(), Android.Graphics.BlendMode.Multiply));
+ handler.PlatformView.GetChildAt(1)?.Background?.SetColorFilter(
+ new BlendModeColorFilter(extStepper.StepperBackgroundColor.ToAndroid(), Android.Graphics.BlendMode.Multiply));
+ }
+ else
+ {
+ handler.PlatformView.GetChildAt(0)?.Background?.SetColorFilter(
+ extStepper.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
+ handler.PlatformView.GetChildAt(1)?.Background?.SetColorFilter(
+ extStepper.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
+ }
+ }
+ });
+
+ Microsoft.Maui.Handlers.StepperHandler.Mapper.AppendToMapping(nameof(ExtendedStepper.StepperForegroundColor), (handler, stepper) =>
+ {
+ if (stepper is ExtendedStepper extStepper)
+ {
+ var btn0 = handler.PlatformView.GetChildAt(0) as Android.Widget.Button;
+ btn0?.SetTextColor(extStepper.StepperForegroundColor.ToAndroid());
+ var btn1 = handler.PlatformView.GetChildAt(1) as Android.Widget.Button;
+ btn1?.SetTextColor(extStepper.StepperForegroundColor.ToAndroid());
+ }
+ });
+ }
+ }
+}
diff --git a/src/Maui/Bitwarden/Platforms/Android/Handlers/SwitchHandlerMappings.cs b/src/Maui/Bitwarden/Platforms/Android/Handlers/SwitchHandlerMappings.cs
new file mode 100644
index 000000000..45ff18ab7
--- /dev/null
+++ b/src/Maui/Bitwarden/Platforms/Android/Handlers/SwitchHandlerMappings.cs
@@ -0,0 +1,42 @@
+using Android.Content.Res;
+using Android.Graphics.Drawables;
+using Android.OS;
+using AndroidX.Core.Content.Resources;
+using Bit.App.Droid.Utilities;
+
+namespace Bit.App.Handlers
+{
+ public partial class SwitchHandlerMappings
+ {
+ partial void SetupPlatform()
+ {
+ if (Build.VERSION.SdkInt <= BuildVersionCodes.LollipopMr1)
+ {
+ // Android 5.x doesn't support ThumbTintList, and using SwitchCompat on every version after 5.x
+ // doesn't apply tinting the way we want. Let 5.x to do its own thing here.
+ return;
+ }
+
+ Microsoft.Maui.Handlers.SwitchHandler.Mapper.AppendToMapping(nameof(ISwitch.ThumbColor), (handler, mauiSwitch) =>
+ {
+ handler.PlatformView.SetHintTextColor(ThemeHelpers.MutedColor);
+ var t = ResourcesCompat.GetDrawable(handler.PlatformView.Resources, Resource.Drawable.switch_thumb, null);
+ if (t is GradientDrawable thumb)
+ {
+ handler.PlatformView.ThumbDrawable = thumb;
+ }
+ var thumbStates = new[]
+ {
+ new[] { Android.Resource.Attribute.StateChecked }, // checked
+ new[] { -Android.Resource.Attribute.StateChecked }, // unchecked
+ };
+ var thumbColors = new int[]
+ {
+ ThemeHelpers.SwitchOnColor,
+ ThemeHelpers.SwitchThumbColor
+ };
+ handler.PlatformView.ThumbTintList = new ColorStateList(thumbStates, thumbColors);
+ });
+ }
+ }
+}
diff --git a/src/Maui/Bitwarden/Platforms/Android/Handlers/TimePickerHandlerMappings.cs b/src/Maui/Bitwarden/Platforms/Android/Handlers/TimePickerHandlerMappings.cs
new file mode 100644
index 000000000..e73cf46fb
--- /dev/null
+++ b/src/Maui/Bitwarden/Platforms/Android/Handlers/TimePickerHandlerMappings.cs
@@ -0,0 +1,39 @@
+using Android.Views;
+using Bit.App.Controls;
+using Microsoft.Maui.Handlers;
+
+namespace Bit.App.Handlers
+{
+ public partial class TimePickerHandlerMappings
+ {
+ partial void SetupPlatform()
+ {
+ TimePickerHandler.Mapper.AppendToMapping("CustomTimePickerHandler", (handler, timePicker) =>
+ {
+ if (timePicker is ExtendedTimePicker extTimePicker)
+ {
+ // center text
+ handler.PlatformView.Gravity = GravityFlags.CenterHorizontal;
+
+ // use placeholder until NullableTime set
+ if (!extTimePicker.NullableTime.HasValue)
+ {
+ handler.PlatformView.Text = extTimePicker.PlaceHolder;
+ }
+ }
+ });
+
+ TimePickerHandler.Mapper.AppendToMapping(nameof(ITimePicker.Time), UpdateTextPlaceholderOnFormatLikePlacholder);
+
+ TimePickerHandler.Mapper.AppendToMapping(nameof(ITimePicker.Format), UpdateTextPlaceholderOnFormatLikePlacholder);
+ }
+
+ private void UpdateTextPlaceholderOnFormatLikePlacholder(ITimePickerHandler handler, ITimePicker timePicker)
+ {
+ if (timePicker is ExtendedTimePicker extDatePicker && extDatePicker.Format == extDatePicker.PlaceHolder)
+ {
+ handler.PlatformView.Text = extDatePicker.PlaceHolder;
+ }
+ }
+ }
+}
diff --git a/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomTabbedRenderer.cs b/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomTabbedRenderer.cs
index 31f73b264..dc14611ef 100644
--- a/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomTabbedRenderer.cs
+++ b/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomTabbedRenderer.cs
@@ -10,6 +10,7 @@ using Microsoft.Maui.Controls.Platform;
namespace Bit.App.Droid.Renderers
{
+ // TODO: Convert to handler
public class CustomTabbedRenderer : TabbedPageRenderer, NavigationBarView.IOnItemReselectedListener
{
private TabbedPage _page;
diff --git a/src/Maui/Bitwarden/Platforms/Android/Renderers/ExtendedGridRenderer.cs b/src/Maui/Bitwarden/Platforms/Android/Renderers/ExtendedGridRenderer.cs
index 64c1e27c8..fbb9ac60e 100644
--- a/src/Maui/Bitwarden/Platforms/Android/Renderers/ExtendedGridRenderer.cs
+++ b/src/Maui/Bitwarden/Platforms/Android/Renderers/ExtendedGridRenderer.cs
@@ -6,6 +6,7 @@ using Microsoft.Maui.Controls.Platform;
namespace Bit.App.Droid.Renderers
{
+ // TODO: Convert to handler
public class ExtendedGridRenderer : ViewRenderer
{
public ExtendedGridRenderer(Context context) : base(context) { }
diff --git a/src/Maui/Bitwarden/Platforms/Android/Renderers/ExtendedStackLayoutRenderer.cs b/src/Maui/Bitwarden/Platforms/Android/Renderers/ExtendedStackLayoutRenderer.cs
index 545729969..976a51e97 100644
--- a/src/Maui/Bitwarden/Platforms/Android/Renderers/ExtendedStackLayoutRenderer.cs
+++ b/src/Maui/Bitwarden/Platforms/Android/Renderers/ExtendedStackLayoutRenderer.cs
@@ -6,6 +6,7 @@ using Microsoft.Maui.Controls.Platform;
namespace Bit.App.Droid.Renderers
{
+ // TODO: Convert to handler
public class ExtendedStackLayoutRenderer : ViewRenderer
{
public ExtendedStackLayoutRenderer(Context context) : base(context) { }
diff --git a/src/Maui/Bitwarden/Platforms/Android/Resources/values-night/styles.xml b/src/Maui/Bitwarden/Platforms/Android/Resources/values-night/styles.xml
index edfaaa455..0b5876f35 100644
--- a/src/Maui/Bitwarden/Platforms/Android/Resources/values-night/styles.xml
+++ b/src/Maui/Bitwarden/Platforms/Android/Resources/values-night/styles.xml
@@ -7,7 +7,7 @@
- @drawable/splash_screen_round
-