mirror of
https://github.com/bitwarden/mobile
synced 2026-01-03 09:03:35 +00:00
PM-3349 MAUI Migration Single Project - Android - Handlers and some fixes to avoid crashing
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -304,6 +304,8 @@
|
||||
<None Remove="Resources\Fonts\bwi-font.ttf" />
|
||||
<None Remove="Resources\Fonts\MaterialIcons_Regular.ttf" />
|
||||
<None Remove="Resources\Fonts\RobotoMono_Regular.ttf" />
|
||||
<None Remove="Handlers\" />
|
||||
<None Remove="Platforms\Android\Handlers\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Core\" />
|
||||
@@ -316,6 +318,8 @@
|
||||
<Folder Include="Core\Services\" />
|
||||
<Folder Include="Core\Utilities\" />
|
||||
<Folder Include="Resources\Fonts\" />
|
||||
<Folder Include="Handlers\" />
|
||||
<Folder Include="Platforms\Android\Handlers\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Core\Resources\eff_long_word_list.txt" />
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
9
src/Maui/Bitwarden/Handlers/ButtonHandlerMappings.cs
Normal file
9
src/Maui/Bitwarden/Handlers/ButtonHandlerMappings.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Bit.App.Handlers
|
||||
{
|
||||
public partial class ButtonHandlerMappings
|
||||
{
|
||||
public void Setup() => SetupPlatform();
|
||||
|
||||
partial void SetupPlatform();
|
||||
}
|
||||
}
|
||||
9
src/Maui/Bitwarden/Handlers/DatePickerHandlerMappings.cs
Normal file
9
src/Maui/Bitwarden/Handlers/DatePickerHandlerMappings.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Bit.App.Handlers
|
||||
{
|
||||
public partial class DatePickerHandlerMappings
|
||||
{
|
||||
public void Setup() => SetupPlatform();
|
||||
|
||||
partial void SetupPlatform();
|
||||
}
|
||||
}
|
||||
10
src/Maui/Bitwarden/Handlers/EditorHandlerMappings.cs
Normal file
10
src/Maui/Bitwarden/Handlers/EditorHandlerMappings.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Bit.App.Handlers
|
||||
{
|
||||
public partial class EditorHandlerMappings
|
||||
{
|
||||
public void Setup() => SetupPlatform();
|
||||
|
||||
partial void SetupPlatform();
|
||||
}
|
||||
}
|
||||
|
||||
9
src/Maui/Bitwarden/Handlers/EntryHandlerMappings.cs
Normal file
9
src/Maui/Bitwarden/Handlers/EntryHandlerMappings.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Bit.App.Handlers
|
||||
{
|
||||
public partial class EntryHandlerMappings
|
||||
{
|
||||
public void Setup() => SetupPlatform();
|
||||
|
||||
partial void SetupPlatform();
|
||||
}
|
||||
}
|
||||
9
src/Maui/Bitwarden/Handlers/LabelHandlerMappings.cs
Normal file
9
src/Maui/Bitwarden/Handlers/LabelHandlerMappings.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Bit.App.Handlers
|
||||
{
|
||||
public partial class LabelHandlerMappings
|
||||
{
|
||||
public void Setup() => SetupPlatform();
|
||||
|
||||
partial void SetupPlatform();
|
||||
}
|
||||
}
|
||||
9
src/Maui/Bitwarden/Handlers/PickerHandlerMappings.cs
Normal file
9
src/Maui/Bitwarden/Handlers/PickerHandlerMappings.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Bit.App.Handlers
|
||||
{
|
||||
public partial class PickerHandlerMappings
|
||||
{
|
||||
public void Setup() => SetupPlatform();
|
||||
|
||||
partial void SetupPlatform();
|
||||
}
|
||||
}
|
||||
10
src/Maui/Bitwarden/Handlers/SearchBarHandlerMappings.cs
Normal file
10
src/Maui/Bitwarden/Handlers/SearchBarHandlerMappings.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Bit.App.Handlers
|
||||
{
|
||||
public partial class SearchBarHandlerMappings
|
||||
{
|
||||
public void Setup() => SetupPlatform();
|
||||
|
||||
partial void SetupPlatform();
|
||||
}
|
||||
}
|
||||
|
||||
9
src/Maui/Bitwarden/Handlers/SliderHandlerMappings.cs
Normal file
9
src/Maui/Bitwarden/Handlers/SliderHandlerMappings.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Bit.App.Handlers
|
||||
{
|
||||
public partial class SliderHandlerMappings
|
||||
{
|
||||
public void Setup() => SetupPlatform();
|
||||
|
||||
partial void SetupPlatform();
|
||||
}
|
||||
}
|
||||
10
src/Maui/Bitwarden/Handlers/StepperHandlerMappings.cs
Normal file
10
src/Maui/Bitwarden/Handlers/StepperHandlerMappings.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Bit.App.Handlers
|
||||
{
|
||||
public partial class StepperHandlerMappings
|
||||
{
|
||||
public void Setup() => SetupPlatform();
|
||||
|
||||
partial void SetupPlatform();
|
||||
}
|
||||
}
|
||||
|
||||
9
src/Maui/Bitwarden/Handlers/SwitchHandlerMappings.cs
Normal file
9
src/Maui/Bitwarden/Handlers/SwitchHandlerMappings.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Bit.App.Handlers
|
||||
{
|
||||
public partial class SwitchHandlerMappings
|
||||
{
|
||||
public void Setup() => SetupPlatform();
|
||||
|
||||
partial void SetupPlatform();
|
||||
}
|
||||
}
|
||||
9
src/Maui/Bitwarden/Handlers/TimePickerHandlerMappings.cs
Normal file
9
src/Maui/Bitwarden/Handlers/TimePickerHandlerMappings.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Bit.App.Handlers
|
||||
{
|
||||
public partial class TimePickerHandlerMappings
|
||||
{
|
||||
public void Setup() => SetupPlatform();
|
||||
|
||||
partial void SetupPlatform();
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,8 @@ namespace Bit.App.Pages
|
||||
public Func<Task> 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") :
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
AutomationProperties.Name="{u:I18n Name}"
|
||||
AutomationId="ItemNameEntry" />
|
||||
</StackLayout>
|
||||
<StackLayout IsVisible="{Binding IsLogin}" Spacing="0" Padding="0">
|
||||
<VerticalStackLayout IsVisible="{Binding IsLogin}" Spacing="0" Padding="0">
|
||||
<Grid StyleClass="box-row, box-row-input"
|
||||
RowDefinitions="Auto,*"
|
||||
ColumnDefinitions="*,Auto">
|
||||
@@ -308,10 +308,11 @@
|
||||
AutomationProperties.Name="{u:I18n ScanQrTitle}"
|
||||
/>
|
||||
</Grid>
|
||||
</StackLayout>
|
||||
<StackLayout IsVisible="{Binding IsCard}" Spacing="0" Padding="0">
|
||||
</VerticalStackLayout>
|
||||
<VerticalStackLayout IsVisible="{Binding IsCard}" Spacing="0" Padding="0">
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
IsVisible="{Binding IsLogin, Mode=OneWay}"
|
||||
Text="{u:I18n CardholderName}"
|
||||
StyleClass="box-label" />
|
||||
<Entry
|
||||
@@ -430,7 +431,7 @@
|
||||
AutomationProperties.Name="{u:I18n ToggleVisibility}"
|
||||
AutomationId="CardShowSecurityCodeButton" />
|
||||
</Grid>
|
||||
</StackLayout>
|
||||
</VerticalStackLayout>
|
||||
<StackLayout IsVisible="{Binding IsIdentity}" Spacing="0" Padding="0">
|
||||
<StackLayout StyleClass="box-row, box-row-input">
|
||||
<Label
|
||||
@@ -831,7 +832,7 @@
|
||||
StyleClass="box-label" />
|
||||
<Picker
|
||||
x:Name="_ownershipPicker"
|
||||
ItemsSource="{Binding OwnershipOptions, Mode=OneTime}"
|
||||
ItemsSource="{Binding OwnershipOptions, Mode=OneWay}"
|
||||
SelectedIndex="{Binding OwnershipSelectedIndex}"
|
||||
StyleClass="box-value"
|
||||
AutomationId="ItemOwnershipPicker" />
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 = "<Pending>")]
|
||||
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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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) { }
|
||||
|
||||
@@ -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) { }
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/splash_screen_round</item>
|
||||
</style>
|
||||
|
||||
<style name="BaseTheme" parent="Theme.AppCompat">
|
||||
<style name="BaseTheme" parent="Theme.MaterialComponents">
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="colorPrimaryDark">@color/dark_notificationBar</item>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Android.Graphics;
|
||||
using Android.Content.Res;
|
||||
using Android.Graphics;
|
||||
using Bit.App.Utilities;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
|
||||
using Color = Android.Graphics.Color;
|
||||
@@ -72,5 +73,20 @@ namespace Bit.App.Droid.Utilities
|
||||
LightTheme = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static ColorStateList GetStateFocusedColors()
|
||||
{
|
||||
var states = new[]
|
||||
{
|
||||
new[] { Android.Resource.Attribute.StateFocused }, // focused
|
||||
new[] { -Android.Resource.Attribute.StateFocused }, // unfocused
|
||||
};
|
||||
var colors = new int[]
|
||||
{
|
||||
PrimaryColor,
|
||||
MutedColor
|
||||
};
|
||||
return new ColorStateList(states, colors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.Android"
|
||||
|
||||
Reference in New Issue
Block a user