mirror of
https://github.com/bitwarden/mobile
synced 2025-12-14 23:33:34 +00:00
ios autofill extension implemented
This commit is contained in:
260
src/iOS.Autofill/CredentialProviderViewController.cs
Normal file
260
src/iOS.Autofill/CredentialProviderViewController.cs
Normal file
@@ -0,0 +1,260 @@
|
|||||||
|
using AuthenticationServices;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using Bit.iOS.Autofill.Models;
|
||||||
|
using Bit.iOS.Core.Utilities;
|
||||||
|
using Foundation;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
public partial class CredentialProviderViewController : ASCredentialProviderViewController
|
||||||
|
{
|
||||||
|
private Context _context;
|
||||||
|
|
||||||
|
public CredentialProviderViewController(IntPtr handle)
|
||||||
|
: base(handle)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public override void ViewDidLoad()
|
||||||
|
{
|
||||||
|
InitApp();
|
||||||
|
base.ViewDidLoad();
|
||||||
|
_context = new Context
|
||||||
|
{
|
||||||
|
ExtContext = ExtensionContext
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrepareCredentialList(ASCredentialServiceIdentifier[] serviceIdentifiers)
|
||||||
|
{
|
||||||
|
_context.ServiceIdentifiers = serviceIdentifiers;
|
||||||
|
if(serviceIdentifiers.Length > 0)
|
||||||
|
{
|
||||||
|
var uri = serviceIdentifiers[0].Identifier;
|
||||||
|
if(serviceIdentifiers[0].Type == ASCredentialServiceIdentifierType.Domain)
|
||||||
|
{
|
||||||
|
uri = string.Concat("https://", uri);
|
||||||
|
}
|
||||||
|
_context.UrlString = uri;
|
||||||
|
}
|
||||||
|
if(!CheckAuthed())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(IsLocked())
|
||||||
|
{
|
||||||
|
PerformSegue("lockPasswordSegue", this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(_context.ServiceIdentifiers == null || _context.ServiceIdentifiers.Length == 0)
|
||||||
|
{
|
||||||
|
PerformSegue("loginSearchSegue", this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PerformSegue("loginListSegue", this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ProvideCredentialWithoutUserInteraction(ASPasswordCredentialIdentity credentialIdentity)
|
||||||
|
{
|
||||||
|
if(!IsAuthed() || IsLocked())
|
||||||
|
{
|
||||||
|
var err = new NSError(new NSString("ASExtensionErrorDomain"),
|
||||||
|
Convert.ToInt32(ASExtensionErrorCode.UserInteractionRequired), null);
|
||||||
|
ExtensionContext.CancelRequest(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_context.CredentialIdentity = credentialIdentity;
|
||||||
|
ProvideCredentialAsync().GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrepareInterfaceToProvideCredential(ASPasswordCredentialIdentity credentialIdentity)
|
||||||
|
{
|
||||||
|
if(!CheckAuthed())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_context.CredentialIdentity = credentialIdentity;
|
||||||
|
CheckLock(async () => await ProvideCredentialAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrepareInterfaceForExtensionConfiguration()
|
||||||
|
{
|
||||||
|
_context.Configuring = true;
|
||||||
|
if(!CheckAuthed())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CheckLock(() => PerformSegue("setupSegue", this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CompleteRequest(string username = null, string password = null, string totp = null)
|
||||||
|
{
|
||||||
|
if((_context?.Configuring ?? true) && string.IsNullOrWhiteSpace(password))
|
||||||
|
{
|
||||||
|
ExtensionContext?.CompleteExtensionConfigurationRequest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(_context == null || string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
|
||||||
|
{
|
||||||
|
var err = new NSError(new NSString("ASExtensionErrorDomain"),
|
||||||
|
Convert.ToInt32(ASExtensionErrorCode.UserCanceled), null);
|
||||||
|
NSRunLoop.Main.BeginInvokeOnMainThread(() => ExtensionContext?.CancelRequest(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!string.IsNullOrWhiteSpace(totp))
|
||||||
|
{
|
||||||
|
UIPasteboard.General.String = totp;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cred = new ASPasswordCredential(username, password);
|
||||||
|
NSRunLoop.Main.BeginInvokeOnMainThread(() => ExtensionContext?.CompleteRequest(cred, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
|
||||||
|
{
|
||||||
|
var navController = segue.DestinationViewController as UINavigationController;
|
||||||
|
if(navController != null)
|
||||||
|
{
|
||||||
|
var listLoginController = navController.TopViewController as LoginListViewController;
|
||||||
|
var listSearchController = navController.TopViewController as LoginSearchViewController;
|
||||||
|
var passwordViewController = navController.TopViewController as LockPasswordViewController;
|
||||||
|
var setupViewController = navController.TopViewController as SetupViewController;
|
||||||
|
|
||||||
|
if(listLoginController != null)
|
||||||
|
{
|
||||||
|
listLoginController.Context = _context;
|
||||||
|
listLoginController.CPViewController = this;
|
||||||
|
}
|
||||||
|
else if(listSearchController != null)
|
||||||
|
{
|
||||||
|
listSearchController.Context = _context;
|
||||||
|
listSearchController.CPViewController = this;
|
||||||
|
}
|
||||||
|
else if(passwordViewController != null)
|
||||||
|
{
|
||||||
|
passwordViewController.CPViewController = this;
|
||||||
|
}
|
||||||
|
else if(setupViewController != null)
|
||||||
|
{
|
||||||
|
setupViewController.CPViewController = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DismissLockAndContinue()
|
||||||
|
{
|
||||||
|
DismissViewController(false, async () =>
|
||||||
|
{
|
||||||
|
if(_context.CredentialIdentity != null)
|
||||||
|
{
|
||||||
|
await ProvideCredentialAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(_context.Configuring)
|
||||||
|
{
|
||||||
|
PerformSegue("setupSegue", this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(_context.ServiceIdentifiers == null || _context.ServiceIdentifiers.Length == 0)
|
||||||
|
{
|
||||||
|
PerformSegue("loginSearchSegue", this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PerformSegue("loginListSegue", this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProvideCredentialAsync()
|
||||||
|
{
|
||||||
|
var cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
||||||
|
var cipher = await cipherService.GetAsync(_context.CredentialIdentity.RecordIdentifier);
|
||||||
|
if(cipher == null || cipher.Type != Bit.Core.Enums.CipherType.Login)
|
||||||
|
{
|
||||||
|
var err = new NSError(new NSString("ASExtensionErrorDomain"),
|
||||||
|
Convert.ToInt32(ASExtensionErrorCode.CredentialIdentityNotFound), null);
|
||||||
|
ExtensionContext.CancelRequest(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||||
|
var decCipher = await cipher.DecryptAsync();
|
||||||
|
string totpCode = null;
|
||||||
|
var disableTotpCopy = await storageService.GetAsync<bool?>(Bit.Core.Constants.DisableAutoTotpCopyKey);
|
||||||
|
if(!disableTotpCopy.GetValueOrDefault(false))
|
||||||
|
{
|
||||||
|
var userService = ServiceContainer.Resolve<IUserService>("userService");
|
||||||
|
var canAccessPremiumAsync = await userService.CanAccessPremiumAsync();
|
||||||
|
if(!string.IsNullOrWhiteSpace(decCipher.Login.Totp) &&
|
||||||
|
(canAccessPremiumAsync || cipher.OrganizationUseTotp))
|
||||||
|
{
|
||||||
|
var totpService = ServiceContainer.Resolve<ITotpService>("totpService");
|
||||||
|
totpCode = await totpService.GetCodeAsync(decCipher.Login.Totp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompleteRequest(decCipher.Login.Username, decCipher.Login.Password, totpCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckLock(Action notLockedAction)
|
||||||
|
{
|
||||||
|
if(IsLocked())
|
||||||
|
{
|
||||||
|
PerformSegue("lockPasswordSegue", this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
notLockedAction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckAuthed()
|
||||||
|
{
|
||||||
|
if(!IsAuthed())
|
||||||
|
{
|
||||||
|
var alert = Dialogs.CreateAlert(null, AppResources.MustLogInMainAppAutofill, AppResources.Ok, (a) =>
|
||||||
|
{
|
||||||
|
CompleteRequest();
|
||||||
|
});
|
||||||
|
PresentViewController(alert, true, null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsLocked()
|
||||||
|
{
|
||||||
|
var lockService = ServiceContainer.Resolve<ILockService>("lockService");
|
||||||
|
return lockService.IsLockedAsync().GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsAuthed()
|
||||||
|
{
|
||||||
|
var userService = ServiceContainer.Resolve<IUserService>("userService");
|
||||||
|
return userService.IsAuthenticatedAsync().GetAwaiter().GetResult();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitApp()
|
||||||
|
{
|
||||||
|
if(ServiceContainer.RegisteredServices.Count > 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iOSCoreHelpers.RegisterLocalServices();
|
||||||
|
ServiceContainer.Init();
|
||||||
|
iOSCoreHelpers.RegisterHockeyApp();
|
||||||
|
iOSCoreHelpers.Bootstrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/iOS.Autofill/CredentialProviderViewController.designer.cs
generated
Normal file
21
src/iOS.Autofill/CredentialProviderViewController.designer.cs
generated
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// WARNING
|
||||||
|
//
|
||||||
|
// This file has been generated automatically by Visual Studio from the outlets and
|
||||||
|
// actions declared in your storyboard file.
|
||||||
|
// Manual changes to this file will not be maintained.
|
||||||
|
//
|
||||||
|
using Foundation;
|
||||||
|
using System;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
[Register ("CredentialProviderViewController")]
|
||||||
|
partial class CredentialProviderViewController
|
||||||
|
{
|
||||||
|
void ReleaseDesignerOutlets ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
29
src/iOS.Autofill/LockPasswordViewController.cs
Normal file
29
src/iOS.Autofill/LockPasswordViewController.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
public partial class LockPasswordViewController : Core.Controllers.LockPasswordViewController
|
||||||
|
{
|
||||||
|
public LockPasswordViewController(IntPtr handle)
|
||||||
|
: base(handle)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public CredentialProviderViewController CPViewController { get; set; }
|
||||||
|
public override UINavigationItem BaseNavItem => NavItem;
|
||||||
|
public override UIBarButtonItem BaseCancelButton => CancelButton;
|
||||||
|
public override UIBarButtonItem BaseSubmitButton => SubmitButton;
|
||||||
|
public override Action Success => () => CPViewController.DismissLockAndContinue();
|
||||||
|
public override Action Cancel => () => CPViewController.CompleteRequest();
|
||||||
|
|
||||||
|
partial void SubmitButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
var task = CheckPasswordAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void CancelButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
Cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
64
src/iOS.Autofill/LockPasswordViewController.designer.cs
generated
Normal file
64
src/iOS.Autofill/LockPasswordViewController.designer.cs
generated
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
// WARNING
|
||||||
|
//
|
||||||
|
// This file has been generated automatically by Visual Studio from the outlets and
|
||||||
|
// actions declared in your storyboard file.
|
||||||
|
// Manual changes to this file will not be maintained.
|
||||||
|
//
|
||||||
|
using Foundation;
|
||||||
|
using System;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
[Register ("LockPasswordViewController")]
|
||||||
|
partial class LockPasswordViewController
|
||||||
|
{
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIBarButtonItem CancelButton { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UITableView MainTableView { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UINavigationItem NavItem { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIBarButtonItem SubmitButton { get; set; }
|
||||||
|
|
||||||
|
[Action ("CancelButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void CancelButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
[Action ("SubmitButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void SubmitButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
void ReleaseDesignerOutlets ()
|
||||||
|
{
|
||||||
|
if (CancelButton != null) {
|
||||||
|
CancelButton.Dispose ();
|
||||||
|
CancelButton = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MainTableView != null) {
|
||||||
|
MainTableView.Dispose ();
|
||||||
|
MainTableView = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NavItem != null) {
|
||||||
|
NavItem.Dispose ();
|
||||||
|
NavItem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SubmitButton != null) {
|
||||||
|
SubmitButton.Dispose ();
|
||||||
|
SubmitButton = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/iOS.Autofill/LoginAddViewController.cs
Normal file
48
src/iOS.Autofill/LoginAddViewController.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using Foundation;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
public partial class LoginAddViewController : Core.Controllers.LoginAddViewController
|
||||||
|
{
|
||||||
|
public LoginAddViewController(IntPtr handle)
|
||||||
|
: base(handle)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public LoginListViewController LoginListController { get; set; }
|
||||||
|
public LoginSearchViewController LoginSearchController { get; set; }
|
||||||
|
|
||||||
|
public override UINavigationItem BaseNavItem => NavItem;
|
||||||
|
public override UIBarButtonItem BaseCancelButton => CancelBarButton;
|
||||||
|
public override UIBarButtonItem BaseSaveButton => SaveBarButton;
|
||||||
|
|
||||||
|
public override Action Success => () =>
|
||||||
|
{
|
||||||
|
LoginListController?.DismissModal();
|
||||||
|
LoginSearchController?.DismissModal();
|
||||||
|
};
|
||||||
|
|
||||||
|
partial void CancelBarButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
DismissViewController(true, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
async partial void SaveBarButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
await SaveAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
|
||||||
|
{
|
||||||
|
if(segue.DestinationViewController is UINavigationController navController)
|
||||||
|
{
|
||||||
|
if(navController.TopViewController is PasswordGeneratorViewController passwordGeneratorController)
|
||||||
|
{
|
||||||
|
passwordGeneratorController.PasswordOptions = Context.PasswordOptions;
|
||||||
|
passwordGeneratorController.Parent = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/iOS.Autofill/LoginAddViewController.designer.cs
generated
Normal file
55
src/iOS.Autofill/LoginAddViewController.designer.cs
generated
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// WARNING
|
||||||
|
//
|
||||||
|
// This file has been generated automatically by Visual Studio from the outlets and
|
||||||
|
// actions declared in your storyboard file.
|
||||||
|
// Manual changes to this file will not be maintained.
|
||||||
|
//
|
||||||
|
using Foundation;
|
||||||
|
using System;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
[Register ("LoginAddViewController")]
|
||||||
|
partial class LoginAddViewController
|
||||||
|
{
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIBarButtonItem CancelBarButton { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UINavigationItem NavItem { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIBarButtonItem SaveBarButton { get; set; }
|
||||||
|
|
||||||
|
[Action ("CancelBarButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void CancelBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
[Action ("SaveBarButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void SaveBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
void ReleaseDesignerOutlets ()
|
||||||
|
{
|
||||||
|
if (CancelBarButton != null) {
|
||||||
|
CancelBarButton.Dispose ();
|
||||||
|
CancelBarButton = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NavItem != null) {
|
||||||
|
NavItem.Dispose ();
|
||||||
|
NavItem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SaveBarButton != null) {
|
||||||
|
SaveBarButton.Dispose ();
|
||||||
|
SaveBarButton = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
100
src/iOS.Autofill/LoginListViewController.cs
Normal file
100
src/iOS.Autofill/LoginListViewController.cs
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.iOS.Autofill.Models;
|
||||||
|
using Foundation;
|
||||||
|
using UIKit;
|
||||||
|
using Bit.iOS.Core.Controllers;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using Bit.iOS.Core.Views;
|
||||||
|
using Bit.iOS.Autofill.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
public partial class LoginListViewController : ExtendedUITableViewController
|
||||||
|
{
|
||||||
|
public LoginListViewController(IntPtr handle)
|
||||||
|
: base(handle)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public Context Context { get; set; }
|
||||||
|
public CredentialProviderViewController CPViewController { get; set; }
|
||||||
|
|
||||||
|
public override void ViewWillAppear(bool animated)
|
||||||
|
{
|
||||||
|
UINavigationBar.Appearance.ShadowImage = new UIImage();
|
||||||
|
UINavigationBar.Appearance.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
|
||||||
|
base.ViewWillAppear(animated);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async override void ViewDidLoad()
|
||||||
|
{
|
||||||
|
base.ViewDidLoad();
|
||||||
|
NavItem.Title = AppResources.Items;
|
||||||
|
CancelBarButton.Title = AppResources.Cancel;
|
||||||
|
|
||||||
|
TableView.RowHeight = UITableView.AutomaticDimension;
|
||||||
|
TableView.EstimatedRowHeight = 44;
|
||||||
|
TableView.Source = new TableSource(this);
|
||||||
|
await ((TableSource)TableView.Source).LoadItemsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void CancelBarButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
CPViewController.CompleteRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void AddBarButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
PerformSegue("loginAddSegue", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void SearchBarButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
PerformSegue("loginSearchFromListSegue", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
|
||||||
|
{
|
||||||
|
if(segue.DestinationViewController is UINavigationController navController)
|
||||||
|
{
|
||||||
|
if(navController.TopViewController is LoginAddViewController addLoginController)
|
||||||
|
{
|
||||||
|
addLoginController.Context = Context;
|
||||||
|
addLoginController.LoginListController = this;
|
||||||
|
}
|
||||||
|
if(navController.TopViewController is LoginSearchViewController searchLoginController)
|
||||||
|
{
|
||||||
|
searchLoginController.Context = Context;
|
||||||
|
searchLoginController.CPViewController = CPViewController;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DismissModal()
|
||||||
|
{
|
||||||
|
DismissViewController(true, async () =>
|
||||||
|
{
|
||||||
|
await ((TableSource)TableView.Source).LoadItemsAsync();
|
||||||
|
TableView.ReloadData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TableSource : ExtensionTableSource
|
||||||
|
{
|
||||||
|
private Context _context;
|
||||||
|
private LoginListViewController _controller;
|
||||||
|
|
||||||
|
public TableSource(LoginListViewController controller)
|
||||||
|
: base(controller.Context, controller)
|
||||||
|
{
|
||||||
|
_context = controller.Context;
|
||||||
|
_controller = controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async override void RowSelected(UITableView tableView, NSIndexPath indexPath)
|
||||||
|
{
|
||||||
|
await AutofillHelpers.TableRowSelectedAsync(tableView, indexPath, this,
|
||||||
|
_controller.CPViewController, _controller, "loginAddSegue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
src/iOS.Autofill/LoginListViewController.designer.cs
generated
Normal file
59
src/iOS.Autofill/LoginListViewController.designer.cs
generated
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// WARNING
|
||||||
|
//
|
||||||
|
// This file has been generated automatically by Visual Studio from the outlets and
|
||||||
|
// actions declared in your storyboard file.
|
||||||
|
// Manual changes to this file will not be maintained.
|
||||||
|
//
|
||||||
|
using Foundation;
|
||||||
|
using System;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
[Register ("LoginListViewController")]
|
||||||
|
partial class LoginListViewController
|
||||||
|
{
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIBarButtonItem AddBarButton { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIBarButtonItem CancelBarButton { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UINavigationItem NavItem { get; set; }
|
||||||
|
|
||||||
|
[Action ("AddBarButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void AddBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
[Action ("CancelBarButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void CancelBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
[Action ("SearchBarButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void SearchBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
void ReleaseDesignerOutlets ()
|
||||||
|
{
|
||||||
|
if (AddBarButton != null) {
|
||||||
|
AddBarButton.Dispose ();
|
||||||
|
AddBarButton = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CancelBarButton != null) {
|
||||||
|
CancelBarButton.Dispose ();
|
||||||
|
CancelBarButton = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NavItem != null) {
|
||||||
|
NavItem.Dispose ();
|
||||||
|
NavItem = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
92
src/iOS.Autofill/LoginSearchViewController.cs
Normal file
92
src/iOS.Autofill/LoginSearchViewController.cs
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.iOS.Autofill.Models;
|
||||||
|
using Foundation;
|
||||||
|
using UIKit;
|
||||||
|
using Bit.iOS.Core.Controllers;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using Bit.iOS.Core.Views;
|
||||||
|
using Bit.iOS.Autofill.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
public partial class LoginSearchViewController : ExtendedUITableViewController
|
||||||
|
{
|
||||||
|
public LoginSearchViewController(IntPtr handle)
|
||||||
|
: base(handle)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public Context Context { get; set; }
|
||||||
|
public CredentialProviderViewController CPViewController { get; set; }
|
||||||
|
|
||||||
|
public override void ViewWillAppear(bool animated)
|
||||||
|
{
|
||||||
|
UINavigationBar.Appearance.ShadowImage = new UIImage();
|
||||||
|
UINavigationBar.Appearance.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
|
||||||
|
base.ViewWillAppear(animated);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async override void ViewDidLoad()
|
||||||
|
{
|
||||||
|
base.ViewDidLoad();
|
||||||
|
NavItem.Title = AppResources.SearchVault;
|
||||||
|
CancelBarButton.Title = AppResources.Cancel;
|
||||||
|
SearchBar.Placeholder = AppResources.Search;
|
||||||
|
|
||||||
|
TableView.RowHeight = UITableView.AutomaticDimension;
|
||||||
|
TableView.EstimatedRowHeight = 44;
|
||||||
|
TableView.Source = new TableSource(this);
|
||||||
|
SearchBar.Delegate = new ExtensionSearchDelegate(TableView);
|
||||||
|
await ((TableSource)TableView.Source).LoadItemsAsync(false, SearchBar.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void CancelBarButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
CPViewController.CompleteRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void AddBarButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
PerformSegue("loginAddFromSearchSegue", this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PrepareForSegue(UIStoryboardSegue segue, NSObject sender)
|
||||||
|
{
|
||||||
|
if(segue.DestinationViewController is UINavigationController navController)
|
||||||
|
{
|
||||||
|
if(navController.TopViewController is LoginAddViewController addLoginController)
|
||||||
|
{
|
||||||
|
addLoginController.Context = Context;
|
||||||
|
addLoginController.LoginSearchController = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DismissModal()
|
||||||
|
{
|
||||||
|
DismissViewController(true, async () =>
|
||||||
|
{
|
||||||
|
await ((TableSource)TableView.Source).LoadItemsAsync(false, SearchBar.Text);
|
||||||
|
TableView.ReloadData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TableSource : ExtensionTableSource
|
||||||
|
{
|
||||||
|
private Context _context;
|
||||||
|
private LoginSearchViewController _controller;
|
||||||
|
|
||||||
|
public TableSource(LoginSearchViewController controller)
|
||||||
|
: base(controller.Context, controller)
|
||||||
|
{
|
||||||
|
_context = controller.Context;
|
||||||
|
_controller = controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async override void RowSelected(UITableView tableView, NSIndexPath indexPath)
|
||||||
|
{
|
||||||
|
await AutofillHelpers.TableRowSelectedAsync(tableView, indexPath, this,
|
||||||
|
_controller.CPViewController, _controller, "loginAddFromSearchSegue");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/iOS.Autofill/LoginSearchViewController.designer.cs
generated
Normal file
55
src/iOS.Autofill/LoginSearchViewController.designer.cs
generated
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
// WARNING
|
||||||
|
//
|
||||||
|
// This file has been generated automatically by Visual Studio from the outlets and
|
||||||
|
// actions declared in your storyboard file.
|
||||||
|
// Manual changes to this file will not be maintained.
|
||||||
|
//
|
||||||
|
using Foundation;
|
||||||
|
using System;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
[Register ("LoginSearchViewController")]
|
||||||
|
partial class LoginSearchViewController
|
||||||
|
{
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIBarButtonItem CancelBarButton { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UINavigationItem NavItem { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UISearchBar SearchBar { get; set; }
|
||||||
|
|
||||||
|
[Action ("AddBarButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void AddBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
[Action ("CancelBarButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void CancelBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
void ReleaseDesignerOutlets ()
|
||||||
|
{
|
||||||
|
if (CancelBarButton != null) {
|
||||||
|
CancelBarButton.Dispose ();
|
||||||
|
CancelBarButton = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NavItem != null) {
|
||||||
|
NavItem.Dispose ();
|
||||||
|
NavItem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SearchBar != null) {
|
||||||
|
SearchBar.Dispose ();
|
||||||
|
SearchBar = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,63 +1,528 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6154.17" systemVersion="13D65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="ObA-dk-sSI">
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="43">
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6153.11"/>
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<scenes>
|
<scenes>
|
||||||
<!--Action View Controller - Image-->
|
<!--Credential Provider View Controller-->
|
||||||
<scene sceneID="7MM-of-jgj">
|
<scene sceneID="42">
|
||||||
<objects>
|
<objects>
|
||||||
<viewController title="Image" id="ObA-dk-sSI" customClass="ActionViewController" sceneMemberID="viewController">
|
<viewController id="43" customClass="CredentialProviderViewController" sceneMemberID="viewController">
|
||||||
<layoutGuides>
|
<layoutGuides>
|
||||||
<viewControllerLayoutGuide type="top" id="qkL-Od-lgU"/>
|
<viewControllerLayoutGuide type="top" id="40"/>
|
||||||
<viewControllerLayoutGuide type="bottom" id="n38-gi-rB5"/>
|
<viewControllerLayoutGuide type="bottom" id="41"/>
|
||||||
</layoutGuides>
|
</layoutGuides>
|
||||||
<view key="view" contentMode="scaleToFill" id="zMn-AG-sqS">
|
<view key="view" contentMode="scaleToFill" id="44">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="320" height="528"/>
|
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="9ga-4F-77Z">
|
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="logo.png" translatesAutoresizingMaskIntoConstraints="NO" id="1713">
|
||||||
<rect key="frame" x="0.0" y="64" width="320" height="464"/>
|
<rect key="frame" x="66" y="316" width="282" height="44"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
<navigationBar contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="NOA-Dm-cuz">
|
|
||||||
<rect key="frame" x="0.0" y="20" width="320" height="44"/>
|
|
||||||
<items>
|
|
||||||
<navigationItem id="3HJ-uW-3hn">
|
|
||||||
<barButtonItem key="leftBarButtonItem" title="Done" style="done" id="WYi-yp-eM6">
|
|
||||||
<connections>
|
|
||||||
<action selector="DoneClicked" destination="ObA-dk-sSI" id="Qdu-qn-U6V"/>
|
|
||||||
</connections>
|
|
||||||
</barButtonItem>
|
|
||||||
</navigationItem>
|
|
||||||
</items>
|
|
||||||
</navigationBar>
|
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="trailing" secondItem="NOA-Dm-cuz" secondAttribute="trailing" id="A05-Pj-hrr"/>
|
<constraint firstItem="1713" firstAttribute="centerY" secondItem="44" secondAttribute="centerY" constant="-30" id="1763"/>
|
||||||
<constraint firstItem="9ga-4F-77Z" firstAttribute="top" secondItem="NOA-Dm-cuz" secondAttribute="bottom" id="Fps-3D-QQW"/>
|
<constraint firstItem="1713" firstAttribute="centerX" secondItem="44" secondAttribute="centerX" id="1764"/>
|
||||||
<constraint firstItem="NOA-Dm-cuz" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="HxO-8t-aoh"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="9ga-4F-77Z" secondAttribute="trailing" id="Ozw-Hg-0yh"/>
|
|
||||||
<constraint firstItem="9ga-4F-77Z" firstAttribute="leading" secondItem="zMn-AG-sqS" secondAttribute="leading" id="XH5-ld-ONA"/>
|
|
||||||
<constraint firstItem="n38-gi-rB5" firstAttribute="top" secondItem="9ga-4F-77Z" secondAttribute="bottom" id="eQg-nn-Zy4"/>
|
|
||||||
<constraint firstItem="NOA-Dm-cuz" firstAttribute="top" secondItem="qkL-Od-lgU" secondAttribute="bottom" id="we0-1t-bgp"/>
|
|
||||||
</constraints>
|
</constraints>
|
||||||
</view>
|
</view>
|
||||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
|
||||||
<size key="freeformSize" width="320" height="528"/>
|
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="imageView" destination="9ga-4F-77Z" id="5y6-5w-9QO"/>
|
<segue destination="oCZ-GQ-aOK" kind="show" identifier="loginListSegue" id="1679"/>
|
||||||
<outlet property="view" destination="zMn-AG-sqS" id="Qma-de-2ek"/>
|
<segue destination="6855" kind="presentation" identifier="lockPasswordSegue" id="9874"/>
|
||||||
|
<segue destination="10580" kind="presentation" identifier="setupSegue" modalTransitionStyle="coverVertical" id="11089"/>
|
||||||
|
<segue destination="11552" kind="show" identifier="loginSearchSegue" id="12959"/>
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="X47-rx-isc" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="45" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="252" y="-124"/>
|
<point key="canvasLocation" x="-374" y="560"/>
|
||||||
|
</scene>
|
||||||
|
<!--Navigation Controller-->
|
||||||
|
<scene sceneID="RvZ-Bc-vCe">
|
||||||
|
<objects>
|
||||||
|
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="oCZ-GQ-aOK" sceneMemberID="viewController">
|
||||||
|
<toolbarItems/>
|
||||||
|
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="8A5-AR-QHS">
|
||||||
|
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<color key="tintColor" red="0.0" green="0.52549019607843139" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<textAttributes key="titleTextAttributes">
|
||||||
|
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</textAttributes>
|
||||||
|
</navigationBar>
|
||||||
|
<nil name="viewControllers"/>
|
||||||
|
<connections>
|
||||||
|
<segue destination="2304" kind="relationship" relationship="rootViewController" id="4562"/>
|
||||||
|
</connections>
|
||||||
|
</navigationController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="Kkn-u3-rq1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="399" y="561"/>
|
||||||
|
</scene>
|
||||||
|
<!--Navigation Controller-->
|
||||||
|
<scene sceneID="1844">
|
||||||
|
<objects>
|
||||||
|
<navigationController definesPresentationContext="YES" id="1845" sceneMemberID="viewController">
|
||||||
|
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="1848">
|
||||||
|
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||||
|
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<textAttributes key="titleTextAttributes">
|
||||||
|
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</textAttributes>
|
||||||
|
</navigationBar>
|
||||||
|
<connections>
|
||||||
|
<segue destination="2087" kind="relationship" relationship="rootViewController" id="2253"/>
|
||||||
|
</connections>
|
||||||
|
</navigationController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="1849" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="1932" y="-270"/>
|
||||||
|
</scene>
|
||||||
|
<!--Add Login-->
|
||||||
|
<scene sceneID="2086">
|
||||||
|
<objects>
|
||||||
|
<tableViewController id="2087" customClass="LoginAddViewController" sceneMemberID="viewController">
|
||||||
|
<tableView key="view" opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" allowsSelection="NO" rowHeight="50" sectionHeaderHeight="22" sectionFooterHeight="22" id="2088">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<color key="sectionIndexBackgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<sections/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="dataSource" destination="2087" id="2089"/>
|
||||||
|
<outlet property="delegate" destination="2087" id="2090"/>
|
||||||
|
</connections>
|
||||||
|
</tableView>
|
||||||
|
<navigationItem key="navigationItem" title="Add Login" id="2252">
|
||||||
|
<barButtonItem key="leftBarButtonItem" title="Cancel" id="3747">
|
||||||
|
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="CancelBarButton_Activated:" destination="2087" id="3751"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
<barButtonItem key="rightBarButtonItem" title="Save" id="3748">
|
||||||
|
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="SaveBarButton_Activated:" destination="2087" id="3752"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
</navigationItem>
|
||||||
|
<connections>
|
||||||
|
<outlet property="CancelBarButton" destination="3747" id="name-outlet-3747"/>
|
||||||
|
<outlet property="NavItem" destination="2252" id="name-outlet-2252"/>
|
||||||
|
<outlet property="SaveBarButton" destination="3748" id="name-outlet-3748"/>
|
||||||
|
<segue destination="4574" kind="show" identifier="passwordGeneratorSegue" id="4805"/>
|
||||||
|
</connections>
|
||||||
|
</tableViewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="2093" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="2632" y="-276"/>
|
||||||
|
</scene>
|
||||||
|
<!--Logins-->
|
||||||
|
<scene sceneID="2303">
|
||||||
|
<objects>
|
||||||
|
<tableViewController id="2304" customClass="LoginListViewController" sceneMemberID="viewController">
|
||||||
|
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="2305">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<prototypes>
|
||||||
|
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" textLabel="3763" detailTextLabel="3764" rowHeight="44" style="IBUITableViewCellStyleSubtitle" id="3761">
|
||||||
|
<rect key="frame" x="0.0" y="22" width="414" height="44"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3761" id="3762">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="3763">
|
||||||
|
<rect key="frame" x="20" y="4" width="35" height="21.5"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="18"/>
|
||||||
|
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
<label opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="left" text="Subtitle" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="3764">
|
||||||
|
<rect key="frame" x="20" y="25.5" width="44" height="14.5"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="12"/>
|
||||||
|
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
</tableViewCellContentView>
|
||||||
|
</tableViewCell>
|
||||||
|
</prototypes>
|
||||||
|
<connections>
|
||||||
|
<outlet property="dataSource" destination="2304" id="2306"/>
|
||||||
|
<outlet property="delegate" destination="2304" id="2307"/>
|
||||||
|
</connections>
|
||||||
|
</tableView>
|
||||||
|
<toolbarItems/>
|
||||||
|
<navigationItem key="navigationItem" title="Logins" id="3734">
|
||||||
|
<barButtonItem key="leftBarButtonItem" title="Cancel" id="3735">
|
||||||
|
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="CancelBarButton_Activated:" destination="2304" id="3750"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
<rightBarButtonItems>
|
||||||
|
<barButtonItem systemItem="add" id="3736">
|
||||||
|
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="AddBarButton_Activated:" destination="2304" id="3749"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
<barButtonItem systemItem="search" id="13195">
|
||||||
|
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="SearchBarButton_Activated:" destination="2304" id="13400"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
</rightBarButtonItems>
|
||||||
|
</navigationItem>
|
||||||
|
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="AddBarButton" destination="3736" id="name-outlet-3736"/>
|
||||||
|
<outlet property="CancelBarButton" destination="3735" id="name-outlet-3735"/>
|
||||||
|
<outlet property="NavItem" destination="3734" id="name-outlet-3734"/>
|
||||||
|
<segue destination="1845" kind="presentation" identifier="loginAddSegue" modalPresentationStyle="fullScreen" modalTransitionStyle="coverVertical" id="3731"/>
|
||||||
|
<segue destination="11552" kind="show" identifier="loginSearchFromListSegue" id="12574"/>
|
||||||
|
</connections>
|
||||||
|
</tableViewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="2310" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="1157" y="566"/>
|
||||||
|
</scene>
|
||||||
|
<!--Navigation Controller-->
|
||||||
|
<scene sceneID="4573">
|
||||||
|
<objects>
|
||||||
|
<navigationController definesPresentationContext="YES" id="4574" sceneMemberID="viewController">
|
||||||
|
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="4577">
|
||||||
|
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||||
|
<color key="tintColor" red="0.0" green="0.52549019607843139" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<textAttributes key="titleTextAttributes">
|
||||||
|
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</textAttributes>
|
||||||
|
</navigationBar>
|
||||||
|
<connections>
|
||||||
|
<segue destination="4576" kind="relationship" relationship="rootViewController" id="4575"/>
|
||||||
|
</connections>
|
||||||
|
</navigationController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="4578" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="3369" y="-276"/>
|
||||||
|
</scene>
|
||||||
|
<!--Generate Password-->
|
||||||
|
<scene sceneID="4579">
|
||||||
|
<objects>
|
||||||
|
<viewController id="4576" customClass="PasswordGeneratorViewController" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="4571"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="4572"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="4930">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<containerView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4933">
|
||||||
|
<rect key="frame" x="0.0" y="160.5" width="414" height="575.5"/>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<connections>
|
||||||
|
<segue destination="4912" kind="embed" id="6480"/>
|
||||||
|
</connections>
|
||||||
|
</containerView>
|
||||||
|
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Label" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="4940">
|
||||||
|
<rect key="frame" x="15" y="105" width="384" height="20.5"/>
|
||||||
|
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
|
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="4933" secondAttribute="trailing" id="6484"/>
|
||||||
|
<constraint firstItem="4933" firstAttribute="top" secondItem="4940" secondAttribute="bottom" constant="35" id="6485"/>
|
||||||
|
<constraint firstItem="4933" firstAttribute="leading" secondItem="4930" secondAttribute="leading" id="6486"/>
|
||||||
|
<constraint firstItem="4940" firstAttribute="leading" secondItem="4930" secondAttribute="leading" constant="15" id="6487"/>
|
||||||
|
<constraint firstItem="4940" firstAttribute="top" secondItem="4571" secondAttribute="bottom" constant="35" id="6488"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="4940" secondAttribute="trailing" constant="15" id="6489"/>
|
||||||
|
<constraint firstItem="4572" firstAttribute="top" secondItem="4933" secondAttribute="bottom" id="6490"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
|
<navigationItem key="navigationItem" title="Generate Password" id="4580">
|
||||||
|
<barButtonItem key="leftBarButtonItem" title="Cancel" id="4807">
|
||||||
|
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="CancelBarButton_Activated:" destination="4576" id="4887"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
<barButtonItem key="rightBarButtonItem" title="Select" id="4808">
|
||||||
|
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="SelectBarButton_Activated:" destination="4576" id="4810"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
</navigationItem>
|
||||||
|
<connections>
|
||||||
|
<outlet property="BaseView" destination="4930" id="name-outlet-4930"/>
|
||||||
|
<outlet property="CancelBarButton" destination="4807" id="name-outlet-4807"/>
|
||||||
|
<outlet property="NavItem" destination="4580" id="name-outlet-4580"/>
|
||||||
|
<outlet property="OptionsContainer" destination="4933" id="name-outlet-4933"/>
|
||||||
|
<outlet property="PasswordLabel" destination="4940" id="name-outlet-4940"/>
|
||||||
|
<outlet property="SelectBarButton" destination="4808" id="name-outlet-4808"/>
|
||||||
|
</connections>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="4582" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="4045" y="-272"/>
|
||||||
|
</scene>
|
||||||
|
<!--Table View Controller-->
|
||||||
|
<scene sceneID="4911">
|
||||||
|
<objects>
|
||||||
|
<tableViewController id="4912" sceneMemberID="viewController">
|
||||||
|
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="4913">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="414" height="575.5"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="dataSource" destination="4912" id="4914"/>
|
||||||
|
<outlet property="delegate" destination="4912" id="4915"/>
|
||||||
|
</connections>
|
||||||
|
</tableView>
|
||||||
|
</tableViewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="4918" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="4708" y="-194"/>
|
||||||
|
</scene>
|
||||||
|
<!--Navigation Controller-->
|
||||||
|
<!--Verify Fingerprint-->
|
||||||
|
<!--Verify PIN-->
|
||||||
|
<!--Navigation Controller-->
|
||||||
|
<!--Navigation Controller-->
|
||||||
|
<scene sceneID="6854">
|
||||||
|
<objects>
|
||||||
|
<navigationController definesPresentationContext="YES" id="6855" sceneMemberID="viewController">
|
||||||
|
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="6857">
|
||||||
|
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||||
|
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<textAttributes key="titleTextAttributes">
|
||||||
|
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</textAttributes>
|
||||||
|
</navigationBar>
|
||||||
|
<connections>
|
||||||
|
<segue destination="7413" kind="relationship" relationship="rootViewController" id="8266"/>
|
||||||
|
</connections>
|
||||||
|
</navigationController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="6858" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="390" y="1407"/>
|
||||||
|
</scene>
|
||||||
|
<!--Verify Master Password-->
|
||||||
|
<scene sceneID="7412">
|
||||||
|
<objects>
|
||||||
|
<tableViewController id="7413" customClass="LockPasswordViewController" sceneMemberID="viewController">
|
||||||
|
<tableView key="view" opaque="NO" clipsSubviews="YES" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="7414">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="dataSource" destination="7413" id="7415"/>
|
||||||
|
<outlet property="delegate" destination="7413" id="7416"/>
|
||||||
|
</connections>
|
||||||
|
</tableView>
|
||||||
|
<navigationItem key="navigationItem" title="Verify Master Password" id="8265">
|
||||||
|
<barButtonItem key="leftBarButtonItem" title="Cancel" id="8268">
|
||||||
|
<connections>
|
||||||
|
<action selector="CancelButton_Activated:" destination="7413" id="8287"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
<barButtonItem key="rightBarButtonItem" title="Submit" id="8269">
|
||||||
|
<connections>
|
||||||
|
<action selector="SubmitButton_Activated:" destination="7413" id="8288"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
</navigationItem>
|
||||||
|
<connections>
|
||||||
|
<outlet property="CancelButton" destination="8268" id="name-outlet-8268"/>
|
||||||
|
<outlet property="MainTableView" destination="7414" id="name-outlet-7414"/>
|
||||||
|
<outlet property="NavItem" destination="8265" id="name-outlet-8265"/>
|
||||||
|
<outlet property="SubmitButton" destination="8269" id="name-outlet-8269"/>
|
||||||
|
</connections>
|
||||||
|
</tableViewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="7419" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="955" y="1407"/>
|
||||||
|
</scene>
|
||||||
|
<!--Setup View Controller-->
|
||||||
|
<scene sceneID="10573">
|
||||||
|
<objects>
|
||||||
|
<viewController id="10570" customClass="SetupViewController" sceneMemberID="viewController">
|
||||||
|
<layoutGuides>
|
||||||
|
<viewControllerLayoutGuide type="top" id="10565"/>
|
||||||
|
<viewControllerLayoutGuide type="bottom" id="10566"/>
|
||||||
|
</layoutGuides>
|
||||||
|
<view key="view" contentMode="scaleToFill" id="10575">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" text="Extension Activated!" textAlignment="center" lineBreakMode="tailTruncation" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="11092">
|
||||||
|
<rect key="frame" x="15" y="100" width="384" height="20.5"/>
|
||||||
|
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
|
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" misplaced="YES" textAlignment="center" lineBreakMode="wordWrap" numberOfLines="0" minimumFontSize="10" translatesAutoresizingMaskIntoConstraints="NO" id="11093">
|
||||||
|
<rect key="frame" x="15" y="134.5" width="570" height="41"/>
|
||||||
|
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||||
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
|
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||||
|
<nil key="highlightedColor"/>
|
||||||
|
</label>
|
||||||
|
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" misplaced="YES" image="check.png" translatesAutoresizingMaskIntoConstraints="NO" id="11094">
|
||||||
|
<rect key="frame" x="255" y="205.5" width="90" height="90"/>
|
||||||
|
</imageView>
|
||||||
|
</subviews>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="11092" firstAttribute="leading" secondItem="10575" secondAttribute="leading" constant="15" id="11114"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="11092" secondAttribute="trailing" constant="15" id="11115"/>
|
||||||
|
<constraint firstItem="11092" firstAttribute="top" secondItem="10565" secondAttribute="bottom" constant="30" id="11116"/>
|
||||||
|
<constraint firstItem="11093" firstAttribute="leading" secondItem="10575" secondAttribute="leading" constant="15" id="11119"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="11093" secondAttribute="trailing" constant="15" id="11120"/>
|
||||||
|
<constraint firstItem="11093" firstAttribute="top" secondItem="11092" secondAttribute="bottom" constant="20" id="11121"/>
|
||||||
|
<constraint firstItem="11094" firstAttribute="centerX" secondItem="10575" secondAttribute="centerX" id="11122"/>
|
||||||
|
<constraint firstItem="11094" firstAttribute="top" secondItem="11093" secondAttribute="bottom" constant="30" id="11123"/>
|
||||||
|
</constraints>
|
||||||
|
</view>
|
||||||
|
<navigationItem key="navigationItem" id="10574">
|
||||||
|
<barButtonItem key="leftBarButtonItem" title="Back" id="11091">
|
||||||
|
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="BackButton_Activated:" destination="10570" id="11124"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
</navigationItem>
|
||||||
|
<connections>
|
||||||
|
<outlet property="ActivatedLabel" destination="11092" id="name-outlet-11092"/>
|
||||||
|
<outlet property="BackButton" destination="11091" id="name-outlet-11091"/>
|
||||||
|
<outlet property="DescriptionLabel" destination="11093" id="name-outlet-11093"/>
|
||||||
|
<outlet property="IconImage" destination="11094" id="name-outlet-11094"/>
|
||||||
|
<outlet property="NavItem" destination="10574" id="name-outlet-10574"/>
|
||||||
|
</connections>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="10576" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="1129" y="-264"/>
|
||||||
|
</scene>
|
||||||
|
<!--Navigation Controller-->
|
||||||
|
<scene sceneID="10579">
|
||||||
|
<objects>
|
||||||
|
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="10580" sceneMemberID="viewController">
|
||||||
|
<toolbarItems/>
|
||||||
|
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="10583">
|
||||||
|
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||||
|
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<textAttributes key="titleTextAttributes">
|
||||||
|
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</textAttributes>
|
||||||
|
</navigationBar>
|
||||||
|
<nil name="viewControllers"/>
|
||||||
|
<connections>
|
||||||
|
<segue destination="10570" kind="relationship" relationship="rootViewController" id="10939"/>
|
||||||
|
</connections>
|
||||||
|
</navigationController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="10584" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="362" y="-267"/>
|
||||||
|
</scene>
|
||||||
|
<!--Search Logins-->
|
||||||
|
<scene sceneID="11542">
|
||||||
|
<objects>
|
||||||
|
<tableViewController id="11543" customClass="LoginSearchViewController" sceneMemberID="viewController">
|
||||||
|
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" id="11545">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
<searchBar key="tableHeaderView" contentMode="redraw" id="13084">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="414" height="44"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||||
|
<textInputTraits key="textInputTraits"/>
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="11543" id="13085"/>
|
||||||
|
</connections>
|
||||||
|
</searchBar>
|
||||||
|
<prototypes>
|
||||||
|
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" id="11548">
|
||||||
|
<rect key="frame" x="0.0" y="72" width="414" height="44"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="11548" id="11549">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="414" height="43.5"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
</tableViewCellContentView>
|
||||||
|
</tableViewCell>
|
||||||
|
</prototypes>
|
||||||
|
<connections>
|
||||||
|
<outlet property="dataSource" destination="11543" id="11546"/>
|
||||||
|
<outlet property="delegate" destination="11543" id="11547"/>
|
||||||
|
</connections>
|
||||||
|
</tableView>
|
||||||
|
<navigationItem key="navigationItem" title="Search Logins" id="11544">
|
||||||
|
<barButtonItem key="leftBarButtonItem" title="Cancel" id="11950">
|
||||||
|
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="CancelBarButton_Activated:" destination="11543" id="12044"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
<barButtonItem key="rightBarButtonItem" systemItem="add" id="11951">
|
||||||
|
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="AddBarButton_Activated:" destination="11543" id="12045"/>
|
||||||
|
</connections>
|
||||||
|
</barButtonItem>
|
||||||
|
</navigationItem>
|
||||||
|
<connections>
|
||||||
|
<outlet property="CancelBarButton" destination="11950" id="name-outlet-11950"/>
|
||||||
|
<outlet property="NavItem" destination="11544" id="name-outlet-11544"/>
|
||||||
|
<outlet property="SearchBar" destination="13084" id="name-outlet-13084"/>
|
||||||
|
<segue destination="1845" kind="show" identifier="loginAddFromSearchSegue" id="12738"/>
|
||||||
|
</connections>
|
||||||
|
</tableViewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="11550" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="2513" y="907"/>
|
||||||
|
</scene>
|
||||||
|
<!--Navigation Controller-->
|
||||||
|
<scene sceneID="11551">
|
||||||
|
<objects>
|
||||||
|
<navigationController id="11552" sceneMemberID="viewController">
|
||||||
|
<navigationBar key="navigationBar" contentMode="scaleToFill" translucent="NO" id="11554">
|
||||||
|
<rect key="frame" x="0.0" y="20" width="414" height="50"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||||
|
<color key="barTintColor" red="0.23529411764705882" green="0.55294117647058827" blue="0.73725490196078436" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
<textAttributes key="titleTextAttributes">
|
||||||
|
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</textAttributes>
|
||||||
|
</navigationBar>
|
||||||
|
<connections>
|
||||||
|
<segue destination="11543" kind="relationship" relationship="rootViewController" id="11553"/>
|
||||||
|
</connections>
|
||||||
|
</navigationController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="11555" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="1920" y="908"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
<resources>
|
||||||
<simulatedStatusBarMetrics key="statusBar"/>
|
<image name="check.png" width="90" height="90"/>
|
||||||
<simulatedOrientationMetrics key="orientation"/>
|
<image name="logo.png" width="282" height="44"/>
|
||||||
<simulatedScreenMetrics key="destination" type="retina4"/>
|
</resources>
|
||||||
</simulatedMetricsContainer>
|
</document>
|
||||||
</document>
|
|
||||||
28
src/iOS.Autofill/PasswordGeneratorViewController.cs
Normal file
28
src/iOS.Autofill/PasswordGeneratorViewController.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
public partial class PasswordGeneratorViewController : Core.Controllers.PasswordGeneratorViewController
|
||||||
|
{
|
||||||
|
public PasswordGeneratorViewController(IntPtr handle)
|
||||||
|
: base(handle)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public LoginAddViewController Parent { get; set; }
|
||||||
|
public override UINavigationItem BaseNavItem => NavItem;
|
||||||
|
public override UIBarButtonItem BaseCancelButton => CancelBarButton;
|
||||||
|
public override UIBarButtonItem BaseSelectBarButton => SelectBarButton;
|
||||||
|
public override UILabel BasePasswordLabel => PasswordLabel;
|
||||||
|
|
||||||
|
partial void SelectBarButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
DismissViewController(true, () => Parent.PasswordCell.TextField.Text = PasswordLabel.Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void CancelBarButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
DismissViewController(true, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
src/iOS.Autofill/PasswordGeneratorViewController.designer.cs
generated
Normal file
82
src/iOS.Autofill/PasswordGeneratorViewController.designer.cs
generated
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
// WARNING
|
||||||
|
//
|
||||||
|
// This file has been generated automatically by Visual Studio from the outlets and
|
||||||
|
// actions declared in your storyboard file.
|
||||||
|
// Manual changes to this file will not be maintained.
|
||||||
|
//
|
||||||
|
using Foundation;
|
||||||
|
using System;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
[Register ("PasswordGeneratorViewController")]
|
||||||
|
partial class PasswordGeneratorViewController
|
||||||
|
{
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIView BaseView { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIBarButtonItem CancelBarButton { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UINavigationItem NavItem { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIView OptionsContainer { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UILabel PasswordLabel { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIBarButtonItem SelectBarButton { get; set; }
|
||||||
|
|
||||||
|
[Action ("CancelBarButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void CancelBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
[Action ("SelectBarButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void SelectBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
void ReleaseDesignerOutlets ()
|
||||||
|
{
|
||||||
|
if (BaseView != null) {
|
||||||
|
BaseView.Dispose ();
|
||||||
|
BaseView = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CancelBarButton != null) {
|
||||||
|
CancelBarButton.Dispose ();
|
||||||
|
CancelBarButton = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NavItem != null) {
|
||||||
|
NavItem.Dispose ();
|
||||||
|
NavItem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OptionsContainer != null) {
|
||||||
|
OptionsContainer.Dispose ();
|
||||||
|
OptionsContainer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PasswordLabel != null) {
|
||||||
|
PasswordLabel.Dispose ();
|
||||||
|
PasswordLabel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SelectBarButton != null) {
|
||||||
|
SelectBarButton.Dispose ();
|
||||||
|
SelectBarButton = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/iOS.Autofill/SetupViewController.cs
Normal file
46
src/iOS.Autofill/SetupViewController.cs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using UIKit;
|
||||||
|
using Bit.iOS.Core.Controllers;
|
||||||
|
using Bit.App.Resources;
|
||||||
|
using Bit.iOS.Core.Utilities;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
public partial class SetupViewController : ExtendedUIViewController
|
||||||
|
{
|
||||||
|
public SetupViewController(IntPtr handle) : base(handle)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public CredentialProviderViewController CPViewController { get; set; }
|
||||||
|
|
||||||
|
public override void ViewWillAppear(bool animated)
|
||||||
|
{
|
||||||
|
UINavigationBar.Appearance.ShadowImage = new UIImage();
|
||||||
|
UINavigationBar.Appearance.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
|
||||||
|
base.ViewWillAppear(animated);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void ViewDidLoad()
|
||||||
|
{
|
||||||
|
View.BackgroundColor = new UIColor(red: 0.94f, green: 0.94f, blue: 0.96f, alpha: 1.0f);
|
||||||
|
var descriptor = UIFontDescriptor.PreferredBody;
|
||||||
|
DescriptionLabel.Text = $@"{AppResources.AutofillSetup}
|
||||||
|
|
||||||
|
{AppResources.AutofillSetup2}";
|
||||||
|
DescriptionLabel.Font = UIFont.FromDescriptor(descriptor, descriptor.PointSize);
|
||||||
|
DescriptionLabel.TextColor = new UIColor(red: 0.47f, green: 0.47f, blue: 0.47f, alpha: 1.0f);
|
||||||
|
|
||||||
|
ActivatedLabel.Text = AppResources.AutofillActivated;
|
||||||
|
ActivatedLabel.Font = UIFont.FromDescriptor(descriptor, descriptor.PointSize * 1.3f);
|
||||||
|
|
||||||
|
BackButton.Title = AppResources.Back;
|
||||||
|
base.ViewDidLoad();
|
||||||
|
var task = ASHelpers.ReplaceAllIdentities();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void BackButton_Activated(UIBarButtonItem sender)
|
||||||
|
{
|
||||||
|
CPViewController.CompleteRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
69
src/iOS.Autofill/SetupViewController.designer.cs
generated
Normal file
69
src/iOS.Autofill/SetupViewController.designer.cs
generated
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// WARNING
|
||||||
|
//
|
||||||
|
// This file has been generated automatically by Visual Studio from the outlets and
|
||||||
|
// actions declared in your storyboard file.
|
||||||
|
// Manual changes to this file will not be maintained.
|
||||||
|
//
|
||||||
|
using Foundation;
|
||||||
|
using System;
|
||||||
|
using System.CodeDom.Compiler;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Autofill
|
||||||
|
{
|
||||||
|
[Register ("SetupViewController")]
|
||||||
|
partial class SetupViewController
|
||||||
|
{
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UILabel ActivatedLabel { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIBarButtonItem BackButton { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UILabel DescriptionLabel { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UIImageView IconImage { get; set; }
|
||||||
|
|
||||||
|
[Outlet]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
UIKit.UINavigationItem NavItem { get; set; }
|
||||||
|
|
||||||
|
[Action ("BackButton_Activated:")]
|
||||||
|
[GeneratedCode ("iOS Designer", "1.0")]
|
||||||
|
partial void BackButton_Activated (UIKit.UIBarButtonItem sender);
|
||||||
|
|
||||||
|
void ReleaseDesignerOutlets ()
|
||||||
|
{
|
||||||
|
if (ActivatedLabel != null) {
|
||||||
|
ActivatedLabel.Dispose ();
|
||||||
|
ActivatedLabel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BackButton != null) {
|
||||||
|
BackButton.Dispose ();
|
||||||
|
BackButton = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DescriptionLabel != null) {
|
||||||
|
DescriptionLabel.Dispose ();
|
||||||
|
DescriptionLabel = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IconImage != null) {
|
||||||
|
IconImage.Dispose ();
|
||||||
|
IconImage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NavItem != null) {
|
||||||
|
NavItem.Dispose ();
|
||||||
|
NavItem = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System.Linq;
|
||||||
using System.Linq;
|
using System.Threading.Tasks;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
using Bit.iOS.Core.Utilities;
|
using Bit.iOS.Core.Utilities;
|
||||||
using Bit.iOS.Core.Views;
|
using Bit.iOS.Core.Views;
|
||||||
using Foundation;
|
using Foundation;
|
||||||
@@ -10,10 +12,9 @@ namespace Bit.iOS.Autofill.Utilities
|
|||||||
{
|
{
|
||||||
public static class AutofillHelpers
|
public static class AutofillHelpers
|
||||||
{
|
{
|
||||||
/*
|
public async static Task TableRowSelectedAsync(UITableView tableView, NSIndexPath indexPath,
|
||||||
public static void TableRowSelected(UITableView tableView, NSIndexPath indexPath,
|
|
||||||
ExtensionTableSource tableSource, CredentialProviderViewController cpViewController,
|
ExtensionTableSource tableSource, CredentialProviderViewController cpViewController,
|
||||||
UITableViewController controller, ISettings settings, string loginAddSegue)
|
UITableViewController controller, string loginAddSegue)
|
||||||
{
|
{
|
||||||
tableView.DeselectRow(indexPath, true);
|
tableView.DeselectRow(indexPath, true);
|
||||||
tableView.EndEditing(true);
|
tableView.EndEditing(true);
|
||||||
@@ -23,7 +24,6 @@ namespace Bit.iOS.Autofill.Utilities
|
|||||||
controller.PerformSegue(loginAddSegue, tableSource);
|
controller.PerformSegue(loginAddSegue, tableSource);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var item = tableSource.Items.ElementAt(indexPath.Row);
|
var item = tableSource.Items.ElementAt(indexPath.Row);
|
||||||
if(item == null)
|
if(item == null)
|
||||||
{
|
{
|
||||||
@@ -34,15 +34,23 @@ namespace Bit.iOS.Autofill.Utilities
|
|||||||
if(!string.IsNullOrWhiteSpace(item.Username) && !string.IsNullOrWhiteSpace(item.Password))
|
if(!string.IsNullOrWhiteSpace(item.Username) && !string.IsNullOrWhiteSpace(item.Password))
|
||||||
{
|
{
|
||||||
string totp = null;
|
string totp = null;
|
||||||
if(!settings.GetValueOrDefault(App.Constants.SettingDisableTotpCopy, false))
|
var storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||||
|
var disableTotpCopy = await storageService.GetAsync<bool?>(Bit.Core.Constants.DisableAutoTotpCopyKey);
|
||||||
|
if(!disableTotpCopy.GetValueOrDefault(false))
|
||||||
{
|
{
|
||||||
totp = tableSource.GetTotp(item);
|
var userService = ServiceContainer.Resolve<IUserService>("userService");
|
||||||
|
var canAccessPremiumAsync = await userService.CanAccessPremiumAsync();
|
||||||
|
if(!string.IsNullOrWhiteSpace(item.Totp) &&
|
||||||
|
(canAccessPremiumAsync || item.CipherView.OrganizationUseTotp))
|
||||||
|
{
|
||||||
|
var totpService = ServiceContainer.Resolve<ITotpService>("totpService");
|
||||||
|
totp = await totpService.GetCodeAsync(item.Totp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cpViewController.CompleteRequest(item.Username, item.Password, totp);
|
cpViewController.CompleteRequest(item.Username, item.Password, totp);
|
||||||
}
|
}
|
||||||
else if(!string.IsNullOrWhiteSpace(item.Username) || !string.IsNullOrWhiteSpace(item.Password) ||
|
else if(!string.IsNullOrWhiteSpace(item.Username) || !string.IsNullOrWhiteSpace(item.Password) ||
|
||||||
!string.IsNullOrWhiteSpace(item.Totp.Value))
|
!string.IsNullOrWhiteSpace(item.Totp))
|
||||||
{
|
{
|
||||||
var sheet = Dialogs.CreateActionSheet(item.Name, controller);
|
var sheet = Dialogs.CreateActionSheet(item.Name, controller);
|
||||||
if(!string.IsNullOrWhiteSpace(item.Username))
|
if(!string.IsNullOrWhiteSpace(item.Username))
|
||||||
@@ -65,7 +73,8 @@ namespace Bit.iOS.Autofill.Utilities
|
|||||||
{
|
{
|
||||||
UIPasteboard clipboard = UIPasteboard.General;
|
UIPasteboard clipboard = UIPasteboard.General;
|
||||||
clipboard.String = item.Password;
|
clipboard.String = item.Password;
|
||||||
var alert = Dialogs.CreateMessageAlert(AppResources.CopiedPassword);
|
var alert = Dialogs.CreateMessageAlert(
|
||||||
|
string.Format(AppResources.ValueHasBeenCopied, AppResources.Password));
|
||||||
controller.PresentViewController(alert, true, () =>
|
controller.PresentViewController(alert, true, () =>
|
||||||
{
|
{
|
||||||
controller.DismissViewController(true, null);
|
controller.DismissViewController(true, null);
|
||||||
@@ -73,26 +82,25 @@ namespace Bit.iOS.Autofill.Utilities
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!string.IsNullOrWhiteSpace(item.Totp.Value))
|
if(!string.IsNullOrWhiteSpace(item.Totp))
|
||||||
{
|
{
|
||||||
sheet.AddAction(UIAlertAction.Create(AppResources.CopyTotp, UIAlertActionStyle.Default, a =>
|
sheet.AddAction(UIAlertAction.Create(AppResources.CopyTotp, UIAlertActionStyle.Default, async a =>
|
||||||
{
|
{
|
||||||
var totp = tableSource.GetTotp(item);
|
var totp = await tableSource.GetTotpAsync(item);
|
||||||
if(string.IsNullOrWhiteSpace(totp))
|
if(string.IsNullOrWhiteSpace(totp))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
UIPasteboard clipboard = UIPasteboard.General;
|
UIPasteboard clipboard = UIPasteboard.General;
|
||||||
clipboard.String = totp;
|
clipboard.String = totp;
|
||||||
var alert = Dialogs.CreateMessageAlert(AppResources.CopiedTotp);
|
var alert = Dialogs.CreateMessageAlert(
|
||||||
|
string.Format(AppResources.ValueHasBeenCopied, AppResources.VerificationCodeTotp));
|
||||||
controller.PresentViewController(alert, true, () =>
|
controller.PresentViewController(alert, true, () =>
|
||||||
{
|
{
|
||||||
controller.DismissViewController(true, null);
|
controller.DismissViewController(true, null);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
sheet.AddAction(UIAlertAction.Create(AppResources.Cancel, UIAlertActionStyle.Cancel, null));
|
sheet.AddAction(UIAlertAction.Create(AppResources.Cancel, UIAlertActionStyle.Cancel, null));
|
||||||
controller.PresentViewController(sheet, true, null);
|
controller.PresentViewController(sheet, true, null);
|
||||||
}
|
}
|
||||||
@@ -102,6 +110,5 @@ namespace Bit.iOS.Autofill.Utilities
|
|||||||
controller.PresentViewController(alert, true, null);
|
controller.PresentViewController(alert, true, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,8 +64,36 @@
|
|||||||
<AppExtensionDebugBundleId />
|
<AppExtensionDebugBundleId />
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="CredentialProviderViewController.cs" />
|
||||||
|
<Compile Include="CredentialProviderViewController.designer.cs">
|
||||||
|
<DependentUpon>CredentialProviderViewController.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="LockPasswordViewController.cs" />
|
||||||
|
<Compile Include="LockPasswordViewController.designer.cs">
|
||||||
|
<DependentUpon>LockPasswordViewController.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="LoginAddViewController.cs" />
|
||||||
|
<Compile Include="LoginAddViewController.designer.cs">
|
||||||
|
<DependentUpon>LoginAddViewController.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="LoginListViewController.cs" />
|
||||||
|
<Compile Include="LoginListViewController.designer.cs">
|
||||||
|
<DependentUpon>LoginListViewController.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="LoginSearchViewController.cs" />
|
||||||
|
<Compile Include="LoginSearchViewController.designer.cs">
|
||||||
|
<DependentUpon>LoginSearchViewController.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Main.cs" />
|
<Compile Include="Main.cs" />
|
||||||
<Compile Include="AppDelegate.cs" />
|
<Compile Include="AppDelegate.cs" />
|
||||||
|
<Compile Include="PasswordGeneratorViewController.cs" />
|
||||||
|
<Compile Include="PasswordGeneratorViewController.designer.cs">
|
||||||
|
<DependentUpon>PasswordGeneratorViewController.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="SetupViewController.cs" />
|
||||||
|
<Compile Include="SetupViewController.designer.cs">
|
||||||
|
<DependentUpon>SetupViewController.cs</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Utilities\AutofillHelpers.cs" />
|
<Compile Include="Utilities\AutofillHelpers.cs" />
|
||||||
<None Include="Info.plist" />
|
<None Include="Info.plist" />
|
||||||
<None Include="Entitlements.plist" />
|
<None Include="Entitlements.plist" />
|
||||||
@@ -90,6 +118,10 @@
|
|||||||
<Project>{ee44c6a1-2a85-45fe-8d9b-bf1d5f88809c}</Project>
|
<Project>{ee44c6a1-2a85-45fe-8d9b-bf1d5f88809c}</Project>
|
||||||
<Name>App</Name>
|
<Name>App</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\Core\Core.csproj">
|
||||||
|
<Project>{4b8a8c41-9820-4341-974c-41e65b7f4366}</Project>
|
||||||
|
<Name>Core</Name>
|
||||||
|
</ProjectReference>
|
||||||
<ProjectReference Include="..\iOS.Core\iOS.Core.csproj">
|
<ProjectReference Include="..\iOS.Core\iOS.Core.csproj">
|
||||||
<Project>{e71f3053-056c-4381-9638-048ed73bdff6}</Project>
|
<Project>{e71f3053-056c-4381-9638-048ed73bdff6}</Project>
|
||||||
<Name>iOS.Core</Name>
|
<Name>iOS.Core</Name>
|
||||||
|
|||||||
@@ -5,23 +5,38 @@ using Bit.iOS.Core.Views;
|
|||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
using Bit.iOS.Core.Utilities;
|
using Bit.iOS.Core.Utilities;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using System.Linq;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.iOS.Core.Controllers;
|
using Bit.Core.Utilities;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.Core.Models.Domain;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
|
||||||
namespace Bit.iOS.Core.Controllers
|
namespace Bit.iOS.Core.Controllers
|
||||||
{
|
{
|
||||||
public abstract class LockPasswordViewController : ExtendedUITableViewController
|
public abstract class LockPasswordViewController : ExtendedUITableViewController
|
||||||
{
|
{
|
||||||
//private IAuthService _authService;
|
private ILockService _lockService;
|
||||||
//private ICryptoService _cryptoService;
|
private ICryptoService _cryptoService;
|
||||||
|
private IDeviceActionService _deviceActionService;
|
||||||
|
private IUserService _userService;
|
||||||
|
private IStorageService _storageService;
|
||||||
|
private IStorageService _secureStorageService;
|
||||||
|
private IPlatformUtilsService _platformUtilsService;
|
||||||
|
private Tuple<bool, bool> _pinSet;
|
||||||
|
private bool _hasKey;
|
||||||
|
private bool _pinLock;
|
||||||
|
private bool _fingerprintLock;
|
||||||
|
private int _invalidPinAttempts;
|
||||||
|
|
||||||
public LockPasswordViewController(IntPtr handle) : base(handle)
|
public LockPasswordViewController(IntPtr handle)
|
||||||
|
: base(handle)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public abstract UINavigationItem BaseNavItem { get; }
|
public abstract UINavigationItem BaseNavItem { get; }
|
||||||
public abstract UIBarButtonItem BaseCancelButton { get; }
|
public abstract UIBarButtonItem BaseCancelButton { get; }
|
||||||
public abstract UIBarButtonItem BaseSubmitButton { get; }
|
public abstract UIBarButtonItem BaseSubmitButton { get; }
|
||||||
public abstract Action Success { get; }
|
public abstract Action Success { get; }
|
||||||
|
public abstract Action Cancel { get; }
|
||||||
|
|
||||||
public FormEntryTableViewCell MasterPasswordCell { get; set; } = new FormEntryTableViewCell(
|
public FormEntryTableViewCell MasterPasswordCell { get; set; } = new FormEntryTableViewCell(
|
||||||
AppResources.MasterPassword, useLabelAsPlaceholder: true);
|
AppResources.MasterPassword, useLabelAsPlaceholder: true);
|
||||||
@@ -35,21 +50,32 @@ namespace Bit.iOS.Core.Controllers
|
|||||||
|
|
||||||
public override void ViewDidLoad()
|
public override void ViewDidLoad()
|
||||||
{
|
{
|
||||||
// _authService = Resolver.Resolve<IAuthService>();
|
_lockService = ServiceContainer.Resolve<ILockService>("lockService");
|
||||||
// _cryptoService = Resolver.Resolve<ICryptoService>();
|
_cryptoService = ServiceContainer.Resolve<ICryptoService>("cryptoService");
|
||||||
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
||||||
|
_userService = ServiceContainer.Resolve<IUserService>("userService");
|
||||||
|
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||||
|
_secureStorageService = ServiceContainer.Resolve<IStorageService>("secureStorageService");
|
||||||
|
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
|
||||||
|
|
||||||
BaseNavItem.Title = AppResources.VerifyMasterPassword;
|
_pinSet = _lockService.IsPinLockSetAsync().GetAwaiter().GetResult();
|
||||||
|
_hasKey = _cryptoService.HasKeyAsync().GetAwaiter().GetResult();
|
||||||
|
_pinLock = (_pinSet.Item1 && _hasKey) || _pinSet.Item2;
|
||||||
|
_fingerprintLock = _lockService.IsFingerprintLockSetAsync().GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
BaseNavItem.Title = _pinLock ? AppResources.VerifyPIN : AppResources.VerifyMasterPassword;
|
||||||
BaseCancelButton.Title = AppResources.Cancel;
|
BaseCancelButton.Title = AppResources.Cancel;
|
||||||
BaseSubmitButton.Title = AppResources.Submit;
|
BaseSubmitButton.Title = AppResources.Submit;
|
||||||
View.BackgroundColor = new UIColor(red: 0.94f, green: 0.94f, blue: 0.96f, alpha: 1.0f);
|
View.BackgroundColor = new UIColor(red: 0.94f, green: 0.94f, blue: 0.96f, alpha: 1.0f);
|
||||||
|
|
||||||
var descriptor = UIFontDescriptor.PreferredBody;
|
var descriptor = UIFontDescriptor.PreferredBody;
|
||||||
|
|
||||||
|
MasterPasswordCell.TextField.Placeholder = _pinLock ? AppResources.PIN : AppResources.MasterPassword;
|
||||||
MasterPasswordCell.TextField.SecureTextEntry = true;
|
MasterPasswordCell.TextField.SecureTextEntry = true;
|
||||||
MasterPasswordCell.TextField.ReturnKeyType = UIReturnKeyType.Go;
|
MasterPasswordCell.TextField.ReturnKeyType = UIReturnKeyType.Go;
|
||||||
MasterPasswordCell.TextField.ShouldReturn += (UITextField tf) =>
|
MasterPasswordCell.TextField.ShouldReturn += (UITextField tf) =>
|
||||||
{
|
{
|
||||||
// CheckPassword();
|
CheckPasswordAsync().GetAwaiter().GetResult();
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -59,49 +85,156 @@ namespace Bit.iOS.Core.Controllers
|
|||||||
TableView.AllowsSelection = true;
|
TableView.AllowsSelection = true;
|
||||||
|
|
||||||
base.ViewDidLoad();
|
base.ViewDidLoad();
|
||||||
|
|
||||||
|
if(_fingerprintLock)
|
||||||
|
{
|
||||||
|
var fingerprintButtonText = _deviceActionService.SupportsFaceId() ? AppResources.UseFaceIDToUnlock :
|
||||||
|
AppResources.UseFingerprintToUnlock;
|
||||||
|
// TODO: set button text
|
||||||
|
var tasks = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
await Task.Delay(500);
|
||||||
|
PromptFingerprintAsync().GetAwaiter().GetResult();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ViewDidAppear(bool animated)
|
public override void ViewDidAppear(bool animated)
|
||||||
{
|
{
|
||||||
base.ViewDidAppear(animated);
|
base.ViewDidAppear(animated);
|
||||||
MasterPasswordCell.TextField.BecomeFirstResponder();
|
if(!_fingerprintLock)
|
||||||
|
{
|
||||||
|
MasterPasswordCell.TextField.BecomeFirstResponder();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// TODO: Try fingerprint again button action
|
||||||
protected void CheckPassword()
|
|
||||||
|
protected async Task CheckPasswordAsync()
|
||||||
{
|
{
|
||||||
if(string.IsNullOrWhiteSpace(MasterPasswordCell.TextField.Text))
|
if(string.IsNullOrWhiteSpace(MasterPasswordCell.TextField.Text))
|
||||||
{
|
{
|
||||||
var alert = Dialogs.CreateAlert(AppResources.AnErrorHasOccurred,
|
var alert = Dialogs.CreateAlert(AppResources.AnErrorHasOccurred,
|
||||||
string.Format(AppResources.ValidationFieldRequired, AppResources.MasterPassword), AppResources.Ok);
|
string.Format(AppResources.ValidationFieldRequired,
|
||||||
|
_pinLock ? AppResources.PIN : AppResources.MasterPassword),
|
||||||
|
AppResources.Ok);
|
||||||
PresentViewController(alert, true, null);
|
PresentViewController(alert, true, null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var key = _cryptoService.MakeKeyFromPassword(MasterPasswordCell.TextField.Text, _authService.Email,
|
var email = await _userService.GetEmailAsync();
|
||||||
_authService.Kdf, _authService.KdfIterations);
|
var kdf = await _userService.GetKdfAsync();
|
||||||
if(key.Key.SequenceEqual(_cryptoService.Key.Key))
|
var kdfIterations = await _userService.GetKdfIterationsAsync();
|
||||||
|
var inputtedValue = MasterPasswordCell.TextField.Text;
|
||||||
|
|
||||||
|
if(_pinLock)
|
||||||
{
|
{
|
||||||
_appSettingsService.Locked = false;
|
var failed = true;
|
||||||
MasterPasswordCell.TextField.ResignFirstResponder();
|
try
|
||||||
Success();
|
{
|
||||||
|
if(_pinSet.Item1)
|
||||||
|
{
|
||||||
|
var protectedPin = await _storageService.GetAsync<string>(Bit.Core.Constants.ProtectedPin);
|
||||||
|
var decPin = await _cryptoService.DecryptToUtf8Async(new CipherString(protectedPin));
|
||||||
|
failed = decPin != inputtedValue;
|
||||||
|
_lockService.PinLocked = failed;
|
||||||
|
if(!failed)
|
||||||
|
{
|
||||||
|
DoContinue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var key2 = await _cryptoService.MakeKeyFromPinAsync(inputtedValue, email,
|
||||||
|
kdf.GetValueOrDefault(KdfType.PBKDF2_SHA256), kdfIterations.GetValueOrDefault(5000));
|
||||||
|
failed = false;
|
||||||
|
await SetKeyAndContinueAsync(key2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
if(failed)
|
||||||
|
{
|
||||||
|
_invalidPinAttempts++;
|
||||||
|
if(_invalidPinAttempts >= 5)
|
||||||
|
{
|
||||||
|
Cancel?.Invoke();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
InvalidValue();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO: keep track of invalid attempts and logout?
|
var key2 = await _cryptoService.MakeKeyAsync(inputtedValue, email, kdf, kdfIterations);
|
||||||
|
var keyHash = await _cryptoService.HashPasswordAsync(inputtedValue, key2);
|
||||||
|
var storedKeyHash = await _cryptoService.GetKeyHashAsync();
|
||||||
|
if(storedKeyHash == null)
|
||||||
|
{
|
||||||
|
var oldKey = await _secureStorageService.GetAsync<string>("oldKey");
|
||||||
|
if(key2.KeyB64 == oldKey)
|
||||||
|
{
|
||||||
|
await _secureStorageService.RemoveAsync("oldKey");
|
||||||
|
await _cryptoService.SetKeyHashAsync(keyHash);
|
||||||
|
storedKeyHash = keyHash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(storedKeyHash != null && keyHash != null && storedKeyHash == keyHash)
|
||||||
|
{
|
||||||
|
await SetKeyAndContinueAsync(key2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
InvalidValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var alert = Dialogs.CreateAlert(AppResources.AnErrorHasOccurred,
|
private async Task SetKeyAndContinueAsync(SymmetricCryptoKey key)
|
||||||
string.Format(null, AppResources.InvalidMasterPassword), AppResources.Ok, (a) =>
|
{
|
||||||
|
if(!_hasKey)
|
||||||
|
{
|
||||||
|
await _cryptoService.SetKeyAsync(key);
|
||||||
|
}
|
||||||
|
DoContinue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoContinue()
|
||||||
|
{
|
||||||
|
MasterPasswordCell.TextField.ResignFirstResponder();
|
||||||
|
Success();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PromptFingerprintAsync()
|
||||||
|
{
|
||||||
|
if(!_fingerprintLock)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var success = await _platformUtilsService.AuthenticateFingerprintAsync(null,
|
||||||
|
_pinLock ? AppResources.PIN : AppResources.MasterPassword,
|
||||||
|
() => MasterPasswordCell.TextField.BecomeFirstResponder());
|
||||||
|
_lockService.FingerprintLocked = !success;
|
||||||
|
if(success)
|
||||||
|
{
|
||||||
|
DoContinue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InvalidValue()
|
||||||
|
{
|
||||||
|
var alert = Dialogs.CreateAlert(AppResources.AnErrorHasOccurred,
|
||||||
|
string.Format(null, _pinLock ? AppResources.PIN : AppResources.InvalidMasterPassword),
|
||||||
|
AppResources.Ok, (a) =>
|
||||||
{
|
{
|
||||||
|
|
||||||
MasterPasswordCell.TextField.Text = string.Empty;
|
MasterPasswordCell.TextField.Text = string.Empty;
|
||||||
MasterPasswordCell.TextField.BecomeFirstResponder();
|
MasterPasswordCell.TextField.BecomeFirstResponder();
|
||||||
});
|
});
|
||||||
|
PresentViewController(alert, true, null);
|
||||||
PresentViewController(alert, true, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
public class TableSource : UITableViewSource
|
public class TableSource : UITableViewSource
|
||||||
{
|
{
|
||||||
@@ -121,7 +254,6 @@ namespace Bit.iOS.Core.Controllers
|
|||||||
return _controller.MasterPasswordCell;
|
return _controller.MasterPasswordCell;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new UITableViewCell();
|
return new UITableViewCell();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +273,6 @@ namespace Bit.iOS.Core.Controllers
|
|||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,15 +290,12 @@ namespace Bit.iOS.Core.Controllers
|
|||||||
{
|
{
|
||||||
tableView.DeselectRow(indexPath, true);
|
tableView.DeselectRow(indexPath, true);
|
||||||
tableView.EndEditing(true);
|
tableView.EndEditing(true);
|
||||||
|
|
||||||
var cell = tableView.CellAt(indexPath);
|
var cell = tableView.CellAt(indexPath);
|
||||||
if(cell == null)
|
if(cell == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(cell is ISelectable selectableCell)
|
||||||
var selectableCell = cell as ISelectable;
|
|
||||||
if(selectableCell != null)
|
|
||||||
{
|
{
|
||||||
selectableCell.Select();
|
selectableCell.Select();
|
||||||
}
|
}
|
||||||
|
|||||||
109
src/iOS.Core/Utilities/iOSCoreHelpers.cs
Normal file
109
src/iOS.Core/Utilities/iOSCoreHelpers.cs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Bit.App.Abstractions;
|
||||||
|
using Bit.App.Services;
|
||||||
|
using Bit.App.Utilities;
|
||||||
|
using Bit.Core.Abstractions;
|
||||||
|
using Bit.Core.Services;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
|
using Bit.iOS.Core.Services;
|
||||||
|
using Foundation;
|
||||||
|
using HockeyApp.iOS;
|
||||||
|
using UIKit;
|
||||||
|
|
||||||
|
namespace Bit.iOS.Core.Utilities
|
||||||
|
{
|
||||||
|
public static class iOSCoreHelpers
|
||||||
|
{
|
||||||
|
public static string AppId = "com.8bit.bitwarden";
|
||||||
|
public static string AppGroupId = "group.com.8bit.bitwarden";
|
||||||
|
public static string AccessGroup = "LTZ2PFU5D6.com.8bit.bitwarden";
|
||||||
|
|
||||||
|
public static void RegisterHockeyApp()
|
||||||
|
{
|
||||||
|
var crashManagerDelegate = new HockeyAppCrashManagerDelegate(
|
||||||
|
ServiceContainer.Resolve<IAppIdService>("appIdService"),
|
||||||
|
ServiceContainer.Resolve<IUserService>("userService"));
|
||||||
|
var manager = BITHockeyManager.SharedHockeyManager;
|
||||||
|
manager.Configure("51f96ae568ba45f699a18ad9f63046c3", crashManagerDelegate);
|
||||||
|
manager.CrashManager.CrashManagerStatus = BITCrashManagerStatus.AutoSend;
|
||||||
|
manager.StartManager();
|
||||||
|
manager.Authenticator.AuthenticateInstallation();
|
||||||
|
manager.DisableMetricsManager = manager.DisableFeedbackManager = manager.DisableUpdateManager = true;
|
||||||
|
var task = crashManagerDelegate.InitAsync(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RegisterLocalServices()
|
||||||
|
{
|
||||||
|
if(ServiceContainer.Resolve<ILogService>("logService", true) == null)
|
||||||
|
{
|
||||||
|
ServiceContainer.Register<ILogService>("logService", new ConsoleLogService());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: This might cause a race condition. Investigate more.
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
FFImageLoading.Forms.Platform.CachedImageRenderer.Init();
|
||||||
|
FFImageLoading.ImageService.Instance.Initialize(new FFImageLoading.Config.Configuration
|
||||||
|
{
|
||||||
|
FadeAnimationEnabled = false,
|
||||||
|
FadeAnimationForCachedImages = false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var preferencesStorage = new PreferencesStorageService(AppGroupId);
|
||||||
|
var appGroupContainer = new NSFileManager().GetContainerUrl(AppGroupId);
|
||||||
|
var liteDbStorage = new LiteDbStorageService(
|
||||||
|
Path.Combine(appGroupContainer.Path, "Library", "bitwarden.db"));
|
||||||
|
liteDbStorage.InitAsync();
|
||||||
|
var localizeService = new LocalizeService();
|
||||||
|
var broadcasterService = new BroadcasterService();
|
||||||
|
var messagingService = new MobileBroadcasterMessagingService(broadcasterService);
|
||||||
|
var i18nService = new MobileI18nService(localizeService.GetCurrentCultureInfo());
|
||||||
|
var secureStorageService = new KeyChainStorageService(AppId, AccessGroup);
|
||||||
|
var cryptoPrimitiveService = new CryptoPrimitiveService();
|
||||||
|
var mobileStorageService = new MobileStorageService(preferencesStorage, liteDbStorage);
|
||||||
|
var deviceActionService = new DeviceActionService(mobileStorageService, messagingService);
|
||||||
|
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, messagingService,
|
||||||
|
broadcasterService);
|
||||||
|
|
||||||
|
ServiceContainer.Register<IBroadcasterService>("broadcasterService", broadcasterService);
|
||||||
|
ServiceContainer.Register<IMessagingService>("messagingService", messagingService);
|
||||||
|
ServiceContainer.Register<ILocalizeService>("localizeService", localizeService);
|
||||||
|
ServiceContainer.Register<II18nService>("i18nService", i18nService);
|
||||||
|
ServiceContainer.Register<ICryptoPrimitiveService>("cryptoPrimitiveService", cryptoPrimitiveService);
|
||||||
|
ServiceContainer.Register<IStorageService>("storageService", mobileStorageService);
|
||||||
|
ServiceContainer.Register<IStorageService>("secureStorageService", secureStorageService);
|
||||||
|
ServiceContainer.Register<IDeviceActionService>("deviceActionService", deviceActionService);
|
||||||
|
ServiceContainer.Register<IPlatformUtilsService>("platformUtilsService", platformUtilsService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Bootstrap()
|
||||||
|
{
|
||||||
|
(ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService).Init();
|
||||||
|
ServiceContainer.Resolve<IAuthService>("authService").Init();
|
||||||
|
// Note: This is not awaited
|
||||||
|
var bootstrapTask = BootstrapAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AppearanceAdjustments()
|
||||||
|
{
|
||||||
|
ThemeHelpers.SetAppearance(ThemeManager.GetTheme(false));
|
||||||
|
UIApplication.SharedApplication.StatusBarHidden = false;
|
||||||
|
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task BootstrapAsync()
|
||||||
|
{
|
||||||
|
var disableFavicon = await ServiceContainer.Resolve<IStorageService>("storageService").GetAsync<bool?>(
|
||||||
|
Bit.Core.Constants.DisableFaviconKey);
|
||||||
|
await ServiceContainer.Resolve<IStateService>("stateService").SaveAsync(
|
||||||
|
Bit.Core.Constants.DisableFaviconKey, disableFavicon);
|
||||||
|
await ServiceContainer.Resolve<IEnvironmentService>("environmentService").SetUrlsFromStorageAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,7 @@ namespace Bit.iOS.Core.Views
|
|||||||
protected ICipherService _cipherService;
|
protected ICipherService _cipherService;
|
||||||
protected ITotpService _totpService;
|
protected ITotpService _totpService;
|
||||||
protected IUserService _userService;
|
protected IUserService _userService;
|
||||||
|
protected ISearchService _searchService;
|
||||||
private AppExtensionContext _context;
|
private AppExtensionContext _context;
|
||||||
private UIViewController _controller;
|
private UIViewController _controller;
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ namespace Bit.iOS.Core.Views
|
|||||||
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
|
||||||
_totpService = ServiceContainer.Resolve<ITotpService>("totpService");
|
_totpService = ServiceContainer.Resolve<ITotpService>("totpService");
|
||||||
_userService = ServiceContainer.Resolve<IUserService>("userService");
|
_userService = ServiceContainer.Resolve<IUserService>("userService");
|
||||||
|
_searchService = ServiceContainer.Resolve<ISearchService>("searchService");
|
||||||
_context = context;
|
_context = context;
|
||||||
_controller = controller;
|
_controller = controller;
|
||||||
}
|
}
|
||||||
@@ -61,8 +63,6 @@ namespace Bit.iOS.Core.Views
|
|||||||
_allItems = combinedLogins
|
_allItems = combinedLogins
|
||||||
.Where(c => c.Type == Bit.Core.Enums.CipherType.Login)
|
.Where(c => c.Type == Bit.Core.Enums.CipherType.Login)
|
||||||
.Select(s => new CipherViewModel(s))
|
.Select(s => new CipherViewModel(s))
|
||||||
.OrderBy(s => s.Name)
|
|
||||||
.ThenBy(s => s.Username)
|
|
||||||
.ToList() ?? new List<CipherViewModel>();
|
.ToList() ?? new List<CipherViewModel>();
|
||||||
FilterResults(searchFilter, new CancellationToken());
|
FilterResults(searchFilter, new CancellationToken());
|
||||||
}
|
}
|
||||||
@@ -78,12 +78,9 @@ namespace Bit.iOS.Core.Views
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
searchFilter = searchFilter.ToLower();
|
searchFilter = searchFilter.ToLower();
|
||||||
Items = _allItems
|
var results = _searchService.SearchCiphersAsync(searchFilter,
|
||||||
.Where(s => s.Name?.ToLower().Contains(searchFilter) ?? false ||
|
c => c.Type == Bit.Core.Enums.CipherType.Login, null, ct).GetAwaiter().GetResult();
|
||||||
(s.Username?.ToLower().Contains(searchFilter) ?? false) ||
|
Items = results.Select(s => new CipherViewModel(s)).ToArray();
|
||||||
(s.Uris?.FirstOrDefault()?.Uri?.ToLower().Contains(searchFilter) ?? false))
|
|
||||||
.TakeWhile(s => !ct.IsCancellationRequested)
|
|
||||||
.ToArray();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,7 @@
|
|||||||
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
<Compile Include="Services\CryptoPrimitiveService.cs" />
|
||||||
<Compile Include="Services\KeyChainStorageService.cs" />
|
<Compile Include="Services\KeyChainStorageService.cs" />
|
||||||
<Compile Include="Services\LocalizeService.cs" />
|
<Compile Include="Services\LocalizeService.cs" />
|
||||||
|
<Compile Include="Utilities\iOSCoreHelpers.cs" />
|
||||||
<Compile Include="Utilities\ThemeHelpers.cs" />
|
<Compile Include="Utilities\ThemeHelpers.cs" />
|
||||||
<Compile Include="Views\ExtensionSearchDelegate.cs" />
|
<Compile Include="Views\ExtensionSearchDelegate.cs" />
|
||||||
<Compile Include="Views\ExtensionTableSource.cs" />
|
<Compile Include="Views\ExtensionTableSource.cs" />
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using AuthenticationServices;
|
using AuthenticationServices;
|
||||||
using Bit.App.Abstractions;
|
using Bit.App.Abstractions;
|
||||||
using Bit.App.Resources;
|
using Bit.App.Resources;
|
||||||
@@ -10,12 +8,10 @@ using Bit.App.Utilities;
|
|||||||
using Bit.Core.Abstractions;
|
using Bit.Core.Abstractions;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
using Bit.iOS.Core.Services;
|
|
||||||
using Bit.iOS.Core.Utilities;
|
using Bit.iOS.Core.Utilities;
|
||||||
using Bit.iOS.Services;
|
using Bit.iOS.Services;
|
||||||
using CoreNFC;
|
using CoreNFC;
|
||||||
using Foundation;
|
using Foundation;
|
||||||
using HockeyApp.iOS;
|
|
||||||
using UIKit;
|
using UIKit;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using Xamarin.Forms.Platform.iOS;
|
using Xamarin.Forms.Platform.iOS;
|
||||||
@@ -23,12 +19,8 @@ using Xamarin.Forms.Platform.iOS;
|
|||||||
namespace Bit.iOS
|
namespace Bit.iOS
|
||||||
{
|
{
|
||||||
[Register("AppDelegate")]
|
[Register("AppDelegate")]
|
||||||
public partial class AppDelegate : Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
|
public partial class AppDelegate : FormsApplicationDelegate
|
||||||
{
|
{
|
||||||
private const string AppId = "com.8bit.bitwarden";
|
|
||||||
private const string AppGroupId = "group.com.8bit.bitwarden";
|
|
||||||
private const string AccessGroup = "LTZ2PFU5D6.com.8bit.bitwarden";
|
|
||||||
|
|
||||||
private NFCNdefReaderSession _nfcSession = null;
|
private NFCNdefReaderSession _nfcSession = null;
|
||||||
private iOSPushNotificationHandler _pushHandler = null;
|
private iOSPushNotificationHandler _pushHandler = null;
|
||||||
private NFCReaderDelegate _nfcDelegate = null;
|
private NFCReaderDelegate _nfcDelegate = null;
|
||||||
@@ -42,14 +34,13 @@ namespace Bit.iOS
|
|||||||
{
|
{
|
||||||
Forms.Init();
|
Forms.Init();
|
||||||
InitApp();
|
InitApp();
|
||||||
Bootstrap();
|
|
||||||
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
|
||||||
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
_messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
|
||||||
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
_broadcasterService = ServiceContainer.Resolve<IBroadcasterService>("broadcasterService");
|
||||||
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
_storageService = ServiceContainer.Resolve<IStorageService>("storageService");
|
||||||
|
|
||||||
LoadApplication(new App.App(null));
|
LoadApplication(new App.App(null));
|
||||||
AppearanceAdjustments();
|
iOSCoreHelpers.AppearanceAdjustments();
|
||||||
ZXing.Net.Mobile.Forms.iOS.Platform.Init();
|
ZXing.Net.Mobile.Forms.iOS.Platform.Init();
|
||||||
|
|
||||||
_broadcasterService.Subscribe(nameof(AppDelegate), async (message) =>
|
_broadcasterService.Subscribe(nameof(AppDelegate), async (message) =>
|
||||||
@@ -226,33 +217,14 @@ namespace Bit.iOS
|
|||||||
_pushHandler?.OnMessageReceived(userInfo);
|
_pushHandler?.OnMessageReceived(userInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitApp()
|
public void InitApp()
|
||||||
{
|
{
|
||||||
if(ServiceContainer.RegisteredServices.Count > 0)
|
if(ServiceContainer.RegisteredServices.Count > 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
RegisterLocalServices();
|
|
||||||
ServiceContainer.Init();
|
|
||||||
_pushHandler = new iOSPushNotificationHandler(
|
|
||||||
ServiceContainer.Resolve<IPushNotificationListenerService>("pushNotificationListenerService"));
|
|
||||||
_nfcDelegate = new NFCReaderDelegate((success, message) =>
|
|
||||||
_messagingService.Send("gotYubiKeyOTP", message));
|
|
||||||
|
|
||||||
var crashManagerDelegate = new HockeyAppCrashManagerDelegate(
|
// Migration services
|
||||||
ServiceContainer.Resolve<IAppIdService>("appIdService"),
|
|
||||||
ServiceContainer.Resolve<IUserService>("userService"));
|
|
||||||
var manager = BITHockeyManager.SharedHockeyManager;
|
|
||||||
manager.Configure("51f96ae568ba45f699a18ad9f63046c3", crashManagerDelegate);
|
|
||||||
manager.CrashManager.CrashManagerStatus = BITCrashManagerStatus.AutoSend;
|
|
||||||
manager.StartManager();
|
|
||||||
manager.Authenticator.AuthenticateInstallation();
|
|
||||||
manager.DisableMetricsManager = manager.DisableFeedbackManager = manager.DisableUpdateManager = true;
|
|
||||||
var task = crashManagerDelegate.InitAsync(manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RegisterLocalServices()
|
|
||||||
{
|
|
||||||
ServiceContainer.Register<ILogService>("logService", new ConsoleLogService());
|
ServiceContainer.Register<ILogService>("logService", new ConsoleLogService());
|
||||||
ServiceContainer.Register("settingsShim", new App.Migration.SettingsShim());
|
ServiceContainer.Register("settingsShim", new App.Migration.SettingsShim());
|
||||||
if(false && App.Migration.MigrationHelpers.NeedsMigration())
|
if(false && App.Migration.MigrationHelpers.NeedsMigration())
|
||||||
@@ -261,44 +233,20 @@ namespace Bit.iOS
|
|||||||
"oldSecureStorageService", new Migration.KeyChainStorageService());
|
"oldSecureStorageService", new Migration.KeyChainStorageService());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: This might cause a race condition. Investigate more.
|
iOSCoreHelpers.RegisterLocalServices();
|
||||||
Task.Run(() =>
|
RegisterPush();
|
||||||
{
|
ServiceContainer.Init();
|
||||||
FFImageLoading.Forms.Platform.CachedImageRenderer.Init();
|
iOSCoreHelpers.RegisterHockeyApp();
|
||||||
FFImageLoading.ImageService.Instance.Initialize(new FFImageLoading.Config.Configuration
|
_pushHandler = new iOSPushNotificationHandler(
|
||||||
{
|
ServiceContainer.Resolve<IPushNotificationListenerService>("pushNotificationListenerService"));
|
||||||
FadeAnimationEnabled = false,
|
_nfcDelegate = new NFCReaderDelegate((success, message) =>
|
||||||
FadeAnimationForCachedImages = false
|
_messagingService.Send("gotYubiKeyOTP", message));
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var preferencesStorage = new PreferencesStorageService(AppGroupId);
|
iOSCoreHelpers.Bootstrap();
|
||||||
var appGroupContainer = new NSFileManager().GetContainerUrl(AppGroupId);
|
}
|
||||||
var liteDbStorage = new LiteDbStorageService(
|
|
||||||
Path.Combine(appGroupContainer.Path, "Library", "bitwarden.db"));
|
|
||||||
liteDbStorage.InitAsync();
|
|
||||||
var localizeService = new LocalizeService();
|
|
||||||
var broadcasterService = new BroadcasterService();
|
|
||||||
var messagingService = new MobileBroadcasterMessagingService(broadcasterService);
|
|
||||||
var i18nService = new MobileI18nService(localizeService.GetCurrentCultureInfo());
|
|
||||||
var secureStorageService = new KeyChainStorageService(AppId, AccessGroup);
|
|
||||||
var cryptoPrimitiveService = new CryptoPrimitiveService();
|
|
||||||
var mobileStorageService = new MobileStorageService(preferencesStorage, liteDbStorage);
|
|
||||||
var deviceActionService = new DeviceActionService(mobileStorageService, messagingService);
|
|
||||||
var platformUtilsService = new MobilePlatformUtilsService(deviceActionService, messagingService,
|
|
||||||
broadcasterService);
|
|
||||||
|
|
||||||
ServiceContainer.Register<IBroadcasterService>("broadcasterService", broadcasterService);
|
private void RegisterPush()
|
||||||
ServiceContainer.Register<IMessagingService>("messagingService", messagingService);
|
{
|
||||||
ServiceContainer.Register<ILocalizeService>("localizeService", localizeService);
|
|
||||||
ServiceContainer.Register<II18nService>("i18nService", i18nService);
|
|
||||||
ServiceContainer.Register<ICryptoPrimitiveService>("cryptoPrimitiveService", cryptoPrimitiveService);
|
|
||||||
ServiceContainer.Register<IStorageService>("storageService", mobileStorageService);
|
|
||||||
ServiceContainer.Register<IStorageService>("secureStorageService", secureStorageService);
|
|
||||||
ServiceContainer.Register<IDeviceActionService>("deviceActionService", deviceActionService);
|
|
||||||
ServiceContainer.Register<IPlatformUtilsService>("platformUtilsService", platformUtilsService);
|
|
||||||
|
|
||||||
// Push
|
|
||||||
var notificationListenerService = new PushNotificationListenerService();
|
var notificationListenerService = new PushNotificationListenerService();
|
||||||
ServiceContainer.Register<IPushNotificationListenerService>(
|
ServiceContainer.Register<IPushNotificationListenerService>(
|
||||||
"pushNotificationListenerService", notificationListenerService);
|
"pushNotificationListenerService", notificationListenerService);
|
||||||
@@ -307,42 +255,6 @@ namespace Bit.iOS
|
|||||||
"pushNotificationService", iosPushNotificationService);
|
"pushNotificationService", iosPushNotificationService);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Bootstrap()
|
|
||||||
{
|
|
||||||
(ServiceContainer.Resolve<II18nService>("i18nService") as MobileI18nService).Init();
|
|
||||||
ServiceContainer.Resolve<IAuthService>("authService").Init();
|
|
||||||
// Note: This is not awaited
|
|
||||||
var bootstrapTask = BootstrapAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task BootstrapAsync()
|
|
||||||
{
|
|
||||||
var disableFavicon = await ServiceContainer.Resolve<IStorageService>("storageService").GetAsync<bool?>(
|
|
||||||
Bit.Core.Constants.DisableFaviconKey);
|
|
||||||
await ServiceContainer.Resolve<IStateService>("stateService").SaveAsync(
|
|
||||||
Bit.Core.Constants.DisableFaviconKey, disableFavicon);
|
|
||||||
await ServiceContainer.Resolve<IEnvironmentService>("environmentService").SetUrlsFromStorageAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AppearanceAdjustments()
|
|
||||||
{
|
|
||||||
ThemeHelpers.SetAppearance(ThemeManager.GetTheme(false));
|
|
||||||
/*
|
|
||||||
var primaryColor = new UIColor(red: 0.24f, green: 0.55f, blue: 0.74f, alpha: 1.0f);
|
|
||||||
var grayLight = new UIColor(red: 0.47f, green: 0.47f, blue: 0.47f, alpha: 1.0f);
|
|
||||||
UINavigationBar.Appearance.ShadowImage = new UIImage();
|
|
||||||
UINavigationBar.Appearance.SetBackgroundImage(new UIImage(), UIBarMetrics.Default);
|
|
||||||
UIBarButtonItem.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).TintColor = primaryColor;
|
|
||||||
UIButton.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).SetTitleColor(primaryColor,
|
|
||||||
UIControlState.Normal);
|
|
||||||
UIButton.AppearanceWhenContainedIn(new Type[] { typeof(UISearchBar) }).TintColor = primaryColor;
|
|
||||||
UIStepper.Appearance.TintColor = grayLight;
|
|
||||||
UISlider.Appearance.TintColor = primaryColor;
|
|
||||||
*/
|
|
||||||
UIApplication.SharedApplication.StatusBarHidden = false;
|
|
||||||
UIApplication.SharedApplication.StatusBarStyle = UIStatusBarStyle.LightContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ListenYubiKey(bool listen)
|
private void ListenYubiKey(bool listen)
|
||||||
{
|
{
|
||||||
if(_deviceActionService.SupportsNfc())
|
if(_deviceActionService.SupportsNfc())
|
||||||
|
|||||||
Reference in New Issue
Block a user