diff --git a/src/Android/Services/DeviceActionService.cs b/src/Android/Services/DeviceActionService.cs
index 2ddee1245..c50558280 100644
--- a/src/Android/Services/DeviceActionService.cs
+++ b/src/Android/Services/DeviceActionService.cs
@@ -520,5 +520,11 @@ namespace Bit.Droid.Services
intent.SetData(uri);
Application.Context.StartActivity(intent);
}
+
+ public void CloseExtensionPopUp()
+ {
+ // only used by iOS
+ throw new NotImplementedException();
+ }
}
}
diff --git a/src/App/Abstractions/IDeviceActionService.cs b/src/App/Abstractions/IDeviceActionService.cs
index 8f4a19a34..70384100e 100644
--- a/src/App/Abstractions/IDeviceActionService.cs
+++ b/src/App/Abstractions/IDeviceActionService.cs
@@ -37,5 +37,6 @@ namespace Bit.App.Abstractions
Task OnAccountSwitchCompleteAsync();
Task SetScreenCaptureAllowedAsync();
void OpenAppSettings();
+ void CloseExtensionPopUp();
}
}
diff --git a/src/App/Pages/Generator/GeneratorPage.xaml b/src/App/Pages/Generator/GeneratorPage.xaml
index 00cd35381..06f436759 100644
--- a/src/App/Pages/Generator/GeneratorPage.xaml
+++ b/src/App/Pages/Generator/GeneratorPage.xaml
@@ -21,7 +21,7 @@
-
_selectAction;
private readonly TabsPage _tabsPage;
- public GeneratorPage(bool fromTabPage, Action selectAction = null, TabsPage tabsPage = null, bool isUsernameGenerator = false, string emailWebsite = null, bool editMode = false)
+ public GeneratorPage(bool fromTabPage, Action selectAction = null, TabsPage tabsPage = null, bool isUsernameGenerator = false, string emailWebsite = null, bool editMode = false, AppOptions appOptions = null)
{
_tabsPage = tabsPage;
InitializeComponent();
- _broadcasterService = ServiceContainer.Resolve("broadcasterService");
+ _broadcasterService = ServiceContainer.Resolve();
_vm = BindingContext as GeneratorPageViewModel;
_vm.Page = this;
_fromTabPage = fromTabPage;
@@ -31,6 +32,7 @@ namespace Bit.App.Pages
_vm.IsUsername = isUsernameGenerator;
_vm.EmailWebsite = emailWebsite;
_vm.EditMode = editMode;
+ _vm.IosExtension = appOptions?.IosExtension ?? false;
var isIos = Device.RuntimePlatform == Device.iOS;
if (selectAction != null)
{
@@ -134,14 +136,6 @@ namespace Bit.App.Pages
await _vm.SliderChangedAsync();
}
- private async void Close_Clicked(object sender, EventArgs e)
- {
- if (DoOnce())
- {
- await Navigation.PopModalAsync();
- }
- }
-
public override async Task UpdateOnThemeChanged()
{
await base.UpdateOnThemeChanged();
diff --git a/src/App/Pages/Generator/GeneratorPageViewModel.cs b/src/App/Pages/Generator/GeneratorPageViewModel.cs
index 6e51ef0d4..b5f103034 100644
--- a/src/App/Pages/Generator/GeneratorPageViewModel.cs
+++ b/src/App/Pages/Generator/GeneratorPageViewModel.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Windows.Input;
+using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.Core;
@@ -21,6 +22,7 @@ namespace Bit.App.Pages
private readonly IClipboardService _clipboardService;
private readonly IUsernameGenerationService _usernameGenerationService;
private readonly ITokenService _tokenService;
+ private readonly IDeviceActionService _deviceActionService;
readonly LazyResolve _logger = new LazyResolve("logger");
private PasswordGenerationOptions _options;
@@ -59,6 +61,7 @@ namespace Bit.App.Pages
_clipboardService = ServiceContainer.Resolve();
_usernameGenerationService = ServiceContainer.Resolve();
_tokenService = ServiceContainer.Resolve();
+ _deviceActionService = ServiceContainer.Resolve();
PageTitle = AppResources.Generator;
GeneratorTypeOptions = new List {
@@ -89,8 +92,9 @@ namespace Bit.App.Pages
UsernameTypePromptHelpCommand = new Command(UsernameTypePromptHelp);
RegenerateCommand = new AsyncCommand(RegenerateAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
RegenerateUsernameCommand = new AsyncCommand(RegenerateUsernameAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
- ToggleForwardedEmailHiddenValueCommand = new AsyncCommand(ToggleForwardedEmailHiddenValueAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
- CopyCommand = new AsyncCommand(CopyAsync, onException: ex => OnSubmitException(ex), allowsMultipleExecutions: false);
+ ToggleForwardedEmailHiddenValueCommand = new AsyncCommand(ToggleForwardedEmailHiddenValueAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
+ CopyCommand = new AsyncCommand(CopyAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
+ CloseCommand = new AsyncCommand(CloseAsync, onException: ex => _logger.Value.Exception(ex), allowsMultipleExecutions: false);
}
public List GeneratorTypeOptions { get; set; }
@@ -104,6 +108,7 @@ namespace Bit.App.Pages
public ICommand RegenerateUsernameCommand { get; set; }
public ICommand ToggleForwardedEmailHiddenValueCommand { get; set; }
public ICommand CopyCommand { get; set; }
+ public ICommand CloseCommand { get; set; }
public string Password
{
@@ -140,6 +145,8 @@ namespace Bit.App.Pages
set => SetProperty(ref _isUsername, value);
}
+ public bool IosExtension { get; set; }
+
public bool ShowTypePicker
{
get => _showTypePicker;
@@ -606,6 +613,7 @@ namespace Bit.App.Pages
LoadFromOptions();
_usernameOptions = await _usernameGenerationService.GetOptionsAsync();
+ await _tokenService.PrepareTokenForDecodingAsync();
_usernameOptions.PlusAddressedEmail = _tokenService.GetEmail();
_usernameOptions.EmailWebsite = EmailWebsite;
_usernameOptions.CatchAllEmailType = _usernameOptions.PlusAddressedEmailType = string.IsNullOrWhiteSpace(EmailWebsite) || !EditMode ? UsernameEmailType.Random : UsernameEmailType.Website;
@@ -681,6 +689,7 @@ namespace Bit.App.Pages
return;
}
+ _usernameOptions.EmailWebsite = EmailWebsite;
await _usernameGenerationService.SaveOptionsAsync(_usernameOptions);
if (regenerate && UsernameTypeSelected != UsernameType.ForwardedEmailAlias)
@@ -729,6 +738,18 @@ namespace Bit.App.Pages
}
}
+ public async Task CloseAsync()
+ {
+ if (IosExtension)
+ {
+ _deviceActionService.CloseExtensionPopUp();
+ }
+ else
+ {
+ await Page.Navigation.PopModalAsync();
+ }
+ }
+
private void LoadFromOptions()
{
AllowAmbiguousChars = _options.AllowAmbiguousChar.GetValueOrDefault();
@@ -765,6 +786,7 @@ namespace Bit.App.Pages
TriggerPropertyChanged(nameof(PlusAddressedEmail));
TriggerPropertyChanged(nameof(GeneratorTypeSelected));
TriggerPropertyChanged(nameof(UsernameTypeDescriptionLabel));
+ TriggerPropertyChanged(nameof(EmailWebsite));
}
private void SetOptions()
diff --git a/src/Core/Abstractions/ITokenService.cs b/src/Core/Abstractions/ITokenService.cs
index 578c97d8f..123c60e8a 100644
--- a/src/Core/Abstractions/ITokenService.cs
+++ b/src/Core/Abstractions/ITokenService.cs
@@ -28,5 +28,6 @@ namespace Bit.Core.Abstractions
Task SetTwoFactorTokenAsync(string token, string email);
bool TokenNeedsRefresh(int minutes = 5);
int TokenSecondsRemaining();
+ Task PrepareTokenForDecodingAsync();
}
}
diff --git a/src/Core/Services/TokenService.cs b/src/Core/Services/TokenService.cs
index 9edd32b22..30bbbe565 100644
--- a/src/Core/Services/TokenService.cs
+++ b/src/Core/Services/TokenService.cs
@@ -44,6 +44,11 @@ namespace Bit.Core.Services
return _accessTokenForDecoding;
}
+ public async Task PrepareTokenForDecodingAsync()
+ {
+ _accessTokenForDecoding = await _stateService.GetAccessTokenAsync();
+ }
+
public async Task SetRefreshTokenAsync(string refreshToken)
{
await _stateService.SetRefreshTokenAsync(refreshToken, await SkipTokenStorage());
diff --git a/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs b/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs
index 3a9f24ce4..98db64ad6 100644
--- a/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs
+++ b/src/iOS.Core/Controllers/BaseLockPasswordViewController.cs
@@ -5,7 +5,6 @@ using Bit.App.Models;
using Bit.App.Pages;
using Bit.App.Resources;
using Bit.App.Utilities;
-using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.Domain;
@@ -55,7 +54,7 @@ namespace Bit.iOS.Core.Controllers
public abstract Action Cancel { get; }
public FormEntryTableViewCell MasterPasswordCell { get; set; } = new FormEntryTableViewCell(
- AppResources.MasterPassword, useButton: true);
+ AppResources.MasterPassword, buttonsConfig: FormEntryTableViewCell.ButtonsConfig.One);
public string BiometricIntegrityKey { get; set; }
@@ -161,13 +160,7 @@ namespace Bit.iOS.Core.Controllers
{
MasterPasswordCell.TextField.KeyboardType = UIKeyboardType.NumberPad;
}
- MasterPasswordCell.Button.TitleLabel.Font = UIFont.FromName("bwi-font", 28f);
- MasterPasswordCell.Button.SetTitle(BitwardenIcons.Eye, UIControlState.Normal);
- MasterPasswordCell.Button.TouchUpInside += (sender, e) =>
- {
- MasterPasswordCell.TextField.SecureTextEntry = !MasterPasswordCell.TextField.SecureTextEntry;
- MasterPasswordCell.Button.SetTitle(MasterPasswordCell.TextField.SecureTextEntry ? BitwardenIcons.Eye : BitwardenIcons.EyeSlash, UIControlState.Normal);
- };
+ MasterPasswordCell.ConfigureToggleSecureTextCell();
}
if (TableView != null)
diff --git a/src/iOS.Core/Controllers/LockPasswordViewController.cs b/src/iOS.Core/Controllers/LockPasswordViewController.cs
index 7f879d3bd..7a04759cf 100644
--- a/src/iOS.Core/Controllers/LockPasswordViewController.cs
+++ b/src/iOS.Core/Controllers/LockPasswordViewController.cs
@@ -14,7 +14,6 @@ using Bit.Core.Enums;
using Bit.App.Pages;
using Bit.App.Models;
using Xamarin.Forms;
-using Bit.Core;
namespace Bit.iOS.Core.Controllers
{
@@ -52,7 +51,7 @@ namespace Bit.iOS.Core.Controllers
public abstract Action Cancel { get; }
public FormEntryTableViewCell MasterPasswordCell { get; set; } = new FormEntryTableViewCell(
- AppResources.MasterPassword, useButton: true);
+ AppResources.MasterPassword, buttonsConfig: FormEntryTableViewCell.ButtonsConfig.One);
public string BiometricIntegrityKey { get; set; }
@@ -155,12 +154,7 @@ namespace Bit.iOS.Core.Controllers
{
MasterPasswordCell.TextField.KeyboardType = UIKeyboardType.NumberPad;
}
- MasterPasswordCell.Button.TitleLabel.Font = UIFont.FromName("bwi-font", 28f);
- MasterPasswordCell.Button.SetTitle(BitwardenIcons.Eye, UIControlState.Normal);
- MasterPasswordCell.Button.TouchUpInside += (sender, e) => {
- MasterPasswordCell.TextField.SecureTextEntry = !MasterPasswordCell.TextField.SecureTextEntry;
- MasterPasswordCell.Button.SetTitle(MasterPasswordCell.TextField.SecureTextEntry ? BitwardenIcons.Eye : BitwardenIcons.EyeSlash, UIControlState.Normal);
- };
+ MasterPasswordCell.ConfigureToggleSecureTextCell();
}
TableView.RowHeight = UITableView.AutomaticDimension;
diff --git a/src/iOS.Core/Controllers/LoginAddViewController.cs b/src/iOS.Core/Controllers/LoginAddViewController.cs
index 2274aa37d..935f70b56 100644
--- a/src/iOS.Core/Controllers/LoginAddViewController.cs
+++ b/src/iOS.Core/Controllers/LoginAddViewController.cs
@@ -1,18 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
+using AuthenticationServices;
+using Bit.App.Models;
+using Bit.App.Pages;
using Bit.App.Resources;
+using Bit.App.Utilities;
+using Bit.Core;
+using Bit.Core.Abstractions;
+using Bit.Core.Exceptions;
+using Bit.Core.Models.View;
+using Bit.Core.Utilities;
+using Bit.iOS.Core.Models;
+using Bit.iOS.Core.Utilities;
using Bit.iOS.Core.Views;
using Foundation;
using UIKit;
-using Bit.iOS.Core.Utilities;
-using Bit.iOS.Core.Models;
-using System.Threading.Tasks;
-using AuthenticationServices;
-using Bit.Core.Abstractions;
-using Bit.Core.Models.View;
-using Bit.Core.Utilities;
-using Bit.Core.Exceptions;
+using Xamarin.Forms;
namespace Bit.iOS.Core.Controllers
{
@@ -29,10 +34,8 @@ namespace Bit.iOS.Core.Controllers
public AppExtensionContext Context { get; set; }
public FormEntryTableViewCell NameCell { get; set; } = new FormEntryTableViewCell(AppResources.Name);
- public FormEntryTableViewCell UsernameCell { get; set; } = new FormEntryTableViewCell(AppResources.Username);
- public FormEntryTableViewCell PasswordCell { get; set; } = new FormEntryTableViewCell(AppResources.Password);
- public UITableViewCell GeneratePasswordCell { get; set; } = new ExtendedUITableViewCell(
- UITableViewCellStyle.Subtitle, "GeneratePasswordCell");
+ public FormEntryTableViewCell UsernameCell { get; set; } = new FormEntryTableViewCell(AppResources.Username, buttonsConfig: FormEntryTableViewCell.ButtonsConfig.One);
+ public FormEntryTableViewCell PasswordCell { get; set; } = new FormEntryTableViewCell(AppResources.Password, buttonsConfig: FormEntryTableViewCell.ButtonsConfig.Two);
public FormEntryTableViewCell UriCell { get; set; } = new FormEntryTableViewCell(AppResources.URI);
public SwitchTableViewCell FavoriteCell { get; set; } = new SwitchTableViewCell(AppResources.Favorite);
public FormEntryTableViewCell NotesCell { get; set; } = new FormEntryTableViewCell(
@@ -67,6 +70,12 @@ namespace Bit.iOS.Core.Controllers
UsernameCell.TextField.AutocorrectionType = UITextAutocorrectionType.No;
UsernameCell.TextField.SpellCheckingType = UITextSpellCheckingType.No;
UsernameCell.TextField.ReturnKeyType = UIReturnKeyType.Next;
+ UsernameCell.Button.TitleLabel.Font = UIFont.FromName("bwi-font", 28f);
+ UsernameCell.Button.SetTitle(BitwardenIcons.Generate, UIControlState.Normal);
+ UsernameCell.Button.TouchUpInside += (sender, e) =>
+ {
+ LaunchUsernameGeneratorFlow();
+ };
UsernameCell.TextField.ShouldReturn += (UITextField tf) =>
{
PasswordCell.TextField.BecomeFirstResponder();
@@ -75,17 +84,20 @@ namespace Bit.iOS.Core.Controllers
PasswordCell.TextField.SecureTextEntry = true;
PasswordCell.TextField.ReturnKeyType = UIReturnKeyType.Next;
+ PasswordCell.Button.TitleLabel.Font = UIFont.FromName("bwi-font", 28f);
+ PasswordCell.Button.SetTitle(BitwardenIcons.Generate, UIControlState.Normal);
+ PasswordCell.Button.TouchUpInside += (sender, e) =>
+ {
+ PerformSegue("passwordGeneratorSegue", this);
+ };
+
+ PasswordCell.ConfigureToggleSecureTextCell(true);
PasswordCell.TextField.ShouldReturn += (UITextField tf) =>
{
UriCell.TextField.BecomeFirstResponder();
return true;
};
- GeneratePasswordCell.TextLabel.Text = AppResources.GeneratePassword;
- GeneratePasswordCell.TextLabel.TextColor = GeneratePasswordCell.TextLabel.TintColor =
- ThemeHelpers.TextColor;
- GeneratePasswordCell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
-
UriCell.TextField.Text = Context?.UrlString ?? string.Empty;
UriCell.TextField.KeyboardType = UIKeyboardType.Url;
UriCell.TextField.ReturnKeyType = UIReturnKeyType.Next;
@@ -210,6 +222,26 @@ namespace Bit.iOS.Core.Controllers
AppResources.InternetConnectionRequiredMessage, AppResources.Ok);
}
+ private void LaunchUsernameGeneratorFlow()
+ {
+ var appOptions = new AppOptions { IosExtension = true };
+ var app = new App.App(appOptions);
+
+ var generatorPage = new GeneratorPage(false, selectAction: async (username) =>
+ {
+ UsernameCell.TextField.Text = username;
+ DismissViewController(false, null);
+ }, isUsernameGenerator: true, emailWebsite: NameCell.TextField.Text, appOptions: appOptions);
+
+ ThemeManager.SetTheme(app.Resources);
+ ThemeManager.ApplyResourcesTo(generatorPage);
+
+ var navigationPage = new NavigationPage(generatorPage);
+ var generatorController = navigationPage.CreateViewController();
+ generatorController.ModalPresentationStyle = UIModalPresentationStyle.FullScreen;
+ PresentViewController(generatorController, true, null);
+ }
+
public class TableSource : ExtendedUITableViewSource
{
private LoginAddViewController _controller;
@@ -235,10 +267,6 @@ namespace Bit.iOS.Core.Controllers
{
return _controller.PasswordCell;
}
- else if (indexPath.Row == 3)
- {
- return _controller.GeneratePasswordCell;
- }
}
else if (indexPath.Section == 1)
{
@@ -277,7 +305,7 @@ namespace Bit.iOS.Core.Controllers
{
if (section == 0)
{
- return 4;
+ return 3;
}
else if (section == 1)
{
@@ -317,11 +345,6 @@ namespace Bit.iOS.Core.Controllers
tableView.DeselectRow(indexPath, true);
tableView.EndEditing(true);
- if (indexPath.Section == 0 && indexPath.Row == 3)
- {
- _controller.PerformSegue("passwordGeneratorSegue", this);
- }
-
var cell = tableView.CellAt(indexPath);
if (cell == null)
{
diff --git a/src/iOS.Core/Services/DeviceActionService.cs b/src/iOS.Core/Services/DeviceActionService.cs
index c2bec2753..21de54abe 100644
--- a/src/iOS.Core/Services/DeviceActionService.cs
+++ b/src/iOS.Core/Services/DeviceActionService.cs
@@ -379,5 +379,10 @@ namespace Bit.iOS.Core.Services
var url = new NSUrl(UIApplication.OpenSettingsUrlString);
UIApplication.SharedApplication.OpenUrl(url);
}
+
+ public void CloseExtensionPopUp()
+ {
+ GetPresentedViewController().DismissViewController(true, null);
+ }
}
}
diff --git a/src/iOS.Core/Views/FormEntryTableViewCell.cs b/src/iOS.Core/Views/FormEntryTableViewCell.cs
index 9ebc25a6d..3de96806a 100644
--- a/src/iOS.Core/Views/FormEntryTableViewCell.cs
+++ b/src/iOS.Core/Views/FormEntryTableViewCell.cs
@@ -1,7 +1,7 @@
-using Bit.iOS.Core.Controllers;
+using System;
+using Bit.Core;
+using Bit.iOS.Core.Controllers;
using Bit.iOS.Core.Utilities;
-using System;
-using System.Drawing;
using UIKit;
namespace Bit.iOS.Core.Views
@@ -12,14 +12,14 @@ namespace Bit.iOS.Core.Views
public UITextField TextField { get; set; }
public UITextView TextView { get; set; }
public UIButton Button { get; set; }
+ public UIButton SecondButton { get; set; }
public event EventHandler ValueChanged;
-
public FormEntryTableViewCell(
string labelName = null,
bool useTextView = false,
nfloat? height = null,
- bool useButton = false,
+ ButtonsConfig buttonsConfig = ButtonsConfig.None,
bool useLabelAsPlaceholder = false,
float leadingConstant = 15f)
: base(UITableViewCellStyle.Default, nameof(FormEntryTableViewCell))
@@ -85,7 +85,6 @@ namespace Bit.iOS.Core.Views
ValueChanged?.Invoke(sender, e);
};
}
-
else
{
TextField = new UITextField
@@ -110,9 +109,10 @@ namespace Bit.iOS.Core.Views
}
ContentView.Add(TextField);
+
ContentView.AddConstraints(new NSLayoutConstraint[] {
NSLayoutConstraint.Create(TextField, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, ContentView, NSLayoutAttribute.Leading, 1f, leadingConstant),
- NSLayoutConstraint.Create(ContentView, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, TextField, NSLayoutAttribute.Trailing, 1f, useButton ? 55f : 15f),
+ NSLayoutConstraint.Create(ContentView, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, TextField, NSLayoutAttribute.Trailing, 1f, GetTextFieldToContainerTrailingConstant(buttonsConfig)),
NSLayoutConstraint.Create(ContentView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, TextField, NSLayoutAttribute.Bottom, 1f, 10f)
});
@@ -148,18 +148,9 @@ namespace Bit.iOS.Core.Views
});
}
- if (useButton)
+ if(buttonsConfig != ButtonsConfig.None)
{
- Button = new UIButton(UIButtonType.System);
- Button.Frame = ContentView.Bounds;
- Button.TranslatesAutoresizingMaskIntoConstraints = false;
- Button.SetTitleColor(ThemeHelpers.PrimaryColor, UIControlState.Normal);
-
- ContentView.Add(Button);
-
- ContentView.BottomAnchor.ConstraintEqualTo(Button.BottomAnchor, 10f).Active = true;
- ContentView.TrailingAnchor.ConstraintEqualTo(Button.TrailingAnchor, 10f).Active = true;
- Button.LeadingAnchor.ConstraintEqualTo(TextField.TrailingAnchor, 10f).Active = true;
+ AddButtons(buttonsConfig);
}
}
@@ -174,5 +165,74 @@ namespace Bit.iOS.Core.Views
TextField.BecomeFirstResponder();
}
}
+
+ public void ConfigureToggleSecureTextCell(bool useSecondaryButton = false)
+ {
+ var button = useSecondaryButton ? SecondButton : Button;
+ button.TitleLabel.Font = UIFont.FromName("bwi-font", 28f);
+ button.SetTitle(BitwardenIcons.Eye, UIControlState.Normal);
+ button.TouchUpInside += (sender, e) =>
+ {
+ TextField.SecureTextEntry = !TextField.SecureTextEntry;
+ button.SetTitle(TextField.SecureTextEntry ? BitwardenIcons.Eye : BitwardenIcons.EyeSlash, UIControlState.Normal);
+ };
+ }
+
+ private void AddButtons(ButtonsConfig buttonsConfig)
+ {
+ Button = new UIButton(UIButtonType.System);
+ Button.TranslatesAutoresizingMaskIntoConstraints = false;
+ Button.SetTitleColor(ThemeHelpers.PrimaryColor, UIControlState.Normal);
+
+ ContentView.Add(Button);
+
+ ContentView.BottomAnchor.ConstraintEqualTo(Button.BottomAnchor, 10f).Active = true;
+
+ switch (buttonsConfig)
+ {
+ case ButtonsConfig.One:
+ ContentView.AddConstraints(new NSLayoutConstraint[] {
+ NSLayoutConstraint.Create(ContentView, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, Button, NSLayoutAttribute.Trailing, 1f, 10f),
+ NSLayoutConstraint.Create(Button, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, TextField, NSLayoutAttribute.Trailing, 1f, 10f)
+ });
+ break;
+ case ButtonsConfig.Two:
+ SecondButton = new UIButton(UIButtonType.System);
+ SecondButton.TranslatesAutoresizingMaskIntoConstraints = false;
+ SecondButton.SetTitleColor(ThemeHelpers.PrimaryColor, UIControlState.Normal);
+
+ ContentView.Add(SecondButton);
+
+ ContentView.AddConstraints(new NSLayoutConstraint[] {
+ NSLayoutConstraint.Create(ContentView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, SecondButton, NSLayoutAttribute.Bottom, 1f, 10f),
+ NSLayoutConstraint.Create(SecondButton, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, TextField, NSLayoutAttribute.Trailing, 1f, 9f),
+ NSLayoutConstraint.Create(Button, NSLayoutAttribute.Leading, NSLayoutRelation.Equal, SecondButton, NSLayoutAttribute.Trailing, 1f, 10f),
+ NSLayoutConstraint.Create(ContentView, NSLayoutAttribute.Trailing, NSLayoutRelation.Equal, Button, NSLayoutAttribute.Trailing, 1f, 10f)
+ });
+ break;
+ }
+ }
+
+ private float GetTextFieldToContainerTrailingConstant(ButtonsConfig buttonsConfig)
+ {
+ switch (buttonsConfig)
+ {
+ case ButtonsConfig.None:
+ return 15f;
+ case ButtonsConfig.One:
+ return 55f;
+ case ButtonsConfig.Two:
+ return 95f;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+
+ public enum ButtonsConfig : byte
+ {
+ None = 0,
+ One = 1,
+ Two = 2
+ }
}
}