1
0
mirror of https://github.com/bitwarden/mobile synced 2025-12-22 19:23:58 +00:00

[EC-259] Added Account Switching to Share extension on iOS (#1971)

* EC-259 Added Account switching on share extension on iOS, also improved performance for this and exception handling

* EC-259 code formatting

* EC-259 Added account switching to Share extension Send view

* EC-259 Fixed navigation on share extension when a forms page is already presented

* EC-259 Fix send text UI update when going from the iOS extension

* EC-259 Improved DateTimeViewModel with helper property to easily setup date and time at the same time and applied on usage
This commit is contained in:
Federico Maccaroni
2022-07-12 14:12:23 -03:00
committed by GitHub
parent d621a5d2f3
commit 292908f53f
28 changed files with 1509 additions and 423 deletions

View File

@@ -1,20 +1,20 @@
using System;
using UIKit;
using Foundation;
using Bit.iOS.Core.Views;
using Bit.App.Resources;
using Bit.iOS.Core.Utilities;
using Bit.App.Abstractions;
using Bit.Core.Abstractions;
using Bit.Core.Utilities;
using System.Threading.Tasks;
using Bit.App.Utilities;
using Bit.Core.Models.Domain;
using Bit.Core.Enums;
using Bit.App.Pages;
using Bit.App.Abstractions;
using Bit.App.Models;
using Xamarin.Forms;
using Bit.App.Pages;
using Bit.App.Resources;
using Bit.App.Utilities;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.Domain;
using Bit.Core.Utilities;
using Bit.iOS.Core.Utilities;
using Bit.iOS.Core.Views;
using Foundation;
using UIKit;
using Xamarin.Forms;
namespace Bit.iOS.Core.Controllers
{
@@ -39,6 +39,10 @@ namespace Bit.iOS.Core.Controllers
protected bool autofillExtension = false;
public BaseLockPasswordViewController()
{
}
public BaseLockPasswordViewController(IntPtr handle)
: base(handle)
{ }
@@ -168,13 +172,12 @@ namespace Bit.iOS.Core.Controllers
{
TableView.BackgroundColor = ThemeHelpers.BackgroundColor;
TableView.SeparatorColor = ThemeHelpers.SeparatorColor;
TableView.RowHeight = UITableView.AutomaticDimension;
TableView.EstimatedRowHeight = 70;
TableView.Source = new TableSource(this);
TableView.AllowsSelection = true;
}
TableView.RowHeight = UITableView.AutomaticDimension;
TableView.EstimatedRowHeight = 70;
TableView.Source = new TableSource(this);
TableView.AllowsSelection = true;
base.ViewDidLoad();
if (_biometricLock)
@@ -191,7 +194,7 @@ namespace Bit.iOS.Core.Controllers
}
}
public override async void ViewDidAppear(bool animated)
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
@@ -402,28 +405,43 @@ namespace Bit.iOS.Core.Controllers
});
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
MasterPasswordCell?.Dispose();
MasterPasswordCell = null;
TableView?.Dispose();
}
public class TableSource : ExtendedUITableViewSource
{
private readonly BaseLockPasswordViewController _controller;
private readonly WeakReference<BaseLockPasswordViewController> _controller;
public TableSource(BaseLockPasswordViewController controller)
{
_controller = controller;
_controller = new WeakReference<BaseLockPasswordViewController>(controller);
}
public override UITableViewCell GetCell(UITableView tableView, NSIndexPath indexPath)
{
if (!_controller.TryGetTarget(out var controller))
{
return new ExtendedUITableViewCell();
}
if (indexPath.Section == 0)
{
if (indexPath.Row == 0)
{
if (_controller._biometricUnlockOnly)
if (controller._biometricUnlockOnly)
{
return _controller.BiometricCell;
return controller.BiometricCell;
}
else
{
return _controller.MasterPasswordCell;
return controller.MasterPasswordCell;
}
}
}
@@ -431,7 +449,7 @@ namespace Bit.iOS.Core.Controllers
{
if (indexPath.Row == 0)
{
if (_controller._passwordReprompt)
if (controller._passwordReprompt)
{
var cell = new ExtendedUITableViewCell();
cell.TextLabel.TextColor = ThemeHelpers.DangerColor;
@@ -441,9 +459,9 @@ namespace Bit.iOS.Core.Controllers
cell.TextLabel.Text = AppResources.PasswordConfirmationDesc;
return cell;
}
else if (!_controller._biometricUnlockOnly)
else if (!controller._biometricUnlockOnly)
{
return _controller.BiometricCell;
return controller.BiometricCell;
}
}
}
@@ -457,8 +475,13 @@ namespace Bit.iOS.Core.Controllers
public override nint NumberOfSections(UITableView tableView)
{
return (!_controller._biometricUnlockOnly && _controller._biometricLock) ||
_controller._passwordReprompt
if (!_controller.TryGetTarget(out var controller))
{
return 0;
}
return (!controller._biometricUnlockOnly && controller._biometricLock) ||
controller._passwordReprompt
? 2
: 1;
}
@@ -484,13 +507,18 @@ namespace Bit.iOS.Core.Controllers
public override void RowSelected(UITableView tableView, NSIndexPath indexPath)
{
if (!_controller.TryGetTarget(out var controller))
{
return;
}
tableView.DeselectRow(indexPath, true);
tableView.EndEditing(true);
if (indexPath.Row == 0 &&
((_controller._biometricUnlockOnly && indexPath.Section == 0) ||
((controller._biometricUnlockOnly && indexPath.Section == 0) ||
indexPath.Section == 1))
{
var task = _controller.PromptBiometricAsync();
var task = controller.PromptBiometricAsync();
return;
}
var cell = tableView.CellAt(indexPath);

View File

@@ -7,7 +7,11 @@ namespace Bit.iOS.Core.Controllers
public class ExtendedUIViewController : UIViewController
{
public Action DismissModalAction { get; set; }
public ExtendedUIViewController()
{
}
public ExtendedUIViewController(IntPtr handle)
: base(handle)
{
@@ -28,16 +32,28 @@ namespace Bit.iOS.Core.Controllers
{
View.BackgroundColor = ThemeHelpers.BackgroundColor;
}
if (NavigationController?.NavigationBar != null)
UpdateNavigationBarTheme();
}
protected virtual void UpdateNavigationBarTheme()
{
UpdateNavigationBarTheme(NavigationController?.NavigationBar);
}
protected void UpdateNavigationBarTheme(UINavigationBar navBar)
{
if (navBar is null)
{
NavigationController.NavigationBar.BarTintColor = ThemeHelpers.NavBarBackgroundColor;
NavigationController.NavigationBar.BackgroundColor = ThemeHelpers.NavBarBackgroundColor;
NavigationController.NavigationBar.TintColor = ThemeHelpers.NavBarTextColor;
NavigationController.NavigationBar.TitleTextAttributes = new UIStringAttributes
{
ForegroundColor = ThemeHelpers.NavBarTextColor
};
return;
}
navBar.BarTintColor = ThemeHelpers.NavBarBackgroundColor;
navBar.BackgroundColor = ThemeHelpers.NavBarBackgroundColor;
navBar.TintColor = ThemeHelpers.NavBarTextColor;
navBar.TitleTextAttributes = new UIStringAttributes
{
ForegroundColor = ThemeHelpers.NavBarTextColor
};
}
}
}

View File

@@ -184,7 +184,7 @@ namespace Bit.iOS.Core.Controllers
}
}
public override async void ViewDidAppear(bool animated)
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);

View File

@@ -12,10 +12,10 @@ namespace Bit.iOS.Core.Utilities
public class AccountSwitchingOverlayHelper
{
const string DEFAULT_SYSTEM_AVATAR_IMAGE = "person.2";
IStateService _stateService;
IMessagingService _messagingService;
ILogger _logger;
readonly IStateService _stateService;
readonly IMessagingService _messagingService;
readonly ILogger _logger;
public AccountSwitchingOverlayHelper()
{
@@ -32,10 +32,12 @@ namespace Bit.iOS.Core.Utilities
{
throw new NullReferenceException(nameof(_stateService));
}
var avatarImageSource = new AvatarImageSource(await _stateService.GetNameAsync(), await _stateService.GetEmailAsync());
var avatarUIImage = await avatarImageSource.GetNativeImageAsync();
return avatarUIImage?.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal) ?? UIImage.GetSystemImage(DEFAULT_SYSTEM_AVATAR_IMAGE);
using (var avatarUIImage = await avatarImageSource.GetNativeImageAsync())
{
return avatarUIImage?.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal) ?? UIImage.GetSystemImage(DEFAULT_SYSTEM_AVATAR_IMAGE);
}
}
catch (Exception ex)
{

View File

@@ -2,6 +2,7 @@
using System.IO;
using System.Threading.Tasks;
using Bit.App.Abstractions;
using Bit.App.Controls;
using Bit.App.Models;
using Bit.App.Pages;
using Bit.App.Resources;
@@ -15,6 +16,7 @@ using Bit.iOS.Core.Services;
using CoreNFC;
using Foundation;
using UIKit;
using Xamarin.Forms;
namespace Bit.iOS.Core.Utilities
{
@@ -26,6 +28,42 @@ namespace Bit.iOS.Core.Utilities
public static string AppGroupId = "group.com.8bit.bitwarden";
public static string AccessGroup = "LTZ2PFU5D6.com.8bit.bitwarden";
public static void InitApp<T>(T rootController,
string clearCipherCacheKey,
NFCNdefReaderSession nfcSession,
out NFCReaderDelegate nfcDelegate,
out IAccountsManager accountsManager)
where T : UIViewController, IAccountsManagerHost
{
Forms.Init();
if (ServiceContainer.RegisteredServices.Count > 0)
{
ServiceContainer.Reset();
}
RegisterLocalServices();
var deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
var messagingService = ServiceContainer.Resolve<IMessagingService>("messagingService");
ServiceContainer.Init(deviceActionService.DeviceUserAgent,
clearCipherCacheKey,
Bit.Core.Constants.iOSAllClearCipherCacheKeys);
InitLogger();
Bootstrap();
var appOptions = new AppOptions { IosExtension = true };
var app = new App.App(appOptions);
ThemeManager.SetTheme(app.Resources);
AppearanceAdjustments();
nfcDelegate = new Core.NFCReaderDelegate((success, message) =>
messagingService.Send("gotYubiKeyOTP", message));
SubscribeBroadcastReceiver(rootController, nfcSession, nfcDelegate);
accountsManager = ServiceContainer.Resolve<IAccountsManager>("accountsManager");
accountsManager.Init(() => appOptions, rootController);
}
public static void InitLogger()
{
ServiceContainer.Resolve<ILogger>("logger").InitAsync();
@@ -89,6 +127,7 @@ namespace Bit.iOS.Core.Utilities
ServiceContainer.Register<ICryptoFunctionService>("cryptoFunctionService", cryptoFunctionService);
ServiceContainer.Register<ICryptoService>("cryptoService", cryptoService);
ServiceContainer.Register<IPasswordRepromptService>("passwordRepromptService", passwordRepromptService);
ServiceContainer.Register<IAvatarImageSourcePool>("avatarImageSourcePool", new AvatarImageSourcePool());
}
public static void Bootstrap(Func<Task> postBootstrapFunc = null)
@@ -181,7 +220,8 @@ namespace Bit.iOS.Core.Utilities
ServiceContainer.Resolve<IStorageService>("secureStorageService"),
ServiceContainer.Resolve<IStateService>("stateService"),
ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService"),
ServiceContainer.Resolve<IAuthService>("authService"));
ServiceContainer.Resolve<IAuthService>("authService"),
ServiceContainer.Resolve<ILogger>("logger"));
ServiceContainer.Register<IAccountsManager>("accountsManager", accountsManager);
if (postBootstrapFunc != null)