diff --git a/src/Maui/Bitwarden/Bitwarden.csproj b/src/Maui/Bitwarden/Bitwarden.csproj index 9b6ecb85f..3f4fde0cf 100644 --- a/src/Maui/Bitwarden/Bitwarden.csproj +++ b/src/Maui/Bitwarden/Bitwarden.csproj @@ -45,10 +45,8 @@ - - - + @@ -302,6 +300,10 @@ + + + + @@ -313,6 +315,7 @@ + diff --git a/src/Maui/Bitwarden/Controls/IconButton.cs b/src/Maui/Bitwarden/Controls/IconButton.cs index d27d50626..faa4ab8ed 100644 --- a/src/Maui/Bitwarden/Controls/IconButton.cs +++ b/src/Maui/Bitwarden/Controls/IconButton.cs @@ -16,7 +16,7 @@ namespace Bit.App.Controls FontFamily = "bwi-font"; break; case Device.Android: - FontFamily = "bwi-font.ttf#bwi-font"; + FontFamily = "bwi-font"; break; } diff --git a/src/Maui/Bitwarden/Controls/IconLabel.cs b/src/Maui/Bitwarden/Controls/IconLabel.cs index 6b5e72308..3df6881ec 100644 --- a/src/Maui/Bitwarden/Controls/IconLabel.cs +++ b/src/Maui/Bitwarden/Controls/IconLabel.cs @@ -17,7 +17,7 @@ namespace Bit.App.Controls FontFamily = "bwi-font"; break; case Device.Android: - FontFamily = "bwi-font.ttf#bwi-font"; + FontFamily = "bwi-font"; break; } diff --git a/src/Maui/Bitwarden/Controls/MiButton.cs b/src/Maui/Bitwarden/Controls/MiButton.cs index 99309351b..a181ab177 100644 --- a/src/Maui/Bitwarden/Controls/MiButton.cs +++ b/src/Maui/Bitwarden/Controls/MiButton.cs @@ -15,7 +15,7 @@ namespace Bit.App.Controls FontFamily = "Material Icons"; break; case Device.Android: - FontFamily = "MaterialIcons_Regular.ttf#Material Icons"; + FontFamily = "MaterialIcons_Regular"; break; } } diff --git a/src/Maui/Bitwarden/Controls/MiLabel.cs b/src/Maui/Bitwarden/Controls/MiLabel.cs index 4d510899f..603a3a738 100644 --- a/src/Maui/Bitwarden/Controls/MiLabel.cs +++ b/src/Maui/Bitwarden/Controls/MiLabel.cs @@ -14,7 +14,7 @@ namespace Bit.App.Controls FontFamily = "Material Icons"; break; case Device.Android: - FontFamily = "MaterialIcons_Regular.ttf#Material Icons"; + FontFamily = "MaterialIcons_Regular"; break; } } diff --git a/src/Maui/Bitwarden/Controls/MonoEntry.cs b/src/Maui/Bitwarden/Controls/MonoEntry.cs index dfa85d849..9bbff5bce 100644 --- a/src/Maui/Bitwarden/Controls/MonoEntry.cs +++ b/src/Maui/Bitwarden/Controls/MonoEntry.cs @@ -7,16 +7,11 @@ namespace Bit.App.Controls { public MonoEntry() { - // 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 = "Menlo-Regular"; - break; - case Device.Android: - FontFamily = "RobotoMono_Regular.ttf#Roboto Mono"; - break; - } +#if ANDROID + FontFamily = "RobotoMono_Regular"; +#elif IOS + FontFamily = "Menlo-Regular"; +#endif } } } diff --git a/src/Maui/Bitwarden/Controls/MonoLabel.cs b/src/Maui/Bitwarden/Controls/MonoLabel.cs index 6baaf399e..b4da3f7a5 100644 --- a/src/Maui/Bitwarden/Controls/MonoLabel.cs +++ b/src/Maui/Bitwarden/Controls/MonoLabel.cs @@ -14,7 +14,7 @@ namespace Bit.App.Controls FontFamily = "Menlo-Regular"; break; case Device.Android: - FontFamily = "RobotoMono_Regular.ttf#Roboto Mono"; + FontFamily = "RobotoMono_Regular"; break; } } diff --git a/src/Maui/Bitwarden/Effects/FabShadowEffect.cs b/src/Maui/Bitwarden/Effects/FabShadowEffect.cs index 2cdd37a02..58806646d 100644 --- a/src/Maui/Bitwarden/Effects/FabShadowEffect.cs +++ b/src/Maui/Bitwarden/Effects/FabShadowEffect.cs @@ -1,12 +1,38 @@ using Microsoft.Maui.Controls; using Microsoft.Maui; +using Microsoft.Maui.Controls.Platform; + +#if ANDROID +using Android.Graphics.Drawables; +using Bit.App.Droid.Utilities; +#endif namespace Bit.App.Effects { public class FabShadowEffect : RoutingEffect { - public FabShadowEffect() - : base("Bitwarden.FabShadowEffect") - { } } + +#if ANDROID + public class FabShadowPlatformEffect : PlatformEffect + { + protected override void OnAttached() + { + if (Control is Android.Widget.Button button) + { + var gd = new GradientDrawable(); + gd.SetColor(ThemeHelpers.FabColor); + gd.SetCornerRadius(100); + + button.SetBackground(gd); + button.Elevation = 6; + button.TranslationZ = 20; + } + } + + protected override void OnDetached() + { + } + } +#endif } diff --git a/src/Maui/Bitwarden/Effects/FixedSizeEffect.cs b/src/Maui/Bitwarden/Effects/FixedSizeEffect.cs index 471151cab..7cfb83e97 100644 --- a/src/Maui/Bitwarden/Effects/FixedSizeEffect.cs +++ b/src/Maui/Bitwarden/Effects/FixedSizeEffect.cs @@ -1,12 +1,32 @@ using Microsoft.Maui.Controls; using Microsoft.Maui; +using Microsoft.Maui.Controls.Platform; + +#if ANDROID +using Android.Widget; +#endif + namespace Bit.App.Effects { public class FixedSizeEffect : RoutingEffect { - public FixedSizeEffect() - : base("Bitwarden.FixedSizeEffect") - { } } + +#if ANDROID + public class FixedSizePlatformEffect : PlatformEffect + { + protected override void OnAttached() + { + if (Element is Label label && Control is TextView textView) + { + textView.SetTextSize(Android.Util.ComplexUnitType.Pt, (float)label.FontSize); + } + } + + protected override void OnDetached() + { + } + } +#endif } diff --git a/src/Maui/Bitwarden/Effects/NoEmojiKeyboardEffect.cs b/src/Maui/Bitwarden/Effects/NoEmojiKeyboardEffect.cs index b8830441b..4e0b60bdd 100644 --- a/src/Maui/Bitwarden/Effects/NoEmojiKeyboardEffect.cs +++ b/src/Maui/Bitwarden/Effects/NoEmojiKeyboardEffect.cs @@ -1,13 +1,32 @@ using System; using Microsoft.Maui.Controls; using Microsoft.Maui; +using Microsoft.Maui.Controls.Platform; + +#if ANDROID +using Android.Widget; +#endif namespace Bit.App.Effects { public class NoEmojiKeyboardEffect : RoutingEffect { - public NoEmojiKeyboardEffect() - : base("Bitwarden.NoEmojiKeyboardEffect") - { } } + +#if ANDROID + public class NoEmojiKeyboardPlatformEffect : PlatformEffect + { + protected override void OnAttached() + { + if (Control is EditText editText) + { + editText.InputType = Android.Text.InputTypes.ClassText | Android.Text.InputTypes.TextVariationVisiblePassword | Android.Text.InputTypes.TextFlagMultiLine; + } + } + + protected override void OnDetached() + { + } + } +#endif } diff --git a/src/Maui/Bitwarden/Effects/RemoveFontPaddingEffect.cs b/src/Maui/Bitwarden/Effects/RemoveFontPaddingEffect.cs index 0e5eb29ba..885b5f057 100644 --- a/src/Maui/Bitwarden/Effects/RemoveFontPaddingEffect.cs +++ b/src/Maui/Bitwarden/Effects/RemoveFontPaddingEffect.cs @@ -1,14 +1,32 @@ using System; using Microsoft.Maui.Controls; using Microsoft.Maui; +using Microsoft.Maui.Controls.Platform; +#if ANDROID +using Android.Widget; +#endif namespace Bit.App.Effects { public class RemoveFontPaddingEffect : RoutingEffect { - public RemoveFontPaddingEffect() - : base("Bitwarden.RemoveFontPaddingEffect") - { } } + +#if ANDROID + public class RemoveFontPaddingPlatformEffect : PlatformEffect + { + protected override void OnAttached() + { + if (Control is TextView textView) + { + textView.SetIncludeFontPadding(false); + } + } + + protected override void OnDetached() + { + } + } +#endif } diff --git a/src/Maui/Bitwarden/Effects/TabBarEffect.cs b/src/Maui/Bitwarden/Effects/TabBarEffect.cs index 8e6c46544..41998e844 100644 --- a/src/Maui/Bitwarden/Effects/TabBarEffect.cs +++ b/src/Maui/Bitwarden/Effects/TabBarEffect.cs @@ -1,12 +1,34 @@ using Microsoft.Maui.Controls; using Microsoft.Maui; +using Microsoft.Maui.Controls.Platform; namespace Bit.App.Effects { public class TabBarEffect : RoutingEffect { - public TabBarEffect() - : base("Bitwarden.TabBarEffect") - { } } + +#if ANDROID + public class TabBarPlatformEffect : PlatformEffect + { + protected override void OnAttached() + { + // TODO: [MAUI-Migration] [Critical] + // now Container is View instead of ViewGroup, let's review this + //if (!(Container.GetChildAt(0) is ViewGroup layout)) + //{ + // return; + //} + //if (!(layout.GetChildAt(1) is BottomNavigationView bottomNavigationView)) + //{ + // return; + //} + //bottomNavigationView.LabelVisibilityMode = LabelVisibilityMode.LabelVisibilityLabeled; + } + + protected override void OnDetached() + { + } + } +#endif } diff --git a/src/Maui/Bitwarden/MauiProgram.cs b/src/Maui/Bitwarden/MauiProgram.cs index 8f968c057..64035cb30 100644 --- a/src/Maui/Bitwarden/MauiProgram.cs +++ b/src/Maui/Bitwarden/MauiProgram.cs @@ -1,4 +1,5 @@ using System; +using Bit.App.Controls; using CommunityToolkit.Maui; using FFImageLoading.Maui; using Microsoft.Extensions.Logging; @@ -13,7 +14,7 @@ namespace Bit.App; public static class MauiProgram { - public static MauiApp CreateMauiApp(Action effectsBuilder) + public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder @@ -23,12 +24,47 @@ public static class MauiProgram .UseBarcodeReader() .UseSkiaSharp() .UseFFImageLoading() - .ConfigureEffects(effectsBuilder) + .ConfigureEffects(effects => + { +#if ANDROID + effects.Add(); + effects.Add(); + effects.Add(); + effects.Add(); + effects.Add(); +#endif + }) .ConfigureFonts(fonts => { - fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); - fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); + fonts.AddFont("RobotoMono_Regular.ttf#Roboto Mono", "RobotoMono_Regular"); + fonts.AddFont("bwi-font.ttf#bwi-font", "bwi-font"); + fonts.AddFont("MaterialIcons_Regular.ttf#Material Icons", "MaterialIcons_Regular"); }); + // TODO: [MAUI-Migration] Convert renderers to handlers + // Currently, there's an issue on reusing renderers https://github.com/dotnet/maui/issues/9936 +// .ConfigureMauiHandlers(handlers => +// { +//#if ANDROID +// handlers.AddHandler(typeof(Editor), typeof(Droid.Renderers.CustomEditorRenderer)); +// handlers.AddHandler(typeof(Entry), typeof(Droid.Renderers.CustomEntryRenderer)); +// handlers.AddHandler(typeof(CustomLabel), typeof(Droid.Renderers.CustomLabelRenderer)); +// //handlers.AddHandler(typeof(ContentPage), typeof(Droid.Renderers.CustomPageRenderer)); +// handlers.AddHandler(typeof(Picker), typeof(Droid.Renderers.CustomPickerRenderer)); +// handlers.AddHandler(typeof(SearchBar), typeof(Droid.Renderers.CustomSearchBarRenderer)); +// handlers.AddHandler(typeof(Switch), typeof(Droid.Renderers.CustomSwitchRenderer)); +// handlers.AddHandler(typeof(TabbedPage), typeof(Droid.Renderers.CustomTabbedRenderer)); +// handlers.AddHandler(typeof(ExtendedDatePicker), typeof(Droid.Renderers.ExtendedDatePickerRenderer)); +// handlers.AddHandler(typeof(ExtendedGrid), typeof(Droid.Renderers.ExtendedGridRenderer)); +// handlers.AddHandler(typeof(ExtendedSlider), typeof(Droid.Renderers.ExtendedSliderRenderer)); +// handlers.AddHandler(typeof(ExtendedStackLayout), typeof(Droid.Renderers.ExtendedStackLayoutRenderer)); +// handlers.AddHandler(typeof(ExtendedStepper), typeof(Droid.Renderers.ExtendedStepperRenderer)); +// handlers.AddHandler(typeof(ExtendedTimePicker), typeof(Droid.Renderers.ExtendedTimePickerRenderer)); +// handlers.AddHandler(typeof(HybridWebView), typeof(Droid.Renderers.HybridWebViewRenderer)); +// handlers.AddHandler(typeof(SelectableLabel), typeof(Droid.Renderers.SelectableLabelRenderer)); +//#elif IOS +// // TODO: configure +//#endif +// }); #if DEBUG builder.Logging.AddDebug(); diff --git a/src/Maui/Bitwarden/Pages/Vault/CipherDetailsPageViewModel.cs b/src/Maui/Bitwarden/Pages/Vault/CipherDetailsPageViewModel.cs index 87d54c076..31cbf19c8 100644 --- a/src/Maui/Bitwarden/Pages/Vault/CipherDetailsPageViewModel.cs +++ b/src/Maui/Bitwarden/Pages/Vault/CipherDetailsPageViewModel.cs @@ -199,11 +199,14 @@ namespace Bit.App.Pages Text = string.Format("{0}:", AppResources.PasswordHistory), FontAttributes = FontAttributes.Bold }); - fs.Spans.Add(new Span + if (Cipher?.PasswordHistory != null) { - Text = string.Format(" {0}", Cipher.PasswordHistory.Count.ToString()), - TextColor = ThemeManager.GetResourceColor("PrimaryColor") - }); + fs.Spans.Add(new Span + { + Text = string.Format(" {0}", Cipher.PasswordHistory.Count.ToString()), + TextColor = ThemeManager.GetResourceColor("PrimaryColor") + }); + } return fs; } } diff --git a/src/Maui/Bitwarden/Pages/Vault/GroupingsPage/GroupingsPage.xaml.cs b/src/Maui/Bitwarden/Pages/Vault/GroupingsPage/GroupingsPage.xaml.cs index e2fb773b9..263a8e71f 100644 --- a/src/Maui/Bitwarden/Pages/Vault/GroupingsPage/GroupingsPage.xaml.cs +++ b/src/Maui/Bitwarden/Pages/Vault/GroupingsPage/GroupingsPage.xaml.cs @@ -90,7 +90,7 @@ namespace Bit.App.Pages base.OnAppearing(); if (_syncService.SyncInProgress) { - IsBusy = true; + MainThread.BeginInvokeOnMainThread(() => IsBusy = true); } _accountAvatar?.OnAppearing(); @@ -105,7 +105,7 @@ namespace Bit.App.Pages { if (message.Command == "syncStarted") { - Device.BeginInvokeOnMainThread(() => IsBusy = true); + MainThread.BeginInvokeOnMainThread(() => IsBusy = true); } else if (message.Command == "syncCompleted") { @@ -114,7 +114,7 @@ namespace Bit.App.Pages { _vm.AvatarImageSource = await GetAvatarImageSourceAsync(); } - Device.BeginInvokeOnMainThread(() => + MainThread.BeginInvokeOnMainThread(() => { IsBusy = false; if (_vm.LoadedOnce) diff --git a/src/Maui/Bitwarden/Platforms/Android/Effects/FabShadowEffect.cs b/src/Maui/Bitwarden/Platforms/Android/Effects/FabShadowEffect.cs deleted file mode 100644 index 0b89e06be..000000000 --- a/src/Maui/Bitwarden/Platforms/Android/Effects/FabShadowEffect.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Android.Graphics.Drawables; -using Bit.App.Droid.Effects; -using Bit.App.Droid.Utilities; -using Microsoft.Maui.Controls.Platform; - -[assembly: ExportEffect(typeof(FabShadowEffect), "FabShadowEffect")] -namespace Bit.App.Droid.Effects -{ - public class FabShadowEffect : PlatformEffect - { - protected override void OnAttached () - { - if (Control is Android.Widget.Button button) - { - var gd = new GradientDrawable(); - gd.SetColor(ThemeHelpers.FabColor); - gd.SetCornerRadius(100); - - button.SetBackground(gd); - button.Elevation = 6; - button.TranslationZ = 20; - } - } - - protected override void OnDetached () - { - } - } -} diff --git a/src/Maui/Bitwarden/Platforms/Android/Effects/FixedSizeEffect.cs b/src/Maui/Bitwarden/Platforms/Android/Effects/FixedSizeEffect.cs deleted file mode 100644 index e18ea1ae8..000000000 --- a/src/Maui/Bitwarden/Platforms/Android/Effects/FixedSizeEffect.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Android.Widget; -using Bit.App.Droid.Effects; -using Microsoft.Maui.Controls.Platform; - -[assembly: ExportEffect(typeof(FixedSizeEffect), "FixedSizeEffect")] -namespace Bit.App.Droid.Effects -{ - public class FixedSizeEffect : PlatformEffect - { - protected override void OnAttached() - { - if (Element is Label label && Control is TextView textView) - { - textView.SetTextSize(Android.Util.ComplexUnitType.Pt, (float)label.FontSize); - } - } - - protected override void OnDetached() - { - } - } -} diff --git a/src/Maui/Bitwarden/Platforms/Android/Effects/NoEmojiKeyboardEffect.cs b/src/Maui/Bitwarden/Platforms/Android/Effects/NoEmojiKeyboardEffect.cs deleted file mode 100644 index 9eaa6833a..000000000 --- a/src/Maui/Bitwarden/Platforms/Android/Effects/NoEmojiKeyboardEffect.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Android.Widget; -using Bit.App.Droid.Effects; -using Microsoft.Maui.Controls.Platform; - -[assembly: ExportEffect(typeof(NoEmojiKeyboardEffect), nameof(NoEmojiKeyboardEffect))] -namespace Bit.App.Droid.Effects -{ - public class NoEmojiKeyboardEffect : PlatformEffect - { - protected override void OnAttached() - { - if (Control is EditText editText) - { - editText.InputType = Android.Text.InputTypes.ClassText | Android.Text.InputTypes.TextVariationVisiblePassword | Android.Text.InputTypes.TextFlagMultiLine; - } - } - - protected override void OnDetached() - { - } - } -} - diff --git a/src/Maui/Bitwarden/Platforms/Android/Effects/RemoveFontPaddingEffect.cs b/src/Maui/Bitwarden/Platforms/Android/Effects/RemoveFontPaddingEffect.cs deleted file mode 100644 index 97e03cd11..000000000 --- a/src/Maui/Bitwarden/Platforms/Android/Effects/RemoveFontPaddingEffect.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Android.Widget; -using Bit.App.Droid.Effects; -using Microsoft.Maui.Controls.Platform; - -[assembly: ExportEffect(typeof(RemoveFontPaddingEffect), nameof(RemoveFontPaddingEffect))] -namespace Bit.App.Droid.Effects -{ - public class RemoveFontPaddingEffect : PlatformEffect - { - protected override void OnAttached() - { - if (Control is TextView textView) - { - textView.SetIncludeFontPadding(false); - } - } - - protected override void OnDetached() - { - } - } -} \ No newline at end of file diff --git a/src/Maui/Bitwarden/Platforms/Android/Effects/TabBarEffect.cs b/src/Maui/Bitwarden/Platforms/Android/Effects/TabBarEffect.cs deleted file mode 100644 index 2ef4c4aa9..000000000 --- a/src/Maui/Bitwarden/Platforms/Android/Effects/TabBarEffect.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Android.Views; -using Bit.App.Droid.Effects; -using Google.Android.Material.BottomNavigation; -using Microsoft.Maui.Controls; -using Microsoft.Maui.Controls.Platform; - -[assembly: ResolutionGroupName("Bitwarden")] -[assembly: ExportEffect(typeof(TabBarEffect), "TabBarEffect")] -namespace Bit.App.Droid.Effects -{ - public class TabBarEffect : PlatformEffect - { - protected override void OnAttached() - { - // TODO: [MAUI-Migration] [Critical] - // now Container is View instead of ViewGroup, let's review this - //if (!(Container.GetChildAt(0) is ViewGroup layout)) - //{ - // return; - //} - //if (!(layout.GetChildAt(1) is BottomNavigationView bottomNavigationView)) - //{ - // return; - //} - //bottomNavigationView.LabelVisibilityMode = LabelVisibilityMode.LabelVisibilityLabeled; - } - - protected override void OnDetached() - { - } - } -} diff --git a/src/Maui/Bitwarden/Platforms/Android/MainApplication.cs b/src/Maui/Bitwarden/Platforms/Android/MainApplication.cs index ef2964c34..810e3e622 100644 --- a/src/Maui/Bitwarden/Platforms/Android/MainApplication.cs +++ b/src/Maui/Bitwarden/Platforms/Android/MainApplication.cs @@ -98,16 +98,7 @@ namespace Bit.App.Droid #endif } - protected override MauiApp CreateMauiApp() - { - return MauiProgram.CreateMauiApp(effects => - { - effects.Add(); - effects.Add(); - effects.Add(); - effects.Add(); - }); - } + protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp(); public override void OnCreate() { diff --git a/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomEditorRenderer.cs b/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomEditorRenderer.cs new file mode 100644 index 000000000..8c69acced --- /dev/null +++ b/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomEditorRenderer.cs @@ -0,0 +1,67 @@ +using System.ComponentModel; +using Android.Content; +using Android.Content.Res; +using Android.Views.InputMethods; +using Bit.App.Droid.Utilities; +using Microsoft.Maui.Controls.Compatibility.Platform.Android; +using Microsoft.Maui.Controls.Platform; + +namespace Bit.App.Droid.Renderers +{ + public class CustomEditorRenderer : EditorRenderer + { + public CustomEditorRenderer(Context context) + : base(context) + { } + + // Workaround for issue described here: + // https://github.com/xamarin/Xamarin.Forms/issues/8291#issuecomment-617456651 + protected override void OnAttachedToWindow() + { + base.OnAttachedToWindow(); + EditText.Enabled = false; + EditText.Enabled = true; + } + + protected override void OnElementChanged(ElementChangedEventArgs e) + { + base.OnElementChanged(e); + UpdateBorderColor(); + if (Control != null && e.NewElement != null) + { + Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight, + Control.PaddingBottom + 20); + Control.ImeOptions = Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning | + (ImeAction)ImeFlags.NoExtractUi; + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) + { + base.OnElementPropertyChanged(sender, e); + + if (e.PropertyName == Entry.TextColorProperty.PropertyName) + { + UpdateBorderColor(); + } + } + + private void UpdateBorderColor() + { + if (Control != null) + { + var states = new[] + { + new[] { Android.Resource.Attribute.StateFocused }, // focused + new[] { -Android.Resource.Attribute.StateFocused }, // unfocused + }; + var colors = new int[] + { + ThemeHelpers.PrimaryColor, + ThemeHelpers.MutedColor + }; + Control.BackgroundTintList = new ColorStateList(states, colors); + } + } + } +} diff --git a/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomEntryRenderer.cs b/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomEntryRenderer.cs new file mode 100644 index 000000000..e68c8e3af --- /dev/null +++ b/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomEntryRenderer.cs @@ -0,0 +1,106 @@ +using System.ComponentModel; +using Android.Content; +using Android.Content.Res; +using Android.Graphics; +using Android.Text; +using Android.Views.InputMethods; +using Android.Widget; +using Bit.App.Droid.Utilities; +using Microsoft.Maui.Controls.Compatibility.Platform.Android; +using Microsoft.Maui.Controls.Platform; +using Microsoft.Maui.Platform; + +namespace Bit.App.Droid.Renderers +{ + public class CustomEntryRenderer : EntryRenderer + { + public CustomEntryRenderer(Context context) + : base(context) + { } + + protected override void OnElementChanged(ElementChangedEventArgs e) + { + base.OnElementChanged(e); + UpdateBorderColor(); + if (Control != null && e.NewElement != null) + { + Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight, + Control.PaddingBottom + 20); + Control.ImeOptions = Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning | + (ImeAction)ImeFlags.NoExtractUi; + } + } + + // Workaround for bug preventing long-press -> copy/paste on Android 11 + // See https://issuetracker.google.com/issues/37095917 + protected override void OnAttachedToWindow() + { + base.OnAttachedToWindow(); + Control.Enabled = false; + Control.Enabled = true; + } + + // Workaround for failure to disable text prediction on non-password fields + // see https://github.com/xamarin/Xamarin.Forms/issues/10857 + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) + { + base.OnElementPropertyChanged(sender, e); + + // Check if changed property is "IsPassword", otherwise ignore + if (e.PropertyName == Entry.IsPasswordProperty.PropertyName) + { + // Check if field type is text, otherwise ignore (numeric passwords, etc.) + EditText.InputType = Element.Keyboard.ToInputType(); + bool isText = (EditText.InputType & InputTypes.ClassText) == InputTypes.ClassText, + isNumber = (EditText.InputType & InputTypes.ClassNumber) == InputTypes.ClassNumber; + if (isText || isNumber) + { + if (Element.IsPassword) + { + // Element is a password field, set inputType to TextVariationPassword which disables + // predictive text by default + EditText.InputType = EditText.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. + EditText.InputType = EditText.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(Context.Assets, "RobotoMono_Regular.ttf"); + if (Control is TextView label) + { + label.Typeface = typeface; + } + } + } + else if (e.PropertyName == Entry.TextColorProperty.PropertyName) + { + UpdateBorderColor(); + } + } + + private void UpdateBorderColor() + { + if (Control != null) + { + var states = new[] + { + new[] { Android.Resource.Attribute.StateFocused }, // focused + new[] { -Android.Resource.Attribute.StateFocused }, // unfocused + }; + var colors = new int[] + { + ThemeHelpers.PrimaryColor, + ThemeHelpers.MutedColor + }; + Control.BackgroundTintList = new ColorStateList(states, colors); + } + } + } +} diff --git a/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomLabelRenderer.cs b/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomLabelRenderer.cs new file mode 100644 index 000000000..1b0514db5 --- /dev/null +++ b/src/Maui/Bitwarden/Platforms/Android/Renderers/CustomLabelRenderer.cs @@ -0,0 +1,42 @@ +using System.ComponentModel; +using Android.Content; +using Android.OS; +using Bit.App.Controls; +using Bit.App.Droid.Renderers; +using Microsoft.Maui.Controls.Compatibility.Platform.Android; +using Microsoft.Maui.Controls.Platform; + +namespace Bit.App.Droid.Renderers +{ + public class CustomLabelRenderer : LabelRenderer + { + public CustomLabelRenderer(Context context) + : base(context) + { } + + protected override void OnElementChanged(ElementChangedEventArgs