mirror of
https://github.com/bitwarden/mobile
synced 2025-12-27 21:53:57 +00:00
PM-3349 PM-3350 MAUI Migration Initial
This commit is contained in:
@@ -3,7 +3,7 @@ using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Models;
|
||||
using Bit.App.Pages;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Enums;
|
||||
@@ -15,8 +15,7 @@ using Bit.iOS.Core.Utilities;
|
||||
using Bit.iOS.Core.Views;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
using Xamarin.Essentials;
|
||||
using Xamarin.Forms;
|
||||
using Microsoft.Maui.Controls.Compatibility;
|
||||
|
||||
namespace Bit.iOS.Core.Controllers
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ using System.Threading.Tasks;
|
||||
using AuthenticationServices;
|
||||
using Bit.App.Models;
|
||||
using Bit.App.Pages;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Abstractions;
|
||||
@@ -17,7 +17,7 @@ using Bit.iOS.Core.Utilities;
|
||||
using Bit.iOS.Core.Views;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Microsoft.Maui.Controls.Compatibility;
|
||||
|
||||
namespace Bit.iOS.Core.Controllers
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ using Foundation;
|
||||
using UIKit;
|
||||
using CoreGraphics;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
using System;
|
||||
using Bit.iOS.Core.Effects;
|
||||
using Microsoft.Maui.Controls.Platform;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportEffect(typeof(NoEmojiKeyboardEffect), nameof(NoEmojiKeyboardEffect))]
|
||||
namespace Bit.iOS.Core.Effects
|
||||
{
|
||||
public class NoEmojiKeyboardEffect : PlatformEffect
|
||||
@@ -22,4 +18,3 @@ namespace Bit.iOS.Core.Effects
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
using Bit.iOS.Core.Effects;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
// TODO: [MAUI-Migration] Check if moving this to the main project works for extensions.
|
||||
|
||||
[assembly: ResolutionGroupName("Bitwarden")]
|
||||
[assembly: ExportEffect(typeof(ScrollEnabledEffect), "ScrollEnabledEffect")]
|
||||
namespace Bit.iOS.Core.Effects
|
||||
{
|
||||
public class ScrollEnabledEffect : PlatformEffect
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
// this can be for any view that inherits from UIScrollView like UITextView.
|
||||
if (Element != null && Control is UIScrollView scrollView)
|
||||
{
|
||||
scrollView.ScrollEnabled = App.Effects.ScrollEnabledEffect.GetIsScrollEnabled(Element);
|
||||
}
|
||||
}
|
||||
//using Bit.iOS.Core.Effects;
|
||||
//using UIKit;
|
||||
//using Xamarin.Forms;
|
||||
//using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
protected override void OnDetached()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
//[assembly: ResolutionGroupName("Bitwarden")]
|
||||
//[assembly: ExportEffect(typeof(ScrollEnabledEffect), "ScrollEnabledEffect")]
|
||||
//namespace Bit.iOS.Core.Effects
|
||||
//{
|
||||
// public class ScrollEnabledEffect : PlatformEffect
|
||||
// {
|
||||
// protected override void OnAttached()
|
||||
// {
|
||||
// // this can be for any view that inherits from UIScrollView like UITextView.
|
||||
// if (Element != null && Control is UIScrollView scrollView)
|
||||
// {
|
||||
// scrollView.ScrollEnabled = App.Effects.ScrollEnabledEffect.GetIsScrollEnabled(Element);
|
||||
// }
|
||||
// }
|
||||
|
||||
// protected override void OnDetached()
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1,37 +1,39 @@
|
||||
using Bit.iOS.Core.Effects;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
// TODO: [MAUI-Migration] Check if moving this to the main project works for extensions.
|
||||
|
||||
[assembly: ExportEffect(typeof(ScrollViewContentInsetAdjustmentBehaviorEffect), nameof(ScrollViewContentInsetAdjustmentBehaviorEffect))]
|
||||
namespace Bit.iOS.Core.Effects
|
||||
{
|
||||
public class ScrollViewContentInsetAdjustmentBehaviorEffect : PlatformEffect
|
||||
{
|
||||
protected override void OnAttached()
|
||||
{
|
||||
if (Element != null && Control is UIScrollView scrollView)
|
||||
{
|
||||
switch (App.Effects.ScrollViewContentInsetAdjustmentBehaviorEffect.GetContentInsetAdjustmentBehavior(Element))
|
||||
{
|
||||
case App.Effects.ScrollContentInsetAdjustmentBehavior.Automatic:
|
||||
scrollView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Automatic;
|
||||
break;
|
||||
case App.Effects.ScrollContentInsetAdjustmentBehavior.ScrollableAxes:
|
||||
scrollView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.ScrollableAxes;
|
||||
break;
|
||||
case App.Effects.ScrollContentInsetAdjustmentBehavior.Never:
|
||||
scrollView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Never;
|
||||
break;
|
||||
case App.Effects.ScrollContentInsetAdjustmentBehavior.Always:
|
||||
scrollView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Always;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//using Bit.iOS.Core.Effects;
|
||||
//using UIKit;
|
||||
//using Xamarin.Forms;
|
||||
//using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
protected override void OnDetached()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
//[assembly: ExportEffect(typeof(ScrollViewContentInsetAdjustmentBehaviorEffect), nameof(ScrollViewContentInsetAdjustmentBehaviorEffect))]
|
||||
//namespace Bit.iOS.Core.Effects
|
||||
//{
|
||||
// public class ScrollViewContentInsetAdjustmentBehaviorEffect : PlatformEffect
|
||||
// {
|
||||
// protected override void OnAttached()
|
||||
// {
|
||||
// if (Element != null && Control is UIScrollView scrollView)
|
||||
// {
|
||||
// switch (App.Effects.ScrollViewContentInsetAdjustmentBehaviorEffect.GetContentInsetAdjustmentBehavior(Element))
|
||||
// {
|
||||
// case App.Effects.ScrollContentInsetAdjustmentBehavior.Automatic:
|
||||
// scrollView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Automatic;
|
||||
// break;
|
||||
// case App.Effects.ScrollContentInsetAdjustmentBehavior.ScrollableAxes:
|
||||
// scrollView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.ScrollableAxes;
|
||||
// break;
|
||||
// case App.Effects.ScrollContentInsetAdjustmentBehavior.Never:
|
||||
// scrollView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Never;
|
||||
// break;
|
||||
// case App.Effects.ScrollContentInsetAdjustmentBehavior.Always:
|
||||
// scrollView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Always;
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// protected override void OnDetached()
|
||||
// {
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
21
src/iOS.Core/Handlers/ButtonHandlerMappings.cs
Normal file
21
src/iOS.Core/Handlers/ButtonHandlerMappings.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
|
||||
namespace Bit.iOS.Core.Handlers
|
||||
{
|
||||
public class ButtonHandlerMappings
|
||||
{
|
||||
public static void Setup()
|
||||
{
|
||||
// TODO: [Maui-Migration] Check if this is needed given that on MAUI FontAutoScalingEnabled is true by default.
|
||||
//Microsoft.Maui.Handlers.ButtonHandler.Mapper.AppendToMapping("CustomButtonHandler", (handler, button) =>
|
||||
//{
|
||||
// var pointSize = iOSHelpers.GetAccessibleFont<Button>(button.FontSize);
|
||||
// if (pointSize != null)
|
||||
// {
|
||||
// handler.PlatformView.Font = UIFont.FromDescriptor(Element.Font.ToUIFont().FontDescriptor, pointSize.Value);
|
||||
// }
|
||||
//});
|
||||
}
|
||||
}
|
||||
}
|
||||
39
src/iOS.Core/Handlers/DatePickerHandlerMappings.cs
Normal file
39
src/iOS.Core/Handlers/DatePickerHandlerMappings.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using Bit.App.Controls;
|
||||
using Microsoft.Maui.Handlers;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Core.Handlers
|
||||
{
|
||||
public class DatePickerHandlerMappings
|
||||
{
|
||||
public static void Setup()
|
||||
{
|
||||
DatePickerHandler.Mapper.AppendToMapping("CustomDatePickerHandler", (handler, datePicker) =>
|
||||
{
|
||||
if (datePicker is ExtendedDatePicker extDatePicker)
|
||||
{
|
||||
// center text
|
||||
handler.PlatformView.TextAlignment = UITextAlignment.Center;
|
||||
|
||||
// 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 static void UpdateTextPlaceholderOnFormatLikePlacholder(IDatePickerHandler handler, IDatePicker datePicker)
|
||||
{
|
||||
if (datePicker is ExtendedDatePicker extDatePicker && extDatePicker.Format == extDatePicker.PlaceHolder)
|
||||
{
|
||||
handler.PlatformView.Text = extDatePicker.PlaceHolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
34
src/iOS.Core/Handlers/EditorHandlerMappings.cs
Normal file
34
src/iOS.Core/Handlers/EditorHandlerMappings.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using Microsoft.Maui.Handlers;
|
||||
using Microsoft.Maui.Platform;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Core.Handlers
|
||||
{
|
||||
public class EditorHandlerMappings
|
||||
{
|
||||
public static void Setup()
|
||||
{
|
||||
EditorHandler.Mapper.AppendToMapping("CustomEditorHandler", (handler, editor) =>
|
||||
{
|
||||
var descriptor = UIFontDescriptor.PreferredBody;
|
||||
handler.PlatformView.Font = UIFont.FromDescriptor(descriptor, descriptor.PointSize);
|
||||
// Remove padding
|
||||
handler.PlatformView.TextContainerInset = new UIEdgeInsets(0, 0, 0, 0);
|
||||
handler.PlatformView.TextContainer.LineFragmentPadding = 0;
|
||||
UpdateTintColor(handler, editor);
|
||||
|
||||
if (!Utilities.ThemeHelpers.LightTheme)
|
||||
{
|
||||
handler.PlatformView.KeyboardAppearance = UIKeyboardAppearance.Dark;
|
||||
}
|
||||
});
|
||||
|
||||
EditorHandler.Mapper.AppendToMapping(nameof(IEditor.TextColor), UpdateTintColor);
|
||||
}
|
||||
|
||||
private static void UpdateTintColor(IEditorHandler handler, IEditor editor)
|
||||
{
|
||||
handler.PlatformView.TintColor = editor.TextColor.ToPlatform();
|
||||
}
|
||||
}
|
||||
}
|
||||
35
src/iOS.Core/Handlers/EntryHandlerMappings.cs
Normal file
35
src/iOS.Core/Handlers/EntryHandlerMappings.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using Microsoft.Maui.Handlers;
|
||||
using Microsoft.Maui.Platform;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Core.Handlers
|
||||
{
|
||||
public class EntryHandlerMappings
|
||||
{
|
||||
public static void Setup()
|
||||
{
|
||||
EntryHandler.Mapper.AppendToMapping("CustomEntryHandler", (handler, editor) =>
|
||||
{
|
||||
handler.PlatformView.ClearButtonMode = UITextFieldViewMode.WhileEditing;
|
||||
UpdateTintColor(handler, editor);
|
||||
iOSHelpers.SetBottomBorder(handler.PlatformView);
|
||||
// TODO: [Maui-Migration] Check if needed given that MAUI should be automatically change the font size based on OS accessbiility
|
||||
//UpdateFontSize();
|
||||
|
||||
if (!ThemeHelpers.LightTheme)
|
||||
{
|
||||
handler.PlatformView.KeyboardAppearance = UIKeyboardAppearance.Dark;
|
||||
}
|
||||
});
|
||||
|
||||
EntryHandler.Mapper.AppendToMapping(nameof(IEntry.TextColor), UpdateTintColor);
|
||||
}
|
||||
|
||||
private static void UpdateTintColor(IEntryHandler handler, IEntry editor)
|
||||
{
|
||||
handler.PlatformView.TintColor = editor.TextColor.ToPlatform();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
83
src/iOS.Core/Handlers/LabelHandlerMappings.cs
Normal file
83
src/iOS.Core/Handlers/LabelHandlerMappings.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using Bit.App.Controls;
|
||||
using Microsoft.Maui.Handlers;
|
||||
using Microsoft.Maui.Platform;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Core.Handlers
|
||||
{
|
||||
public class LabelHandlerMappings
|
||||
{
|
||||
// TODO: [Maui-Migration] See if the SelectableLabel is needed.
|
||||
//public static void Setup()
|
||||
//{
|
||||
// LabelHandler.Mapper.AppendToMapping(nameof(ILabel.TextColor), (handler, label) =>
|
||||
// {
|
||||
// if (label is SelectableLabel selectableLabel)
|
||||
// {
|
||||
// handler.PlatformView.Selectable = true;
|
||||
// handler.PlatformView.Editable = false;
|
||||
// handler.PlatformView.ScrollEnabled = false;
|
||||
// handler.PlatformView.TextContainerInset = UIEdgeInsets.Zero;
|
||||
// handler.PlatformView.TextContainer.LineFragmentPadding = 0;
|
||||
// handler.PlatformView.BackgroundColor = UIColor.Clear;
|
||||
|
||||
// handler.PlatformView.Text = selectableLabel.Text;
|
||||
// handler.PlatformView.TextColor = selectableLabel.TextColor.ToPlatform();
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
|
||||
// TODO: [Maui-Migration] Check if needed to migrate given that MAUI should be automatically change the font size based on OS accessbiility
|
||||
|
||||
//protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
|
||||
//{
|
||||
// base.OnElementChanged(e);
|
||||
// if (Control != null && e.NewElement is Label)
|
||||
// {
|
||||
// UpdateFont();
|
||||
// }
|
||||
//}
|
||||
|
||||
//protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
//{
|
||||
// var label = sender as CustomLabel;
|
||||
// switch (e.PropertyName)
|
||||
// {
|
||||
// case nameof(CustomLabel.AutomationId):
|
||||
// Control.AccessibilityIdentifier = label.AutomationId;
|
||||
// break;
|
||||
// }
|
||||
|
||||
// base.OnElementPropertyChanged(sender, e);
|
||||
|
||||
// if (e.PropertyName == Label.FontProperty.PropertyName ||
|
||||
// e.PropertyName == Label.TextProperty.PropertyName ||
|
||||
// e.PropertyName == Label.FormattedTextProperty.PropertyName)
|
||||
// {
|
||||
// UpdateFont();
|
||||
// }
|
||||
//}
|
||||
|
||||
//private void UpdateFont()
|
||||
//{
|
||||
// if (Element is null || Control is null)
|
||||
// return;
|
||||
|
||||
// var pointSize = iOSHelpers.GetAccessibleFont<Label>(Element.FontSize);
|
||||
// if (pointSize != null)
|
||||
// {
|
||||
// Control.Font = UIFont.FromDescriptor(Element.ToUIFont().FontDescriptor, pointSize.Value);
|
||||
// }
|
||||
// // TODO: For now, I'm only doing this for IconLabel with setup just in case I break the whole app labels.
|
||||
// // We need to revisit this when we address Accessibility Large Font issues across the app
|
||||
// // to check if we can left it more generic like
|
||||
// // else if (Element.FontFamily != null)
|
||||
// else if (Element is IconLabel iconLabel && iconLabel.ShouldUpdateFontSizeDynamicallyForAccesibility)
|
||||
// {
|
||||
// var customFont = Element.ToUIFont();
|
||||
// Control.Font = new UIFontMetrics(UIFontTextStyle.Body.GetConstant()).GetScaledFont(customFont);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
24
src/iOS.Core/Handlers/PickerHandlerMappings.cs
Normal file
24
src/iOS.Core/Handlers/PickerHandlerMappings.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using Microsoft.Maui.Handlers;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Core.Handlers
|
||||
{
|
||||
public class PickerHandlerMappings
|
||||
{
|
||||
public static void Setup()
|
||||
{
|
||||
PickerHandler.Mapper.AppendToMapping("CustomPickerHandler", (handler, picker) =>
|
||||
{
|
||||
var descriptor = UIFontDescriptor.PreferredBody;
|
||||
handler.PlatformView.Font = UIFont.FromDescriptor(descriptor, descriptor.PointSize);
|
||||
iOSHelpers.SetBottomBorder(handler.PlatformView);
|
||||
|
||||
if (!ThemeHelpers.LightTheme)
|
||||
{
|
||||
handler.PlatformView.KeyboardAppearance = UIKeyboardAppearance.Dark;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
20
src/iOS.Core/Handlers/SearchBarHandlerMappings.cs
Normal file
20
src/iOS.Core/Handlers/SearchBarHandlerMappings.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using Microsoft.Maui.Handlers;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Core.Handlers
|
||||
{
|
||||
public class SearchBarHandlerMappings
|
||||
{
|
||||
public static void Setup()
|
||||
{
|
||||
SearchBarHandler.Mapper.AppendToMapping("CustomSearchBarHandler", (handler, searchBar) =>
|
||||
{
|
||||
if (!ThemeHelpers.LightTheme)
|
||||
{
|
||||
handler.PlatformView.KeyboardAppearance = UIKeyboardAppearance.Dark;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/iOS.Core/Handlers/StepperHandlerMappings.cs
Normal file
31
src/iOS.Core/Handlers/StepperHandlerMappings.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Bit.App.Controls;
|
||||
using Microsoft.Maui.Handlers;
|
||||
using Microsoft.Maui.Platform;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Core.Handlers
|
||||
{
|
||||
public class StepperHandlerMappings
|
||||
{
|
||||
public static void Setup()
|
||||
{
|
||||
StepperHandler.Mapper.AppendToMapping("CustomStepperHandler", UpdateFgColor);
|
||||
|
||||
StepperHandler.Mapper.AppendToMapping(nameof(ExtendedStepper.StepperForegroundColor), UpdateFgColor);
|
||||
}
|
||||
|
||||
private static void UpdateFgColor(IStepperHandler handler, IStepper stepper)
|
||||
{
|
||||
if (stepper is ExtendedStepper extStepper)
|
||||
{
|
||||
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
|
||||
{
|
||||
// https://developer.apple.com/forums/thread/121495
|
||||
handler.PlatformView.SetIncrementImage(handler.PlatformView.GetIncrementImage(UIControlState.Normal), UIControlState.Normal);
|
||||
handler.PlatformView.SetDecrementImage(handler.PlatformView.GetDecrementImage(UIControlState.Normal), UIControlState.Normal);
|
||||
}
|
||||
handler.PlatformView.TintColor = extStepper.StepperForegroundColor.ToPlatform();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
55
src/iOS.Core/Handlers/TimePickerHandlerMappings.cs
Normal file
55
src/iOS.Core/Handlers/TimePickerHandlerMappings.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using Bit.App.Controls;
|
||||
using Microsoft.Maui.Handlers;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Core.Handlers
|
||||
{
|
||||
public class TimePickerHandlerMappings
|
||||
{
|
||||
public static void Setup()
|
||||
{
|
||||
TimePickerHandler.Mapper.AppendToMapping("CustomDatePickerHandler", (handler, datePicker) =>
|
||||
{
|
||||
if (datePicker is ExtendedTimePicker extTimePicker)
|
||||
{
|
||||
// center text
|
||||
handler.PlatformView.TextAlignment = UITextAlignment.Center;
|
||||
|
||||
// use placeholder until NullableDate set
|
||||
if (!extTimePicker.NullableTime.HasValue)
|
||||
{
|
||||
handler.PlatformView.Text = extTimePicker.PlaceHolder;
|
||||
}
|
||||
|
||||
// force use of wheel picker on iOS 14+
|
||||
// TODO remove this when we upgrade to X.F 5 SR-1
|
||||
// TODO: [Maui-Migration] Check if this is needed given that we're not on XForms anymore.
|
||||
// https://github.com/xamarin/Xamarin.Forms/issues/12258#issuecomment-700168665
|
||||
try
|
||||
{
|
||||
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 2)
|
||||
&&
|
||||
handler.PlatformView.InputView is UIDatePicker picker)
|
||||
{
|
||||
picker.PreferredDatePickerStyle = UIDatePickerStyle.Wheels;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
});
|
||||
|
||||
TimePickerHandler.Mapper.AppendToMapping(nameof(ITimePicker.Time), UpdateTextPlaceholderOnFormatLikePlacholder);
|
||||
|
||||
TimePickerHandler.Mapper.AppendToMapping(nameof(ITimePicker.Format), UpdateTextPlaceholderOnFormatLikePlacholder);
|
||||
}
|
||||
|
||||
private static void UpdateTextPlaceholderOnFormatLikePlacholder(ITimePickerHandler handler, ITimePicker timePicker)
|
||||
{
|
||||
if (timePicker is ExtendedTimePicker extDatePicker && extDatePicker.Format == extDatePicker.PlaceHolder)
|
||||
{
|
||||
handler.PlatformView.Text = extDatePicker.PlaceHolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("BitwardeniOSCore")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Bitwarden Inc.")]
|
||||
[assembly: AssemblyProduct("Bitwarden")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("50c7b8c9-e664-45af-b88e-0c9b8b9c1be1")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,16 +0,0 @@
|
||||
using System;
|
||||
namespace Bit.iOS.Core.Renderers.CollectionView
|
||||
{
|
||||
public class CollectionException : Exception
|
||||
{
|
||||
public CollectionException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public CollectionException(string message, Exception innerEx)
|
||||
: base(message, innerEx)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
using Bit.App.Controls;
|
||||
using Bit.iOS.Core.Renderers.CollectionView;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedCollectionView), typeof(ExtendedCollectionViewRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers.CollectionView
|
||||
{
|
||||
public class ExtendedCollectionViewRenderer : GroupableItemsViewRenderer<ExtendedCollectionView, GroupableItemsViewController<ExtendedCollectionView>>
|
||||
{
|
||||
protected override GroupableItemsViewController<ExtendedCollectionView> CreateController(ExtendedCollectionView itemsView, ItemsViewLayout layout)
|
||||
{
|
||||
return new ExtendedGroupableItemsViewController<ExtendedCollectionView>(itemsView, layout);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Core.Services;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
namespace Bit.iOS.Core.Renderers.CollectionView
|
||||
{
|
||||
public class ExtendedGroupableItemsViewController<TItemsView> : GroupableItemsViewController<TItemsView>
|
||||
where TItemsView : ExtendedCollectionView
|
||||
{
|
||||
public ExtendedGroupableItemsViewController(TItemsView groupableItemsView, ItemsViewLayout layout)
|
||||
: base(groupableItemsView, layout)
|
||||
{
|
||||
}
|
||||
|
||||
protected override UICollectionViewDelegateFlowLayout CreateDelegator()
|
||||
{
|
||||
return new ExtendedGroupableItemsViewDelegator<TItemsView, ExtendedGroupableItemsViewController<TItemsView>>(ItemsViewLayout, this);
|
||||
}
|
||||
|
||||
protected override void UpdateTemplatedCell(TemplatedCell cell, NSIndexPath indexPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
base.UpdateTemplatedCell(cell, indexPath);
|
||||
}
|
||||
catch (Exception ex) when (ItemsView?.ExtraDataForLogging != null)
|
||||
{
|
||||
var colEx = new CollectionException("Error in ExtendedCollectionView -> ExtendedGroupableItemsViewController, extra data: " + ItemsView.ExtraDataForLogging, ex);
|
||||
try
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(colEx);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing in here, this is temporary to get more info about the crash, if the logger fails, we want to get the info
|
||||
// by crashing with the original exception and not the logger one
|
||||
}
|
||||
throw colEx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using System;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Core.Services;
|
||||
using CoreGraphics;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
namespace Bit.iOS.Core.Renderers.CollectionView
|
||||
{
|
||||
public class ExtendedGroupableItemsViewDelegator<TItemsView, TViewController> : GroupableItemsViewDelegator<TItemsView, TViewController>
|
||||
where TItemsView : ExtendedCollectionView
|
||||
where TViewController : GroupableItemsViewController<TItemsView>
|
||||
{
|
||||
public ExtendedGroupableItemsViewDelegator(ItemsViewLayout itemsViewLayout, TViewController itemsViewController)
|
||||
: base(itemsViewLayout, itemsViewController)
|
||||
{
|
||||
}
|
||||
|
||||
public override CGSize GetSizeForItem(UICollectionView collectionView, UICollectionViewLayout layout, NSIndexPath indexPath)
|
||||
{
|
||||
// Added this to get extra information on a crash when getting the size for an item.
|
||||
try
|
||||
{
|
||||
return base.GetSizeForItem(collectionView, layout, indexPath);
|
||||
}
|
||||
catch (Exception ex) when (ViewController?.ItemsView?.ExtraDataForLogging != null)
|
||||
{
|
||||
var colEx = new CollectionException("Error in ExtendedCollectionView -> ExtendedGroupableItemsViewDelegator, extra data: " + ViewController.ItemsView.ExtraDataForLogging, ex);
|
||||
try
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(colEx);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Do nothing in here, this is temporary to get more info about the crash, if the logger fails, we want to get the info
|
||||
// by crashing with the original exception and not the logger one
|
||||
}
|
||||
throw colEx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
using System.ComponentModel;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(Button), typeof(CustomButtonRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class CustomButtonRenderer : ButtonRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && e.NewElement is Button)
|
||||
{
|
||||
UpdateFont();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
if (e.PropertyName == Button.FontProperty.PropertyName)
|
||||
{
|
||||
UpdateFont();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFont()
|
||||
{
|
||||
var pointSize = iOSHelpers.GetAccessibleFont<Button>(Element.FontSize);
|
||||
if (pointSize != null)
|
||||
{
|
||||
Control.Font = UIFont.FromDescriptor(Element.Font.ToUIFont().FontDescriptor, pointSize.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ContentPage), typeof(CustomContentPageRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class CustomContentPageRenderer : PageRenderer
|
||||
{
|
||||
public override void ViewWillAppear(bool animated)
|
||||
{
|
||||
base.ViewWillAppear(animated);
|
||||
if (!(Element is ContentPage contentPage) || NavigationController == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide bottom line under nav bar
|
||||
var navBar = NavigationController.NavigationBar;
|
||||
if (navBar != null)
|
||||
{
|
||||
navBar.SetValueForKey(FromObject(true), new Foundation.NSString("hidesShadow"));
|
||||
}
|
||||
|
||||
var navigationItem = NavigationController.TopViewController.NavigationItem;
|
||||
var leftNativeButtons = (navigationItem.LeftBarButtonItems ?? new UIBarButtonItem[] { }).ToList();
|
||||
var rightNativeButtons = (navigationItem.RightBarButtonItems ?? new UIBarButtonItem[] { }).ToList();
|
||||
var newLeftButtons = new List<UIBarButtonItem>();
|
||||
var newRightButtons = new List<UIBarButtonItem>();
|
||||
foreach (var nativeItem in rightNativeButtons)
|
||||
{
|
||||
// Use reflection to get Xamarin private field "_item"
|
||||
var field = nativeItem.GetType().GetField("_item", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
if (field == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!(field.GetValue(nativeItem) is ToolbarItem info))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (info.Priority < 0)
|
||||
{
|
||||
newLeftButtons.Add(nativeItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
newRightButtons.Add(nativeItem);
|
||||
}
|
||||
}
|
||||
foreach (var nativeItem in leftNativeButtons)
|
||||
{
|
||||
newLeftButtons.Add(nativeItem);
|
||||
}
|
||||
navigationItem.RightBarButtonItems = newRightButtons.ToArray();
|
||||
navigationItem.LeftBarButtonItems = newLeftButtons.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using System.ComponentModel;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(Editor), typeof(CustomEditorRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class CustomEditorRenderer : EditorRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Editor> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (e.NewElement is Editor)
|
||||
{
|
||||
var descriptor = UIFontDescriptor.PreferredBody;
|
||||
Control.Font = UIFont.FromDescriptor(descriptor, descriptor.PointSize);
|
||||
// Remove padding
|
||||
Control.TextContainerInset = new UIEdgeInsets(0, 0, 0, 0);
|
||||
Control.TextContainer.LineFragmentPadding = 0;
|
||||
UpdateTintColor();
|
||||
UpdateKeyboardAppearance();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
if (e.PropertyName == Editor.TextColorProperty.PropertyName)
|
||||
{
|
||||
UpdateTintColor();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTintColor()
|
||||
{
|
||||
Control.TintColor = Element.TextColor.ToUIColor();
|
||||
}
|
||||
|
||||
private void UpdateKeyboardAppearance()
|
||||
{
|
||||
if (!Utilities.ThemeHelpers.LightTheme)
|
||||
{
|
||||
Control.KeyboardAppearance = UIKeyboardAppearance.Dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
using System.ComponentModel;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(Entry), typeof(CustomEntryRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class CustomEntryRenderer : EntryRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && e.NewElement is Entry)
|
||||
{
|
||||
Control.ClearButtonMode = UITextFieldViewMode.WhileEditing;
|
||||
UpdateTintColor();
|
||||
UpdateFontSize();
|
||||
UpdateKeyboardAppearance();
|
||||
iOSHelpers.SetBottomBorder(Control);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
if (e.PropertyName == Entry.FontAttributesProperty.PropertyName ||
|
||||
e.PropertyName == Entry.FontFamilyProperty.PropertyName ||
|
||||
e.PropertyName == Entry.FontSizeProperty.PropertyName)
|
||||
{
|
||||
UpdateFontSize();
|
||||
}
|
||||
else if (e.PropertyName == Entry.TextColorProperty.PropertyName)
|
||||
{
|
||||
UpdateTintColor();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFontSize()
|
||||
{
|
||||
var pointSize = iOSHelpers.GetAccessibleFont<Entry>(Element.FontSize);
|
||||
if (pointSize != null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(Element.FontFamily))
|
||||
{
|
||||
Control.Font = UIFont.FromName(Element.FontFamily, pointSize.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Control.Font = UIFont.FromDescriptor(UIFontDescriptor.PreferredBody, pointSize.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTintColor()
|
||||
{
|
||||
Control.TintColor = Element.TextColor.ToUIColor();
|
||||
}
|
||||
|
||||
private void UpdateKeyboardAppearance()
|
||||
{
|
||||
if (!ThemeHelpers.LightTheme)
|
||||
{
|
||||
Control.KeyboardAppearance = UIKeyboardAppearance.Dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Bit.App.Controls;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(Label), typeof(CustomLabelRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class CustomLabelRenderer : LabelRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && e.NewElement is Label)
|
||||
{
|
||||
UpdateFont();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
var label = sender as CustomLabel;
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(CustomLabel.AutomationId):
|
||||
Control.AccessibilityIdentifier = label.AutomationId;
|
||||
break;
|
||||
}
|
||||
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
|
||||
if (e.PropertyName == Label.FontProperty.PropertyName ||
|
||||
e.PropertyName == Label.TextProperty.PropertyName ||
|
||||
e.PropertyName == Label.FormattedTextProperty.PropertyName)
|
||||
{
|
||||
UpdateFont();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFont()
|
||||
{
|
||||
if (Element is null || Control is null)
|
||||
return;
|
||||
|
||||
var pointSize = iOSHelpers.GetAccessibleFont<Label>(Element.FontSize);
|
||||
if (pointSize != null)
|
||||
{
|
||||
Control.Font = UIFont.FromDescriptor(Element.ToUIFont().FontDescriptor, pointSize.Value);
|
||||
}
|
||||
// TODO: For now, I'm only doing this for IconLabel with setup just in case I break the whole app labels.
|
||||
// We need to revisit this when we address Accessibility Large Font issues across the app
|
||||
// to check if we can left it more generic like
|
||||
// else if (Element.FontFamily != null)
|
||||
else if (Element is IconLabel iconLabel && iconLabel.ShouldUpdateFontSizeDynamicallyForAccesibility)
|
||||
{
|
||||
var customFont = Element.ToUIFont();
|
||||
Control.Font = new UIFontMetrics(UIFontTextStyle.Body.GetConstant()).GetScaledFont(customFont);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Bit.App.Controls;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using CoreFoundation;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(NavigationPage), typeof(CustomNavigationRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class CustomNavigationRenderer : NavigationRenderer
|
||||
{
|
||||
public override void PushViewController(UIViewController viewController, bool animated)
|
||||
{
|
||||
base.PushViewController(viewController, animated);
|
||||
|
||||
var currentPage = (Element as NavigationPage)?.CurrentPage;
|
||||
if (currentPage == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var toolbarItems = currentPage.ToolbarItems;
|
||||
if (!toolbarItems.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// In order to get the correct index we need to do the same as XF and reverse the toolbar items list
|
||||
// https://github.com/xamarin/Xamarin.Forms/blob/8f765bd87a2968bef9c86122d88c9c47be9196d2/Xamarin.Forms.Platform.iOS/Renderers/NavigationRenderer.cs#L1432
|
||||
toolbarItems = toolbarItems.Where(t => t.Order != ToolbarItemOrder.Secondary)
|
||||
.Reverse()
|
||||
.ToList();
|
||||
|
||||
var uiBarButtonItems = TopViewController.NavigationItem.RightBarButtonItems;
|
||||
if (uiBarButtonItems == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (ExtendedToolbarItem toolbarItem in toolbarItems.Where(t => t is ExtendedToolbarItem eti
|
||||
&&
|
||||
eti.UseOriginalImage))
|
||||
{
|
||||
var index = toolbarItems.IndexOf(toolbarItem);
|
||||
if (index < 0 || index >= uiBarButtonItems.Length)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// HACK: this is awful but I can't find another way to properly prevent memory leaks from
|
||||
// subscribing on the PropertyChanged event; there are several private places where Xamarin Forms
|
||||
// disposes objects that are not accessible from here so I think this should cover the (un)subscription
|
||||
// but we need to remember to call the internal methods of ExtendedToolbarItem on the lifecycle of the Page
|
||||
toolbarItem.OnAppearingAction = () => toolbarItem.PropertyChanged += ToolbarItem_PropertyChanged;
|
||||
toolbarItem.OnDisappearingAction = () => toolbarItem.PropertyChanged -= ToolbarItem_PropertyChanged;
|
||||
|
||||
// HACK: XF PimaryToolbarItem is sealed so we can't override it, and also it doesn't provide any
|
||||
// direct way to replace it with our custom one (we can but we need to rewrite several parts of the NavigationRenderer)
|
||||
// So I think this is the easiest soolution for now to set UIImageRenderingMode.AlwaysOriginal
|
||||
// on the toolbar item image
|
||||
void ToolbarItem_PropertyChanged(object s, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(ExtendedToolbarItem.IconImageSource))
|
||||
{
|
||||
var uiBarButtonItem = uiBarButtonItems[index];
|
||||
|
||||
DispatchQueue.MainQueue.DispatchAsync(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
uiBarButtonItem.Image = uiBarButtonItem.Image?.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal);
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
// Do nothing, we can't access the proper place to properly dispose this, so here
|
||||
// we can just catch and ignore the exception. This should only happen when logging out a user.
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(Picker), typeof(CustomPickerRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class CustomPickerRenderer : PickerRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Picker> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (e.NewElement is Picker)
|
||||
{
|
||||
var descriptor = UIFontDescriptor.PreferredBody;
|
||||
Control.Font = UIFont.FromDescriptor(descriptor, descriptor.PointSize);
|
||||
iOSHelpers.SetBottomBorder(Control);
|
||||
UpdateKeyboardAppearance();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateKeyboardAppearance()
|
||||
{
|
||||
if (!ThemeHelpers.LightTheme)
|
||||
{
|
||||
Control.KeyboardAppearance = UIKeyboardAppearance.Dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(SearchBar), typeof(CustomSearchBarRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class CustomSearchBarRenderer : SearchBarRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<SearchBar> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (e.NewElement is SearchBar)
|
||||
{
|
||||
UpdateKeyboardAppearance();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateKeyboardAppearance()
|
||||
{
|
||||
if (!Utilities.ThemeHelpers.LightTheme)
|
||||
{
|
||||
Control.KeyboardAppearance = UIKeyboardAppearance.Dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
using System;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Pages;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedRenderer))]
|
||||
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class CustomTabbedRenderer : TabbedRenderer
|
||||
{
|
||||
private IBroadcasterService _broadcasterService;
|
||||
private UITabBarItem _previousSelectedItem;
|
||||
|
||||
public CustomTabbedRenderer()
|
||||
{
|
||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
||||
_broadcasterService.Subscribe(nameof(CustomTabbedRenderer), (message) =>
|
||||
{
|
||||
if (message.Command is ThemeManager.UPDATED_THEME_MESSAGE_KEY)
|
||||
{
|
||||
Device.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
iOSCoreHelpers.AppearanceAdjustments();
|
||||
UpdateTabBarAppearance();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void OnElementChanged(VisualElementChangedEventArgs e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
TabBar.Translucent = false;
|
||||
TabBar.Opaque = true;
|
||||
UpdateTabBarAppearance();
|
||||
}
|
||||
|
||||
public override void ViewDidAppear(bool animated)
|
||||
{
|
||||
base.ViewDidAppear(animated);
|
||||
|
||||
if (SelectedIndex < TabBar.Items.Length)
|
||||
{
|
||||
_previousSelectedItem = TabBar.Items[SelectedIndex];
|
||||
}
|
||||
}
|
||||
|
||||
public override void ItemSelected(UITabBar tabbar, UITabBarItem item)
|
||||
{
|
||||
if (_previousSelectedItem == item && Element is TabsPage tabsPage)
|
||||
{
|
||||
tabsPage.OnPageReselected();
|
||||
}
|
||||
_previousSelectedItem = item;
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_broadcasterService.Unsubscribe(nameof(CustomTabbedRenderer));
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void UpdateTabBarAppearance()
|
||||
{
|
||||
// https://developer.apple.com/forums/thread/682420
|
||||
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
||||
if (deviceActionService.SystemMajorVersion() >= 15)
|
||||
{
|
||||
var appearance = new UITabBarAppearance();
|
||||
appearance.ConfigureWithOpaqueBackground();
|
||||
appearance.BackgroundColor = ThemeHelpers.TabBarBackgroundColor;
|
||||
appearance.StackedLayoutAppearance.Normal.IconColor = ThemeHelpers.TabBarItemColor;
|
||||
appearance.StackedLayoutAppearance.Normal.TitleTextAttributes =
|
||||
new UIStringAttributes { ForegroundColor = ThemeHelpers.TabBarItemColor };
|
||||
TabBar.StandardAppearance = appearance;
|
||||
TabBar.ScrollEdgeAppearance = TabBar.StandardAppearance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using Bit.App.Utilities;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ViewCell), typeof(CustomViewCellRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class CustomViewCellRenderer : ViewCellRenderer
|
||||
{
|
||||
private bool _noSelectionStyle = false;
|
||||
|
||||
public CustomViewCellRenderer()
|
||||
{
|
||||
_noSelectionStyle = ThemeManager.GetResourceColor("BackgroundColor") != Color.White;
|
||||
}
|
||||
|
||||
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
|
||||
{
|
||||
var cell = base.GetCell(item, reusableCell, tv);
|
||||
if (_noSelectionStyle)
|
||||
{
|
||||
cell.SelectionStyle = UITableViewCellSelectionStyle.None;
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
using System.ComponentModel;
|
||||
using Bit.App.Controls;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedDatePicker), typeof(ExtendedDatePickerRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class ExtendedDatePickerRenderer : DatePickerRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<DatePicker> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && Element is ExtendedDatePicker element)
|
||||
{
|
||||
// center text
|
||||
Control.TextAlignment = UITextAlignment.Center;
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
using System.ComponentModel;
|
||||
using Bit.App.Controls;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedStepper), typeof(ExtendedStepperRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class ExtendedStepperRenderer : StepperRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Stepper> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
UpdateFgColor();
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == ExtendedStepper.StepperForegroundColorProperty.PropertyName)
|
||||
{
|
||||
UpdateFgColor();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateFgColor()
|
||||
{
|
||||
if (Control != null && Element is ExtendedStepper view)
|
||||
{
|
||||
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
|
||||
{
|
||||
// https://developer.apple.com/forums/thread/121495
|
||||
Control.SetIncrementImage(Control.GetIncrementImage(UIControlState.Normal), UIControlState.Normal);
|
||||
Control.SetDecrementImage(Control.GetDecrementImage(UIControlState.Normal), UIControlState.Normal);
|
||||
}
|
||||
Control.TintColor = view.StepperForegroundColor.ToUIColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
using System.ComponentModel;
|
||||
using Bit.App.Controls;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(ExtendedTimePicker), typeof(ExtendedTimePickerRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class ExtendedTimePickerRenderer : TimePickerRenderer
|
||||
{
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<TimePicker> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
if (Control != null && Element is ExtendedTimePicker element)
|
||||
{
|
||||
// center text
|
||||
Control.TextAlignment = UITextAlignment.Center;
|
||||
|
||||
// use placeholder until NullableTime set
|
||||
if (!element.NullableTime.HasValue)
|
||||
{
|
||||
Control.Text = element.PlaceHolder;
|
||||
}
|
||||
|
||||
// force use of wheel picker on iOS 14+
|
||||
// TODO remove this when we upgrade to X.F 5 SR-1
|
||||
// https://github.com/xamarin/Xamarin.Forms/issues/12258#issuecomment-700168665
|
||||
try
|
||||
{
|
||||
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 2))
|
||||
{
|
||||
var picker = (UIDatePicker)Control.InputView;
|
||||
picker.PreferredDatePickerStyle = UIDatePickerStyle.Wheels;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
using Foundation;
|
||||
using WebKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
using Bit.App.Controls;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using System.ComponentModel;
|
||||
|
||||
[assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, WKWebView>, IWKScriptMessageHandler
|
||||
{
|
||||
private const string JSFunction =
|
||||
"function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
|
||||
|
||||
private WKUserContentController _userController;
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (Control == null)
|
||||
{
|
||||
_userController = new WKUserContentController();
|
||||
var script = new WKUserScript(new NSString(JSFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
|
||||
_userController.AddUserScript(script);
|
||||
_userController.AddScriptMessageHandler(this, "invokeAction");
|
||||
|
||||
var config = new WKWebViewConfiguration { UserContentController = _userController };
|
||||
var webView = new WKWebView(Frame, config);
|
||||
SetNativeControl(webView);
|
||||
}
|
||||
if (e.OldElement != null)
|
||||
{
|
||||
_userController.RemoveAllUserScripts();
|
||||
_userController.RemoveScriptMessageHandler("invokeAction");
|
||||
var hybridWebView = e.OldElement as HybridWebView;
|
||||
hybridWebView.Cleanup();
|
||||
}
|
||||
if (e.NewElement != null)
|
||||
{
|
||||
if (Element.Uri != null)
|
||||
{
|
||||
Control.LoadRequest(new NSUrlRequest(new NSUrl(Element.Uri)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
if (e.PropertyName == HybridWebView.UriProperty.PropertyName && Element.Uri != null)
|
||||
{
|
||||
Control.LoadRequest(new NSUrlRequest(new NSUrl(Element.Uri)));
|
||||
}
|
||||
}
|
||||
|
||||
public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
|
||||
{
|
||||
Element.InvokeAction(message.Body.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Bit.App.Controls;
|
||||
using Bit.iOS.Core.Renderers;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
[assembly: ExportRenderer(typeof(SelectableLabel), typeof(SelectableLabelRenderer))]
|
||||
namespace Bit.iOS.Core.Renderers
|
||||
{
|
||||
public class SelectableLabelRenderer : ViewRenderer<Label, UITextView>
|
||||
{
|
||||
UITextView uiTextView;
|
||||
|
||||
protected override void OnElementChanged(ElementChangedEventArgs<Label> e)
|
||||
{
|
||||
base.OnElementChanged(e);
|
||||
|
||||
if (e.OldElement != null || Element == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Control == null)
|
||||
{
|
||||
uiTextView = new UITextView();
|
||||
}
|
||||
|
||||
uiTextView.Selectable = true;
|
||||
uiTextView.Editable = false;
|
||||
uiTextView.ScrollEnabled = false;
|
||||
uiTextView.TextContainerInset = UIEdgeInsets.Zero;
|
||||
uiTextView.TextContainer.LineFragmentPadding = 0;
|
||||
uiTextView.BackgroundColor = UIColor.Clear;
|
||||
|
||||
uiTextView.Text = Element.Text;
|
||||
uiTextView.TextColor = Element.TextColor.ToUIColor();
|
||||
switch (Element.FontAttributes)
|
||||
{
|
||||
case FontAttributes.None:
|
||||
uiTextView.Font = UIFont.SystemFontOfSize(new nfloat(Element.FontSize));
|
||||
break;
|
||||
case FontAttributes.Bold:
|
||||
uiTextView.Font = UIFont.BoldSystemFontOfSize(new nfloat(Element.FontSize));
|
||||
break;
|
||||
case FontAttributes.Italic:
|
||||
uiTextView.Font = UIFont.ItalicSystemFontOfSize(new nfloat(Element.FontSize));
|
||||
break;
|
||||
default:
|
||||
uiTextView.Font = UIFont.BoldSystemFontOfSize(new nfloat(Element.FontSize));
|
||||
break;
|
||||
}
|
||||
|
||||
SetNativeControl(uiTextView);
|
||||
}
|
||||
|
||||
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
base.OnElementPropertyChanged(sender, e);
|
||||
|
||||
if (e.PropertyName == Label.TextProperty.PropertyName)
|
||||
{
|
||||
if (Control != null && Element != null && !string.IsNullOrWhiteSpace(Element.Text))
|
||||
{
|
||||
uiTextView.Text = Element.Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ using Bit.Core.Abstractions;
|
||||
using Foundation;
|
||||
using MobileCoreServices;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.iOS.Core.Services
|
||||
{
|
||||
|
||||
@@ -48,9 +48,10 @@ namespace Bit.iOS.Core.Services
|
||||
var passwordData = NSData.FromArray(password);
|
||||
var saltData = NSData.FromArray(salt);
|
||||
|
||||
argon2id_hash_raw(iterations, memory, parallelism, passwordData.Bytes, passwordData.Length,
|
||||
saltData.Bytes, saltData.Length, keyData.MutableBytes, keyData.Length);
|
||||
|
||||
// TODO: [MAUI-Migration] [Critical]
|
||||
//argon2id_hash_raw(iterations, memory, parallelism, passwordData.Bytes, passwordData.Length,
|
||||
// saltData.Bytes, saltData.Length, keyData.MutableBytes, keyData.Length);
|
||||
|
||||
var keyBytes = new byte[keyData.Length];
|
||||
Marshal.Copy(keyData.Bytes, keyBytes, 0, Convert.ToInt32(keyData.Length));
|
||||
return keyBytes;
|
||||
@@ -61,8 +62,9 @@ namespace Bit.iOS.Core.Services
|
||||
private extern static int CCKeyCerivationPBKDF(uint algorithm, IntPtr password, nuint passwordLen,
|
||||
IntPtr salt, nuint saltLen, uint prf, nuint rounds, IntPtr derivedKey, nuint derivedKeyLength);
|
||||
|
||||
[DllImport("__Internal", EntryPoint = "argon2id_hash_raw")]
|
||||
private static extern int argon2id_hash_raw(int timeCost, int memoryCost, int parallelism, IntPtr pwd,
|
||||
nuint pwdlen, IntPtr salt, nuint saltlen, IntPtr hash, nuint hashlen);
|
||||
// TODO: [MAUI-Migration] [Critical]
|
||||
//[DllImport("__Internal", EntryPoint = "argon2id_hash_raw")]
|
||||
//private static extern int argon2id_hash_raw(int timeCost, int memoryCost, int parallelism, IntPtr pwd,
|
||||
// nuint pwdlen, IntPtr salt, nuint saltlen, IntPtr hash, nuint hashlen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.App.Utilities.Prompts;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
@@ -11,7 +11,7 @@ using CoreGraphics;
|
||||
using Foundation;
|
||||
using LocalAuthentication;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.iOS.Core.Services
|
||||
{
|
||||
@@ -27,14 +27,14 @@ namespace Bit.iOS.Core.Services
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_userAgent))
|
||||
{
|
||||
_userAgent = $"Bitwarden_Mobile/{Xamarin.Essentials.AppInfo.VersionString} " +
|
||||
_userAgent = $"Bitwarden_Mobile/{AppInfo.VersionString} " +
|
||||
$"(iOS {UIDevice.CurrentDevice.SystemVersion}; Model {UIDevice.CurrentDevice.Model})";
|
||||
}
|
||||
return _userAgent;
|
||||
}
|
||||
}
|
||||
|
||||
public DeviceType DeviceType => DeviceType.iOS;
|
||||
public Bit.Core.Enums.DeviceType DeviceType => Bit.Core.Enums.DeviceType.iOS;
|
||||
|
||||
public bool LaunchApp(string appName)
|
||||
{
|
||||
@@ -165,7 +165,7 @@ namespace Bit.iOS.Core.Services
|
||||
{
|
||||
uri = "itms-apps://itunes.apple.com/us/app/id1137397744?action=write-review";
|
||||
}
|
||||
Device.OpenUri(new Uri(uri));
|
||||
Launcher.OpenAsync(uri).FireAndForget();
|
||||
}
|
||||
|
||||
public bool SupportsFaceBiometric()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using Foundation;
|
||||
|
||||
@@ -4,8 +4,6 @@ using Bit.App.Controls;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
namespace Bit.iOS.Core.Utilities
|
||||
{
|
||||
@@ -69,21 +67,22 @@ namespace Bit.iOS.Core.Utilities
|
||||
overlay.BindingContext = vm;
|
||||
overlay.IsVisible = false;
|
||||
|
||||
var renderer = Platform.CreateRenderer(overlay.Content);
|
||||
renderer.SetElementSize(new Size(containerView.Frame.Size.Width, containerView.Frame.Size.Height));
|
||||
// TODO: [MAUI-Migration] [Critical] check how to create a native view here.
|
||||
//var renderer = Platform.CreateRenderer(overlay.Content);
|
||||
//renderer.SetElementSize(new Size(containerView.Frame.Size.Width, containerView.Frame.Size.Height));
|
||||
|
||||
var view = renderer.NativeView;
|
||||
view.TranslatesAutoresizingMaskIntoConstraints = false;
|
||||
//var view = renderer.NativeView;
|
||||
//view.TranslatesAutoresizingMaskIntoConstraints = false;
|
||||
|
||||
containerView.AddSubview(view);
|
||||
containerView.AddConstraints(new NSLayoutConstraint[]
|
||||
{
|
||||
NSLayoutConstraint.Create(containerView, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, view, NSLayoutAttribute.Trailing, 1f, 0f),
|
||||
NSLayoutConstraint.Create(containerView, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, view, NSLayoutAttribute.Leading, 1f, 0f),
|
||||
NSLayoutConstraint.Create(containerView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, view, NSLayoutAttribute.Top, 1f, 0f),
|
||||
NSLayoutConstraint.Create(containerView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, view, NSLayoutAttribute.Bottom, 1f, 0f)
|
||||
});
|
||||
containerView.Hidden = true;
|
||||
//containerView.AddSubview(view);
|
||||
//containerView.AddConstraints(new NSLayoutConstraint[]
|
||||
//{
|
||||
// NSLayoutConstraint.Create(containerView, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, view, NSLayoutAttribute.Trailing, 1f, 0f),
|
||||
// NSLayoutConstraint.Create(containerView, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, view, NSLayoutAttribute.Leading, 1f, 0f),
|
||||
// NSLayoutConstraint.Create(containerView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, view, NSLayoutAttribute.Top, 1f, 0f),
|
||||
// NSLayoutConstraint.Create(containerView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, view, NSLayoutAttribute.Bottom, 1f, 0f)
|
||||
//});
|
||||
//containerView.Hidden = true;
|
||||
|
||||
return overlay;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Internals;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
namespace Bit.iOS.Core.Utilities
|
||||
{
|
||||
public static class FontElementExtensions
|
||||
{
|
||||
public static UIFont ToUIFont(this IFontElement fontElement)
|
||||
// TODO: [MAUI-Migration] [Critical] Compiling but big untested change
|
||||
|
||||
public static UIFont ToUIFont(this Microsoft.Maui.Font font)
|
||||
{
|
||||
var fontSize = fontElement.FontSize;
|
||||
var fontAttributes = fontElement.FontAttributes;
|
||||
var fontFamily = fontElement.FontFamily;
|
||||
var fontSize = font.Size;
|
||||
var fontAttributes = font.GetFontAttributes();
|
||||
var fontFamily = font.Family;
|
||||
var fontWeight = fontAttributes == FontAttributes.Bold ? UIFontWeight.Bold : UIFontWeight.Regular;
|
||||
|
||||
return fontFamily is null
|
||||
? Font.SystemFontOfSize(fontSize, fontAttributes).ToUIFont()
|
||||
: Font.OfSize(fontFamily, fontSize).WithAttributes(fontAttributes).ToUIFont();
|
||||
? UIFont.SystemFontOfSize((nfloat)fontSize, fontWeight)
|
||||
: UIFont.FromName(fontFamily, (nfloat)fontSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.iOS;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
namespace Bit.iOS.Core.Utilities
|
||||
{
|
||||
@@ -21,7 +20,7 @@ namespace Bit.iOS.Core.Utilities
|
||||
return null;
|
||||
}
|
||||
|
||||
var handler = Xamarin.Forms.Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source);
|
||||
var handler = Microsoft.Maui.Controls.Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source);
|
||||
if (handler == null)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(new InvalidOperationException("GetNativeImageAsync failed cause IImageSourceHandler couldn't be found"));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
using Bit.App.Utilities;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.iOS;
|
||||
using UIKit;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
namespace Bit.iOS.Core.Utilities
|
||||
{
|
||||
@@ -75,8 +75,8 @@ namespace Bit.iOS.Core.Utilities
|
||||
|
||||
public static UIFont GetDangerFont()
|
||||
{
|
||||
return Xamarin.Forms.Font.SystemFontOfSize(Xamarin.Forms.NamedSize.Small,
|
||||
Xamarin.Forms.FontAttributes.Bold).ToUIFont();
|
||||
// TODO: [MAUI-Migration] [Deprecated] NamedSizes are deprecated on MAUI
|
||||
return Microsoft.Maui.Font.SystemFontOfSize(Device.GetNamedSize(NamedSize.Small, typeof(UILabel)), FontWeight.Bold).ToUIFont();
|
||||
}
|
||||
|
||||
private static void SetThemeVariables(string theme, bool osDarkModeEnabled)
|
||||
|
||||
@@ -5,7 +5,7 @@ using Bit.App.Abstractions;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Models;
|
||||
using Bit.App.Pages;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.App.Services;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.App.Utilities.AccountManagement;
|
||||
@@ -17,7 +17,6 @@ using Bit.iOS.Core.Services;
|
||||
using CoreNFC;
|
||||
using Foundation;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace Bit.iOS.Core.Utilities
|
||||
{
|
||||
@@ -36,8 +35,6 @@ namespace Bit.iOS.Core.Utilities
|
||||
out IAccountsManager accountsManager)
|
||||
where T : UIViewController, IAccountsManagerHost
|
||||
{
|
||||
Forms.Init();
|
||||
|
||||
if (ServiceContainer.RegisteredServices.Count > 0)
|
||||
{
|
||||
ServiceContainer.Reset();
|
||||
@@ -106,7 +103,7 @@ namespace Bit.iOS.Core.Utilities
|
||||
var storageMediatorService = new StorageMediatorService(mobileStorageService, secureStorageService, preferencesStorage);
|
||||
var stateService = new StateService(mobileStorageService, secureStorageService, storageMediatorService, messagingService);
|
||||
var stateMigrationService =
|
||||
new StateMigrationService(DeviceType.iOS, liteDbStorage, preferencesStorage, secureStorageService);
|
||||
new StateMigrationService(Bit.Core.Enums.DeviceType.iOS, liteDbStorage, preferencesStorage, secureStorageService);
|
||||
var deviceActionService = new DeviceActionService();
|
||||
var fileService = new FileService(stateService, messagingService);
|
||||
var clipboardService = new ClipboardService(stateService);
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Bit.App.Utilities;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.iOS;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
namespace Bit.iOS.Core.Utilities
|
||||
{
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Models.View;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using Bit.App.Resources;
|
||||
using Bit.Core.Resources.Localization;
|
||||
using Bit.Core;
|
||||
using Bit.iOS.Core.Controllers;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
using Bit.App.Utilities;
|
||||
using Foundation;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.iOS;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using UIKit;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Platform.iOS;
|
||||
|
||||
namespace Bit.iOS.Core.Views
|
||||
{
|
||||
|
||||
@@ -1,240 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{E71F3053-056C-4381-9638-048ED73BDFF6}</ProjectGuid>
|
||||
<ProjectTypeGuids>{FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<TemplateGuid>{a52b8a63-bc84-4b47-910d-692533484892}</TemplateGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFrameworks>net8.0-ios;net8.0-android</TargetFrameworks>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseMaui>true</UseMaui>
|
||||
<ImplicitUsings>true</ImplicitUsings>
|
||||
|
||||
<ForceSimulatorX64ArchitectureInIDE>true</ForceSimulatorX64ArchitectureInIDE>
|
||||
|
||||
<!--<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">11.0</SupportedOSPlatformVersion>-->
|
||||
<RootNamespace>Bit.iOS.Core</RootNamespace>
|
||||
<IPhoneResourcePrefix>Resources</IPhoneResourcePrefix>
|
||||
<AssemblyName>BitwardeniOSCore</AssemblyName>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhone' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\iPhone\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|iPhoneSimulator' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\iPhoneSimulator\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
<CreatePackage>false</CreatePackage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<ConsolePause>false</ConsolePause>
|
||||
<CreatePackage>false</CreatePackage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|iPhoneSimulator' ">
|
||||
<OutputPath>bin\iPhoneSimulator\Release\</OutputPath>
|
||||
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;VSX1000</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'FDroid|AnyCPU'">
|
||||
<OutputPath>bin\FDroid\</OutputPath>
|
||||
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'AppStore|AnyCPU'">
|
||||
<OutputPath>bin\AppStore\</OutputPath>
|
||||
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;VSX1000</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|iPhone' ">
|
||||
<OutputPath>bin\iPhone\AppStore\</OutputPath>
|
||||
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;VSX1000</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'AppStore|iPhoneSimulator' ">
|
||||
<OutputPath>bin\iPhoneSimulator\AppStore\</OutputPath>
|
||||
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;VSX1000</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Ad-Hoc|AnyCPU'">
|
||||
<OutputPath>bin\Ad-Hoc\</OutputPath>
|
||||
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;VSX1000</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Ad-Hoc|iPhone' ">
|
||||
<OutputPath>bin\iPhone\Ad-Hoc\</OutputPath>
|
||||
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;VSX1000</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Ad-Hoc|iPhoneSimulator' ">
|
||||
<OutputPath>bin\iPhoneSimulator\Ad-Hoc\</OutputPath>
|
||||
<DefineConstants>__IOS__;__MOBILE__;__UNIFIED__;</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;VSX1000</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="Xamarin.iOS" />
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0-android'">
|
||||
<Content Remove="**" />
|
||||
<Compile Remove="**" />
|
||||
<EmbeddedResource Remove="**" />
|
||||
<None Remove="**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\" />
|
||||
<Folder Include="Effects\" />
|
||||
<Folder Include="Renderers\CollectionView\" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="$(MauiVersion)" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Constants.cs" />
|
||||
<Compile Include="Controllers\ExtendedUITableViewController.cs" />
|
||||
<Compile Include="Controllers\ExtendedUITableViewCell.cs" />
|
||||
<Compile Include="Controllers\ExtendedUIViewController.cs" />
|
||||
<Compile Include="Controllers\ExtendedUITableViewSource.cs" />
|
||||
<Compile Include="Controllers\LoginAddViewController.cs" />
|
||||
<Compile Include="Controllers\PasswordGeneratorViewController.cs" />
|
||||
<Compile Include="Models\AppExtensionContext.cs" />
|
||||
<Compile Include="Models\CipherViewModel.cs" />
|
||||
<Compile Include="Models\FillScript.cs" />
|
||||
<Compile Include="Models\PageDetails.cs" />
|
||||
<Compile Include="Models\PasswordGenerationOptions.cs" />
|
||||
<Compile Include="NFCReaderDelegate.cs" />
|
||||
<Compile Include="Renderers\CustomButtonRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomContentPageRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomNavigationRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedDatePickerRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomEditorRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomEntryRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomLabelRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomPickerRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomSearchBarRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomTabbedRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedStepperRenderer.cs" />
|
||||
<Compile Include="Renderers\ExtendedTimePickerRenderer.cs" />
|
||||
<Compile Include="Renderers\CustomViewCellRenderer.cs" />
|
||||
<Compile Include="Renderers\HybridWebViewRenderer.cs" />
|
||||
<Compile Include="Services\BiometricService.cs" />
|
||||
<Compile Include="Services\DeviceActionService.cs" />
|
||||
<Compile Include="Utilities\ASHelpers.cs" />
|
||||
<Compile Include="Utilities\Dialogs.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
||||
<Compile Include="Services\KeyChainStorageService.cs" />
|
||||
<Compile Include="Services\LocalizeService.cs" />
|
||||
<Compile Include="Utilities\iOSCoreHelpers.cs" />
|
||||
<Compile Include="Utilities\iOSHelpers.cs" />
|
||||
<Compile Include="Utilities\ThemeHelpers.cs" />
|
||||
<Compile Include="Views\CustomPresentationControllerDelegate.cs" />
|
||||
<Compile Include="Views\ExtensionSearchDelegate.cs" />
|
||||
<Compile Include="Views\ExtensionTableSource.cs" />
|
||||
<Compile Include="Views\FormEntryTableViewCell.cs" />
|
||||
<Compile Include="Views\ISelectable.cs" />
|
||||
<Compile Include="Views\PickerTableViewCell.cs" />
|
||||
<Compile Include="Views\SliderTableViewCell.cs" />
|
||||
<Compile Include="Views\StepperTableViewCell.cs" />
|
||||
<Compile Include="Views\SwitchTableViewCell.cs" />
|
||||
<Compile Include="Views\Toast.cs" />
|
||||
<Compile Include="Renderers\SelectableLabelRenderer.cs" />
|
||||
<Compile Include="Effects\ScrollEnabledEffect.cs" />
|
||||
<Compile Include="Services\ClipboardService.cs" />
|
||||
<Compile Include="Utilities\FontElementExtensions.cs" />
|
||||
<Compile Include="Effects\ScrollViewContentInsetAdjustmentBehaviorEffect.cs" />
|
||||
<Compile Include="Utilities\AccountSwitchingOverlayHelper.cs" />
|
||||
<Compile Include="Utilities\ImageSourceExtensions.cs" />
|
||||
<Compile Include="Controllers\BaseLockPasswordViewController.cs" />
|
||||
<Compile Include="Renderers\CollectionView\ExtendedCollectionViewRenderer.cs" />
|
||||
<Compile Include="Renderers\CollectionView\ExtendedGroupableItemsViewController.cs" />
|
||||
<Compile Include="Utilities\UISearchBarExtensions.cs" />
|
||||
<Compile Include="Renderers\CollectionView\CollectionException.cs" />
|
||||
<Compile Include="Renderers\CollectionView\ExtendedGroupableItemsViewDelegator.cs" />
|
||||
<Compile Include="Effects\NoEmojiKeyboardEffect.cs" />
|
||||
<Compile Include="Utilities\WCSessionManager.cs" />
|
||||
<Compile Include="Services\FileService.cs" />
|
||||
<Compile Include="Utilities\UIViewControllerExtensions.cs" />
|
||||
<Compile Include="Services\AutofillHandler.cs" />
|
||||
<Compile Include="Utilities\DictionaryExtensions.cs" />
|
||||
<Compile Include="Services\WatchDeviceService.cs" />
|
||||
<ProjectReference Include="..\Core\Core.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\App\App.csproj">
|
||||
<Project>{ee44c6a1-2a85-45fe-8d9b-bf1d5f88809c}</Project>
|
||||
<Name>App</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Core\Core.csproj">
|
||||
<Project>{4b8a8c41-9820-4341-974c-41e65b7f4366}</Project>
|
||||
<Name>Core</Name>
|
||||
</ProjectReference>
|
||||
<None Remove="Handlers\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NETStandard.Library">
|
||||
<Version>2.0.3</Version>
|
||||
</PackageReference>
|
||||
<Folder Include="Handlers\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user