mirror of
https://github.com/bitwarden/mobile
synced 2025-12-05 23:53:33 +00:00
MAUI Migration Single Project - Android - Fonts, renderers, effects
This commit is contained in:
@@ -45,10 +45,8 @@
|
||||
<MauiImage Update="Resources\Images\dotnet_bot.svg" BaseSize="168,208" />
|
||||
|
||||
<!-- Custom Fonts -->
|
||||
<MauiFont Include="Resources\Fonts\*" />
|
||||
|
||||
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
|
||||
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
<MauiFont Include="Resources\Fonts\*" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -302,6 +300,10 @@
|
||||
<None Remove="Platforms\Android\Resources\mipmap-xhdpi\ic_launcher.png" />
|
||||
<None Remove="Platforms\Android\Resources\mipmap-xhdpi\ic_launcher_round.png" />
|
||||
<None Remove="Platforms\Android\google-services.json" />
|
||||
<None Remove="Resources\Fonts\" />
|
||||
<None Remove="Resources\Fonts\bwi-font.ttf" />
|
||||
<None Remove="Resources\Fonts\MaterialIcons_Regular.ttf" />
|
||||
<None Remove="Resources\Fonts\RobotoMono_Regular.ttf" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Core\" />
|
||||
@@ -313,6 +315,7 @@
|
||||
<Folder Include="Core\Resources\" />
|
||||
<Folder Include="Core\Services\" />
|
||||
<Folder Include="Core\Utilities\" />
|
||||
<Folder Include="Resources\Fonts\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Core\Resources\eff_long_word_list.txt" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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<IEffectsBuilder> 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.FabShadowEffect, Effects.FabShadowPlatformEffect>();
|
||||
effects.Add<Effects.FixedSizeEffect, Effects.FixedSizePlatformEffect>();
|
||||
effects.Add<Effects.NoEmojiKeyboardEffect, Effects.NoEmojiKeyboardPlatformEffect>();
|
||||
effects.Add<Effects.TabBarEffect, Effects.TabBarPlatformEffect>();
|
||||
effects.Add<Effects.RemoveFontPaddingEffect, Effects.RemoveFontPaddingPlatformEffect>();
|
||||
#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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,16 +98,7 @@ namespace Bit.App.Droid
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override MauiApp CreateMauiApp()
|
||||
{
|
||||
return MauiProgram.CreateMauiApp(effects =>
|
||||
{
|
||||
effects.Add<Bit.App.Effects.FabShadowEffect, Droid.Effects.FabShadowEffect>();
|
||||
effects.Add<Bit.App.Effects.FixedSizeEffect, Droid.Effects.FixedSizeEffect>();
|
||||
effects.Add<Bit.App.Effects.NoEmojiKeyboardEffect, Droid.Effects.NoEmojiKeyboardEffect>();
|
||||
effects.Add<Bit.App.Effects.TabBarEffect, Droid.Effects.TabBarEffect>();
|
||||
});
|
||||
}
|
||||
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
|
||||
|
||||
public override void OnCreate()
|
||||
{
|
||||
|
||||
@@ -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<Editor> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Entry> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Label> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (Control != null && e.NewElement is CustomLabel label)
|
||||
{
|
||||
if (label.FontWeight.HasValue && Build.VERSION.SdkInt >= BuildVersionCodes.P)
|
||||
{
|
||||
Control.Typeface = Android.Graphics.Typeface.Create(null, label.FontWeight.Value, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
var label = sender as CustomLabel;
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(CustomLabel.AutomationId):
|
||||
Control.ContentDescription = label.AutomationId;
|
||||
break;
|
||||
}
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using AndroidX.AppCompat.Widget;
|
||||
using Bit.App.Resources;
|
||||
using Bit.App.Droid.Renderers;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
|
||||
using Microsoft.Maui.Controls.Platform;
|
||||
using Toolbar = AndroidX.AppCompat.Widget.Toolbar;
|
||||
|
||||
namespace Bit.App.Droid.Renderers
|
||||
{
|
||||
public class CustomPageRenderer : PageRenderer
|
||||
{
|
||||
public CustomPageRenderer(Context context) : base(context)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Page> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
// TODO: [MAUI-Migration] [Critical]
|
||||
//Activity context = (Activity)this.Context;
|
||||
//var toolbar = context.FindViewById<Toolbar>(Android.Resource.Id.toolbar);
|
||||
//if(toolbar != null)
|
||||
//{
|
||||
// toolbar.NavigationContentDescription = AppResources.TapToGoBack;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Content.Res;
|
||||
using Bit.App.Droid.Utilities;
|
||||
using Bit.App.Droid.Renderers;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android.AppCompat;
|
||||
using Microsoft.Maui.Controls.Platform;
|
||||
|
||||
namespace Bit.App.Droid.Renderers
|
||||
{
|
||||
public class CustomPickerRenderer : PickerRenderer
|
||||
{
|
||||
public CustomPickerRenderer(Context context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
UpdateBorderColor();
|
||||
if (Control != null && e.NewElement != null)
|
||||
{
|
||||
Control.SetPadding(Control.PaddingLeft, Control.PaddingTop - 10, Control.PaddingRight,
|
||||
Control.PaddingBottom + 20);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
|
||||
if (e.PropertyName == Picker.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using Android.Content;
|
||||
using Android.Views.InputMethods;
|
||||
using Bit.App.Droid.Renderers;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
|
||||
using Microsoft.Maui.Controls.Platform;
|
||||
|
||||
namespace Bit.App.Droid.Renderers
|
||||
{
|
||||
public class CustomSearchBarRenderer : SearchBarRenderer
|
||||
{
|
||||
public CustomSearchBarRenderer(Context context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && e.NewElement != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var magId = Resources.GetIdentifier("android:id/search_mag_icon", null, null);
|
||||
var magImage = (Android.Widget.ImageView)Control.FindViewById(magId);
|
||||
magImage.LayoutParameters = new Android.Widget.LinearLayout.LayoutParams(0, 0);
|
||||
}
|
||||
catch { }
|
||||
// TODO: [MAUI-Migration] [Check]
|
||||
Control.ImeOptions = Control.ImeOptions | (int)ImeFlags.NoPersonalizedLearning |
|
||||
(int)ImeFlags.NoExtractUi;
|
||||
//Control.SetImeOptions(Control.ImeOptions | (ImeAction)ImeFlags.NoPersonalizedLearning |
|
||||
// (ImeAction)ImeFlags.NoExtractUi);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Content.Res;
|
||||
using Android.Graphics.Drawables;
|
||||
using Android.OS;
|
||||
using AndroidX.Core.Content.Resources;
|
||||
using Bit.App.Droid.Renderers;
|
||||
using Bit.App.Droid.Utilities;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android.AppCompat;
|
||||
using Microsoft.Maui.Controls.Platform;
|
||||
|
||||
namespace Bit.App.Droid.Renderers
|
||||
{
|
||||
public class CustomSwitchRenderer : SwitchRenderer
|
||||
{
|
||||
public CustomSwitchRenderer(Context context)
|
||||
: base(context)
|
||||
{}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
UpdateColors();
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
|
||||
if (e.PropertyName == Switch.OnColorProperty.PropertyName)
|
||||
{
|
||||
UpdateColors();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateColors()
|
||||
{
|
||||
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;
|
||||
}
|
||||
if (Control != null)
|
||||
{
|
||||
Control.SetHintTextColor(ThemeHelpers.MutedColor);
|
||||
var t = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.switch_thumb, null);
|
||||
if (t is GradientDrawable thumb)
|
||||
{
|
||||
Control.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
|
||||
};
|
||||
Control.ThumbTintList = new ColorStateList(thumbStates, thumbColors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using Android.Content;
|
||||
using Android.Views;
|
||||
using Bit.App.Pages;
|
||||
using Bit.App.Droid.Renderers;
|
||||
using Google.Android.Material.BottomNavigation;
|
||||
using Google.Android.Material.Navigation;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android.AppCompat;
|
||||
using Microsoft.Maui.Controls.Platform;
|
||||
|
||||
namespace Bit.App.Droid.Renderers
|
||||
{
|
||||
public class CustomTabbedRenderer : TabbedPageRenderer, NavigationBarView.IOnItemReselectedListener
|
||||
{
|
||||
private TabbedPage _page;
|
||||
|
||||
public CustomTabbedRenderer(Context context) : base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (e.NewElement != null)
|
||||
{
|
||||
_page = e.NewElement;
|
||||
GetBottomNavigationView()?.SetOnItemReselectedListener(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
_page = e.OldElement;
|
||||
}
|
||||
}
|
||||
|
||||
private BottomNavigationView GetBottomNavigationView()
|
||||
{
|
||||
for (var i = 0; i < ChildCount; i++)
|
||||
{
|
||||
var childView = GetChildAt(i);
|
||||
if (childView is ViewGroup viewGroup)
|
||||
{
|
||||
for (var j = 0; j < viewGroup.ChildCount; j++)
|
||||
{
|
||||
var childRelativeLayoutView = viewGroup.GetChildAt(j);
|
||||
if (childRelativeLayoutView is BottomNavigationView bottomNavigationView)
|
||||
{
|
||||
return bottomNavigationView;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void OnNavigationItemReselected(IMenuItem item)
|
||||
{
|
||||
if (_page?.CurrentPage?.Navigation != null && _page.CurrentPage.Navigation.NavigationStack.Count > 0)
|
||||
{
|
||||
if (_page is TabsPage tabsPage)
|
||||
{
|
||||
tabsPage.OnPageReselected();
|
||||
}
|
||||
Device.BeginInvokeOnMainThread(async () => await _page.CurrentPage.Navigation.PopToRootAsync());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Views;
|
||||
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 ExtendedDatePickerRenderer : DatePickerRenderer
|
||||
{
|
||||
public ExtendedDatePickerRenderer(Context context)
|
||||
: base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Android.Content;
|
||||
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 ExtendedGridRenderer : ViewRenderer
|
||||
{
|
||||
public ExtendedGridRenderer(Context context) : base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
|
||||
{
|
||||
base.OnElementChanged(elementChangedEvent);
|
||||
if (elementChangedEvent.NewElement != null)
|
||||
{
|
||||
SetBackgroundResource(Resource.Drawable.list_item_bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Graphics.Drawables;
|
||||
using AndroidX.Core.Content.Resources;
|
||||
using Bit.App.Controls;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
|
||||
using Microsoft.Maui.Controls.Platform;
|
||||
|
||||
namespace Bit.App.Droid.Renderers
|
||||
{
|
||||
public class ExtendedSliderRenderer : SliderRenderer
|
||||
{
|
||||
public ExtendedSliderRenderer(Context context)
|
||||
: base(context)
|
||||
{}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Slider> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
UpdateColor();
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
|
||||
if (e.PropertyName == ExtendedSlider.ThumbBorderColorProperty.PropertyName)
|
||||
{
|
||||
UpdateColor();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateColor()
|
||||
{
|
||||
if (Control != null && Element is ExtendedSlider view)
|
||||
{
|
||||
var t = ResourcesCompat.GetDrawable(Resources, Resource.Drawable.slider_thumb, null);
|
||||
if (t is GradientDrawable thumb)
|
||||
{
|
||||
// TODO: [MAUI-Migration]
|
||||
//if (view.ThumbColor == Colors.Default)
|
||||
//{
|
||||
// thumb.SetColor(Colors.White.ToAndroid());
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
thumb.SetColor(view.ThumbColor.ToAndroid());
|
||||
//}
|
||||
thumb.SetStroke(3, view.ThumbBorderColor.ToAndroid());
|
||||
Control.SetThumb(thumb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Android.Content;
|
||||
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 ExtendedStackLayoutRenderer : ViewRenderer
|
||||
{
|
||||
public ExtendedStackLayoutRenderer(Context context) : base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<View> elementChangedEvent)
|
||||
{
|
||||
base.OnElementChanged(elementChangedEvent);
|
||||
if (elementChangedEvent.NewElement != null)
|
||||
{
|
||||
SetBackgroundResource(Resource.Drawable.list_item_bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Graphics;
|
||||
using Android.OS;
|
||||
using Bit.App.Controls;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
|
||||
using Microsoft.Maui.Controls.Platform;
|
||||
|
||||
namespace Bit.App.Droid.Renderers
|
||||
{
|
||||
public class ExtendedStepperRenderer : StepperRenderer
|
||||
{
|
||||
public ExtendedStepperRenderer(Context context)
|
||||
: base(context)
|
||||
{}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
UpdateBgColor();
|
||||
UpdateFgColor();
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
|
||||
if (e.PropertyName == ExtendedStepper.StepperBackgroundColorProperty.PropertyName)
|
||||
{
|
||||
UpdateBgColor();
|
||||
}
|
||||
else if (e.PropertyName == ExtendedStepper.StepperForegroundColorProperty.PropertyName)
|
||||
{
|
||||
UpdateFgColor();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateBgColor()
|
||||
{
|
||||
if (Control != null && Element is ExtendedStepper view)
|
||||
{
|
||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.Q)
|
||||
{
|
||||
Control.GetChildAt(0)?.Background?.SetColorFilter(
|
||||
new BlendModeColorFilter(view.StepperBackgroundColor.ToAndroid(), Android.Graphics.BlendMode.Multiply));
|
||||
Control.GetChildAt(1)?.Background?.SetColorFilter(
|
||||
new BlendModeColorFilter(view.StepperBackgroundColor.ToAndroid(), Android.Graphics.BlendMode.Multiply));
|
||||
}
|
||||
else
|
||||
{
|
||||
Control.GetChildAt(0)?.Background?.SetColorFilter(
|
||||
view.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
|
||||
Control.GetChildAt(1)?.Background?.SetColorFilter(
|
||||
view.StepperBackgroundColor.ToAndroid(), PorterDuff.Mode.Multiply);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFgColor()
|
||||
{
|
||||
if (Control != null && Element is ExtendedStepper view)
|
||||
{
|
||||
var btn0 = Control.GetChildAt(0) as Android.Widget.Button;
|
||||
btn0?.SetTextColor(view.StepperForegroundColor.ToAndroid());
|
||||
var btn1 = Control.GetChildAt(1) as Android.Widget.Button;
|
||||
btn1?.SetTextColor(view.StepperForegroundColor.ToAndroid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Views;
|
||||
using Bit.App.Controls;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
|
||||
using Microsoft.Maui.Controls.Platform;
|
||||
|
||||
namespace Bit.App.Droid.Renderers
|
||||
{
|
||||
public class ExtendedTimePickerRenderer : TimePickerRenderer
|
||||
{
|
||||
public ExtendedTimePickerRenderer(Context context)
|
||||
: base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.ComponentModel;
|
||||
using Android.Content;
|
||||
using Android.Webkit;
|
||||
using Bit.App.Controls;
|
||||
using Java.Interop;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
|
||||
using Microsoft.Maui.Controls.Platform;
|
||||
using AWebkit = Android.Webkit;
|
||||
|
||||
namespace Bit.App.Droid.Renderers
|
||||
{
|
||||
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, AWebkit.WebView>
|
||||
{
|
||||
private const string JSFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";
|
||||
|
||||
private readonly Context _context;
|
||||
|
||||
public HybridWebViewRenderer(Context context)
|
||||
: base(context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (Control == null)
|
||||
{
|
||||
var webView = new AWebkit.WebView(_context);
|
||||
webView.Settings.JavaScriptEnabled = true;
|
||||
webView.SetWebViewClient(new JSWebViewClient(string.Format("javascript: {0}", JSFunction)));
|
||||
SetNativeControl(webView);
|
||||
}
|
||||
if (e.OldElement != null)
|
||||
{
|
||||
Control.RemoveJavascriptInterface("jsBridge");
|
||||
var hybridWebView = e.OldElement as HybridWebView;
|
||||
hybridWebView.Cleanup();
|
||||
}
|
||||
if (e.NewElement != null)
|
||||
{
|
||||
Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
|
||||
Control.LoadUrl(Element.Uri);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
if (e.PropertyName == HybridWebView.UriProperty.PropertyName)
|
||||
{
|
||||
Control.LoadUrl(Element.Uri);
|
||||
}
|
||||
}
|
||||
|
||||
public class JSBridge : Java.Lang.Object
|
||||
{
|
||||
private readonly WeakReference<HybridWebViewRenderer> _hybridWebViewRenderer;
|
||||
|
||||
public JSBridge(HybridWebViewRenderer hybridRenderer)
|
||||
{
|
||||
_hybridWebViewRenderer = new WeakReference<HybridWebViewRenderer>(hybridRenderer);
|
||||
}
|
||||
|
||||
[JavascriptInterface]
|
||||
[Export("invokeAction")]
|
||||
public void InvokeAction(string data)
|
||||
{
|
||||
if (_hybridWebViewRenderer != null &&
|
||||
_hybridWebViewRenderer.TryGetTarget(out HybridWebViewRenderer hybridRenderer))
|
||||
{
|
||||
hybridRenderer.Element.InvokeAction(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class JSWebViewClient : WebViewClient
|
||||
{
|
||||
private readonly string _javascript;
|
||||
|
||||
public JSWebViewClient(string javascript)
|
||||
{
|
||||
_javascript = javascript;
|
||||
|
||||
}
|
||||
|
||||
public override void OnPageFinished(AWebkit.WebView view, string url)
|
||||
{
|
||||
base.OnPageFinished(view, url);
|
||||
view.EvaluateJavascript(_javascript, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using Android.Content;
|
||||
using Bit.App.Controls;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
|
||||
using Microsoft.Maui.Controls.Platform;
|
||||
|
||||
namespace Bit.App.Droid.Renderers
|
||||
{
|
||||
public class SelectableLabelRenderer : LabelRenderer
|
||||
{
|
||||
public SelectableLabelRenderer(Context context) : base(context) { }
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (Control != null)
|
||||
{
|
||||
Control.SetTextIsSelectable(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
src/Maui/Bitwarden/Resources/Fonts/MaterialIcons_Regular.ttf
Normal file
BIN
src/Maui/Bitwarden/Resources/Fonts/MaterialIcons_Regular.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/Maui/Bitwarden/Resources/Fonts/RobotoMono_Regular.ttf
Normal file
BIN
src/Maui/Bitwarden/Resources/Fonts/RobotoMono_Regular.ttf
Normal file
Binary file not shown.
BIN
src/Maui/Bitwarden/Resources/Fonts/bwi-font.ttf
Normal file
BIN
src/Maui/Bitwarden/Resources/Fonts/bwi-font.ttf
Normal file
Binary file not shown.
@@ -59,11 +59,12 @@
|
||||
<Setter Property="FontAttributes"
|
||||
Value="Bold" />
|
||||
</Style>
|
||||
<!--[MAUI-Migration][Color-default]-->
|
||||
<Style TargetType="Label"
|
||||
Class="text-html"
|
||||
ApplyToDerivedTypes="True">
|
||||
<Setter Property="TextColor"
|
||||
Value="Default" />
|
||||
Value="#ffffff" />
|
||||
<Setter Property="TextType"
|
||||
Value="Html" />
|
||||
</Style>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Bit.App.Styles.Light">
|
||||
@@ -35,7 +35,8 @@
|
||||
<Color x:Key="ListHeaderTextColor">#175DDC</Color>
|
||||
<Color x:Key="ListHeaderBackgroundColor">#efeff4</Color>
|
||||
|
||||
<Color x:Key="SliderThumbColor">Default</Color>
|
||||
<!--[MAUI-Migration][Color-default]-->
|
||||
<Color x:Key="SliderThumbColor">#ffffff</Color>
|
||||
<Color x:Key="SliderThumbBorderColor">#b5b5b5</Color>
|
||||
<Color x:Key="SliderTrackMinColor">#175DDC</Color>
|
||||
<Color x:Key="SliderTrackMaxColor">#dddddd</Color>
|
||||
|
||||
Reference in New Issue
Block a user