mirror of
https://github.com/bitwarden/mobile.git
synced 2024-11-15 10:25:20 +01:00
Merge branch 'feature/maui-migration' into feature/maui-migration-passkeys
This commit is contained in:
commit
9d29af36e5
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@ -147,7 +147,7 @@ jobs:
|
||||
name: com.x8bit.bitwarden-fdroid.apk
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
|
||||
uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
|
||||
with:
|
||||
node-version: '16.x'
|
||||
|
||||
|
62
src/Core/Controls/Avatar/AvatarImageSource.cs
Normal file
62
src/Core/Controls/Avatar/AvatarImageSource.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public class AvatarImageSource : StreamImageSource
|
||||
{
|
||||
private readonly string _text;
|
||||
private readonly string _id;
|
||||
private readonly string _color;
|
||||
private readonly AvatarInfo _avatarInfo;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj is AvatarImageSource avatar)
|
||||
{
|
||||
return avatar._id == _id && avatar._text == _text && avatar._color == _color;
|
||||
}
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => _id?.GetHashCode() ?? _text?.GetHashCode() ?? -1;
|
||||
|
||||
public AvatarImageSource(string userId = null, string name = null, string email = null, string color = null)
|
||||
{
|
||||
_id = userId;
|
||||
_text = name;
|
||||
if (string.IsNullOrWhiteSpace(_text))
|
||||
{
|
||||
_text = email;
|
||||
}
|
||||
_color = color;
|
||||
|
||||
//Workaround: [MAUI-Migration] There is currently a bug in MAUI where the actual size of the image is used instead of the size it should occupy in the Toolbar.
|
||||
//This causes some issues with the position of the icon. As a workaround we make the icon smaller until this is fixed.
|
||||
//Github issues: https://github.com/dotnet/maui/issues/12359 and https://github.com/dotnet/maui/pull/17120
|
||||
_avatarInfo = new AvatarInfo(userId, name, email, color, DeviceInfo.Platform == DevicePlatform.iOS ? 20 : 50);
|
||||
}
|
||||
|
||||
public override Func<CancellationToken, Task<Stream>> Stream => GetStreamAsync;
|
||||
|
||||
private Task<Stream> GetStreamAsync(CancellationToken userToken = new CancellationToken())
|
||||
{
|
||||
var result = Draw();
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
private Stream Draw()
|
||||
{
|
||||
using (var img = SKAvatarImageHelper.Draw(_avatarInfo))
|
||||
{
|
||||
var data = img.Encode(SKEncodedImageFormat.Png, 100);
|
||||
return data?.AsStream(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
63
src/Core/Controls/Avatar/AvatarInfo.cs
Normal file
63
src/Core/Controls/Avatar/AvatarInfo.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public struct AvatarInfo
|
||||
{
|
||||
private const string DEFAULT_BACKGROUND_COLOR = "#33ffffff";
|
||||
|
||||
public AvatarInfo(string? userId = null, string? name = null, string? email = null, string? color = null, int size = 50)
|
||||
{
|
||||
Size = size;
|
||||
var text = string.IsNullOrWhiteSpace(name) ? email : name;
|
||||
|
||||
string? upperCaseText = null;
|
||||
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
CharsToDraw = "..";
|
||||
}
|
||||
else if (text.Length > 1)
|
||||
{
|
||||
upperCaseText = text.ToUpper();
|
||||
CharsToDraw = GetFirstLetters(upperCaseText, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
CharsToDraw = upperCaseText = text.ToUpper();
|
||||
}
|
||||
|
||||
BackgroundColor = color ?? CoreHelpers.StringToColor(userId ?? upperCaseText, DEFAULT_BACKGROUND_COLOR);
|
||||
TextColor = CoreHelpers.TextColorFromBgColor(BackgroundColor);
|
||||
}
|
||||
|
||||
public string CharsToDraw { get; }
|
||||
public string BackgroundColor { get; }
|
||||
public string TextColor { get; }
|
||||
public int Size { get; }
|
||||
|
||||
private static string GetFirstLetters(string data, int charCount)
|
||||
{
|
||||
var sanitizedData = data.Trim();
|
||||
var parts = sanitizedData.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (parts.Length > 1 && charCount <= 2)
|
||||
{
|
||||
var text = string.Empty;
|
||||
for (var i = 0; i < charCount; i++)
|
||||
{
|
||||
text += parts[i][0];
|
||||
}
|
||||
return text;
|
||||
}
|
||||
if (sanitizedData.Length > 2)
|
||||
{
|
||||
return sanitizedData.Substring(0, 2);
|
||||
}
|
||||
return sanitizedData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
63
src/Core/Controls/Avatar/SKAvatarImageHelper.cs
Normal file
63
src/Core/Controls/Avatar/SKAvatarImageHelper.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public static class SKAvatarImageHelper
|
||||
{
|
||||
public static SKImage Draw(AvatarInfo avatarInfo)
|
||||
{
|
||||
using (var bitmap = new SKBitmap(avatarInfo.Size * 2,
|
||||
avatarInfo.Size * 2,
|
||||
SKImageInfo.PlatformColorType,
|
||||
SKAlphaType.Premul))
|
||||
{
|
||||
using (var canvas = new SKCanvas(bitmap))
|
||||
{
|
||||
canvas.Clear(SKColors.Transparent);
|
||||
using (var paint = new SKPaint
|
||||
{
|
||||
IsAntialias = true,
|
||||
Style = SKPaintStyle.Fill,
|
||||
StrokeJoin = SKStrokeJoin.Miter,
|
||||
Color = SKColor.Parse(avatarInfo.BackgroundColor)
|
||||
})
|
||||
{
|
||||
var midX = canvas.LocalClipBounds.Size.ToSizeI().Width / 2;
|
||||
var midY = canvas.LocalClipBounds.Size.ToSizeI().Height / 2;
|
||||
var radius = midX - midX / 5;
|
||||
|
||||
using (var circlePaint = new SKPaint
|
||||
{
|
||||
IsAntialias = true,
|
||||
Style = SKPaintStyle.Fill,
|
||||
StrokeJoin = SKStrokeJoin.Miter,
|
||||
Color = SKColor.Parse(avatarInfo.BackgroundColor)
|
||||
})
|
||||
{
|
||||
canvas.DrawCircle(midX, midY, radius, circlePaint);
|
||||
|
||||
var typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Normal);
|
||||
var textSize = midX / 1.3f;
|
||||
using (var textPaint = new SKPaint
|
||||
{
|
||||
IsAntialias = true,
|
||||
Style = SKPaintStyle.Fill,
|
||||
Color = SKColor.Parse(avatarInfo.TextColor),
|
||||
TextSize = textSize,
|
||||
TextAlign = SKTextAlign.Center,
|
||||
Typeface = typeface
|
||||
})
|
||||
{
|
||||
var rect = new SKRect();
|
||||
textPaint.MeasureText(avatarInfo.CharsToDraw, ref rect);
|
||||
canvas.DrawText(avatarInfo.CharsToDraw, midX, midY + rect.Height / 2, textPaint);
|
||||
|
||||
return SKImage.FromBitmap(bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,179 +0,0 @@
|
||||
using Bit.Core.Utilities;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Bit.App.Controls
|
||||
{
|
||||
public class AvatarImageSource : StreamImageSource
|
||||
{
|
||||
private readonly string _text;
|
||||
private readonly string _id;
|
||||
private readonly string _color;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj is AvatarImageSource avatar)
|
||||
{
|
||||
return avatar._id == _id && avatar._text == _text && avatar._color == _color;
|
||||
}
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => _id?.GetHashCode() ?? _text?.GetHashCode() ?? -1;
|
||||
|
||||
public AvatarImageSource(string userId = null, string name = null, string email = null, string color = null)
|
||||
{
|
||||
_id = userId;
|
||||
_text = name;
|
||||
if (string.IsNullOrWhiteSpace(_text))
|
||||
{
|
||||
_text = email;
|
||||
}
|
||||
_color = color;
|
||||
}
|
||||
|
||||
public override Func<CancellationToken, Task<Stream>> Stream => GetStreamAsync;
|
||||
|
||||
private Task<Stream> GetStreamAsync(CancellationToken userToken = new CancellationToken())
|
||||
{
|
||||
var result = Draw();
|
||||
return Task.FromResult(result);
|
||||
}
|
||||
|
||||
private Stream Draw()
|
||||
{
|
||||
string chars;
|
||||
string upperCaseText = null;
|
||||
|
||||
if (string.IsNullOrEmpty(_text))
|
||||
{
|
||||
chars = "..";
|
||||
}
|
||||
else if (_text?.Length > 1)
|
||||
{
|
||||
upperCaseText = _text.ToUpper();
|
||||
chars = GetFirstLetters(upperCaseText, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
chars = upperCaseText = _text.ToUpper();
|
||||
}
|
||||
|
||||
var bgColor = _color ?? CoreHelpers.StringToColor(_id ?? upperCaseText, "#33ffffff");
|
||||
var textColor = CoreHelpers.TextColorFromBgColor(bgColor);
|
||||
var size = 50;
|
||||
|
||||
//Workaround: [MAUI-Migration] There is currently a bug in MAUI where the actual size of the image is used instead of the size it should occupy in the Toolbar.
|
||||
//This causes some issues with the position of the icon. As a workaround we make the icon smaller until this is fixed.
|
||||
//Github issues: https://github.com/dotnet/maui/issues/12359 and https://github.com/dotnet/maui/pull/17120
|
||||
if (DeviceInfo.Platform == DevicePlatform.iOS)
|
||||
{
|
||||
size = 20;
|
||||
}
|
||||
|
||||
using (var bitmap = new SKBitmap(size * 2,
|
||||
size * 2,
|
||||
SKImageInfo.PlatformColorType,
|
||||
SKAlphaType.Premul))
|
||||
{
|
||||
using (var canvas = new SKCanvas(bitmap))
|
||||
{
|
||||
canvas.Clear(SKColors.Transparent);
|
||||
using (var paint = new SKPaint
|
||||
{
|
||||
IsAntialias = true,
|
||||
Style = SKPaintStyle.Fill,
|
||||
StrokeJoin = SKStrokeJoin.Miter,
|
||||
Color = SKColor.Parse(bgColor)
|
||||
})
|
||||
{
|
||||
var midX = canvas.LocalClipBounds.Size.ToSizeI().Width / 2;
|
||||
var midY = canvas.LocalClipBounds.Size.ToSizeI().Height / 2;
|
||||
var radius = midX - midX / 5;
|
||||
|
||||
using (var circlePaint = new SKPaint
|
||||
{
|
||||
IsAntialias = true,
|
||||
Style = SKPaintStyle.Fill,
|
||||
StrokeJoin = SKStrokeJoin.Miter,
|
||||
Color = SKColor.Parse(bgColor)
|
||||
})
|
||||
{
|
||||
canvas.DrawCircle(midX, midY, radius, circlePaint);
|
||||
|
||||
var typeface = SKTypeface.FromFamilyName("Arial", SKFontStyle.Normal);
|
||||
var textSize = midX / 1.3f;
|
||||
using (var textPaint = new SKPaint
|
||||
{
|
||||
IsAntialias = true,
|
||||
Style = SKPaintStyle.Fill,
|
||||
Color = SKColor.Parse(textColor),
|
||||
TextSize = textSize,
|
||||
TextAlign = SKTextAlign.Center,
|
||||
Typeface = typeface
|
||||
})
|
||||
{
|
||||
var rect = new SKRect();
|
||||
textPaint.MeasureText(chars, ref rect);
|
||||
canvas.DrawText(chars, midX, midY + rect.Height / 2, textPaint);
|
||||
|
||||
using (var img = SKImage.FromBitmap(bitmap))
|
||||
{
|
||||
var data = img.Encode(SKEncodedImageFormat.Png, 100);
|
||||
return data?.AsStream(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetFirstLetters(string data, int charCount)
|
||||
{
|
||||
var sanitizedData = data.Trim();
|
||||
var parts = sanitizedData.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (parts.Length > 1 && charCount <= 2)
|
||||
{
|
||||
var text = string.Empty;
|
||||
for (var i = 0; i < charCount; i++)
|
||||
{
|
||||
text += parts[i][0];
|
||||
}
|
||||
return text;
|
||||
}
|
||||
if (sanitizedData.Length > 2)
|
||||
{
|
||||
return sanitizedData.Substring(0, 2);
|
||||
}
|
||||
return sanitizedData;
|
||||
}
|
||||
|
||||
private Color StringToColor(string str)
|
||||
{
|
||||
if (str == null)
|
||||
{
|
||||
return Color.FromArgb("#33ffffff");
|
||||
}
|
||||
var hash = 0;
|
||||
for (var i = 0; i < str.Length; i++)
|
||||
{
|
||||
hash = str[i] + ((hash << 5) - hash);
|
||||
}
|
||||
var color = "#FF";
|
||||
for (var i = 0; i < 3; i++)
|
||||
{
|
||||
var value = (hash >> (i * 8)) & 0xff;
|
||||
var base16 = "00" + Convert.ToString(value, 16);
|
||||
color += base16.Substring(base16.Length - 2);
|
||||
}
|
||||
return Color.FromArgb(color);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<ContentView
|
||||
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
@ -17,7 +17,7 @@
|
||||
LineBreakMode="TailTruncation" />
|
||||
|
||||
<controls:IconLabel
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.ShareSquare}}"
|
||||
Text="{Binding Source={x:Static core:BitwardenIcons.ExternalLink}}"
|
||||
TextColor="{DynamicResource TextColor}"
|
||||
HorizontalOptions="End"
|
||||
VerticalOptions="Center"
|
||||
|
@ -78,6 +78,7 @@
|
||||
<Folder Include="Resources\Localization\" />
|
||||
<Folder Include="Utilities\Fido2\" />
|
||||
<Folder Include="Controls\Picker\" />
|
||||
<Folder Include="Controls\Avatar\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<MauiImage Include="Resources\Images\dotnet_bot.svg">
|
||||
@ -108,5 +109,6 @@
|
||||
<ItemGroup>
|
||||
<None Remove="Utilities\Fido2\" />
|
||||
<None Remove="Controls\Picker\" />
|
||||
<None Remove="Controls\Avatar\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -2,12 +2,15 @@ using System;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using MapKit;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Autofill
|
||||
{
|
||||
public partial class LockPasswordViewController : Core.Controllers.BaseLockPasswordViewController
|
||||
{
|
||||
UIBarButtonItem _cancelButton;
|
||||
UIControl _accountSwitchButton;
|
||||
AccountSwitchingOverlayView _accountSwitchingOverlayView;
|
||||
AccountSwitchingOverlayHelper _accountSwitchingOverlayHelper;
|
||||
|
||||
@ -23,22 +26,37 @@ namespace Bit.iOS.Autofill
|
||||
|
||||
public CredentialProviderViewController CPViewController { get; set; }
|
||||
public override UINavigationItem BaseNavItem => NavItem;
|
||||
public override UIBarButtonItem BaseCancelButton => CancelButton;
|
||||
public override UIBarButtonItem BaseCancelButton => _cancelButton;
|
||||
public override UIBarButtonItem BaseSubmitButton => SubmitButton;
|
||||
public override Action Success => () => CPViewController.DismissLockAndContinue();
|
||||
public override Action Cancel => () => CPViewController.CompleteRequest();
|
||||
|
||||
public override async void ViewDidLoad()
|
||||
{
|
||||
_cancelButton = new UIBarButtonItem(UIBarButtonSystemItem.Cancel, CancelButton_TouchUpInside);
|
||||
|
||||
base.ViewDidLoad();
|
||||
|
||||
_accountSwitchingOverlayHelper = new AccountSwitchingOverlayHelper();
|
||||
AccountSwitchingBarButton.Image = await _accountSwitchingOverlayHelper.CreateAvatarImageAsync();
|
||||
|
||||
_accountSwitchButton = await _accountSwitchingOverlayHelper.CreateAccountSwitchToolbarButtonItemCustomViewAsync();
|
||||
_accountSwitchButton.TouchUpInside += AccountSwitchedButton_TouchUpInside;
|
||||
|
||||
NavItem.SetLeftBarButtonItems(new UIBarButtonItem[]
|
||||
{
|
||||
_cancelButton,
|
||||
new UIBarButtonItem(_accountSwitchButton)
|
||||
}, false);
|
||||
|
||||
_accountSwitchingOverlayView = _accountSwitchingOverlayHelper.CreateAccountSwitchingOverlayView(OverlayView);
|
||||
}
|
||||
|
||||
partial void AccountSwitchingBarButton_Activated(UIBarButtonItem sender)
|
||||
private void CancelButton_TouchUpInside(object sender, EventArgs e)
|
||||
{
|
||||
Cancel();
|
||||
}
|
||||
|
||||
private void AccountSwitchedButton_TouchUpInside(object sender, EventArgs e)
|
||||
{
|
||||
_accountSwitchingOverlayHelper.OnToolbarItemActivated(_accountSwitchingOverlayView, OverlayView);
|
||||
}
|
||||
@ -48,9 +66,19 @@ namespace Bit.iOS.Autofill
|
||||
CheckPasswordAsync().FireAndForget();
|
||||
}
|
||||
|
||||
partial void CancelButton_Activated(UIBarButtonItem sender)
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
Cancel();
|
||||
if (disposing)
|
||||
{
|
||||
if (_accountSwitchButton != null)
|
||||
{
|
||||
_accountSwitchingOverlayHelper.DisposeAccountSwitchToolbarButtonItemImage(_accountSwitchButton);
|
||||
|
||||
_accountSwitchButton.TouchUpInside -= AccountSwitchedButton_TouchUpInside;
|
||||
}
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,13 +12,6 @@ namespace Bit.iOS.Autofill
|
||||
[Register ("LockPasswordViewController")]
|
||||
partial class LockPasswordViewController
|
||||
{
|
||||
[Outlet]
|
||||
UIKit.UIBarButtonItem AccountSwitchingBarButton { get; set; }
|
||||
|
||||
[Outlet]
|
||||
[GeneratedCode ("iOS Designer", "1.0")]
|
||||
UIKit.UIBarButtonItem CancelButton { get; set; }
|
||||
|
||||
[Outlet]
|
||||
[GeneratedCode ("iOS Designer", "1.0")]
|
||||
UIKit.UITableView MainTableView { get; set; }
|
||||
@ -34,27 +27,11 @@ namespace Bit.iOS.Autofill
|
||||
[GeneratedCode ("iOS Designer", "1.0")]
|
||||
UIKit.UIBarButtonItem SubmitButton { get; set; }
|
||||
|
||||
[Action ("AccountSwitchingBarButton_Activated:")]
|
||||
partial void AccountSwitchingBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||
|
||||
[Action ("CancelButton_Activated:")]
|
||||
partial void CancelButton_Activated (UIKit.UIBarButtonItem sender);
|
||||
|
||||
[Action ("SubmitButton_Activated:")]
|
||||
partial void SubmitButton_Activated (UIKit.UIBarButtonItem sender);
|
||||
|
||||
void ReleaseDesignerOutlets ()
|
||||
{
|
||||
if (AccountSwitchingBarButton != null) {
|
||||
AccountSwitchingBarButton.Dispose ();
|
||||
AccountSwitchingBarButton = null;
|
||||
}
|
||||
|
||||
if (CancelButton != null) {
|
||||
CancelButton.Dispose ();
|
||||
CancelButton = null;
|
||||
}
|
||||
|
||||
if (MainTableView != null) {
|
||||
MainTableView.Dispose ();
|
||||
MainTableView = null;
|
||||
@ -65,15 +42,15 @@ namespace Bit.iOS.Autofill
|
||||
NavItem = null;
|
||||
}
|
||||
|
||||
if (SubmitButton != null) {
|
||||
SubmitButton.Dispose ();
|
||||
SubmitButton = null;
|
||||
}
|
||||
|
||||
if (OverlayView != null) {
|
||||
OverlayView.Dispose ();
|
||||
OverlayView = null;
|
||||
}
|
||||
|
||||
if (SubmitButton != null) {
|
||||
SubmitButton.Dispose ();
|
||||
SubmitButton = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,9 @@ namespace Bit.iOS.Autofill
|
||||
{
|
||||
public partial class LoginListViewController : ExtendedUIViewController
|
||||
{
|
||||
UIBarButtonItem _cancelButton;
|
||||
UIControl _accountSwitchButton;
|
||||
|
||||
public LoginListViewController(IntPtr handle)
|
||||
: base(handle)
|
||||
{
|
||||
@ -37,12 +40,14 @@ namespace Bit.iOS.Autofill
|
||||
|
||||
public async override void ViewDidLoad()
|
||||
{
|
||||
_cancelButton = new UIBarButtonItem(UIBarButtonSystemItem.Cancel, CancelButton_TouchUpInside);
|
||||
|
||||
base.ViewDidLoad();
|
||||
|
||||
SubscribeSyncCompleted();
|
||||
|
||||
NavItem.Title = AppResources.Items;
|
||||
CancelBarButton.Title = AppResources.Cancel;
|
||||
_cancelButton.Title = AppResources.Cancel;
|
||||
|
||||
TableView.RowHeight = UITableView.AutomaticDimension;
|
||||
TableView.EstimatedRowHeight = 44;
|
||||
@ -61,21 +66,29 @@ namespace Bit.iOS.Autofill
|
||||
}
|
||||
|
||||
_accountSwitchingOverlayHelper = new AccountSwitchingOverlayHelper();
|
||||
AccountSwitchingBarButton.Image = await _accountSwitchingOverlayHelper.CreateAvatarImageAsync();
|
||||
|
||||
_accountSwitchButton = await _accountSwitchingOverlayHelper.CreateAccountSwitchToolbarButtonItemCustomViewAsync();
|
||||
_accountSwitchButton.TouchUpInside += AccountSwitchedButton_TouchUpInside;
|
||||
|
||||
NavItem.SetLeftBarButtonItems(new UIBarButtonItem[]
|
||||
{
|
||||
_cancelButton,
|
||||
new UIBarButtonItem(_accountSwitchButton)
|
||||
}, false);
|
||||
|
||||
_accountSwitchingOverlayView = _accountSwitchingOverlayHelper.CreateAccountSwitchingOverlayView(OverlayView);
|
||||
}
|
||||
|
||||
partial void AccountSwitchingBarButton_Activated(UIBarButtonItem sender)
|
||||
{
|
||||
_accountSwitchingOverlayHelper.OnToolbarItemActivated(_accountSwitchingOverlayView, OverlayView);
|
||||
}
|
||||
|
||||
partial void CancelBarButton_Activated(UIBarButtonItem sender)
|
||||
private void CancelButton_TouchUpInside(object sender, EventArgs e)
|
||||
{
|
||||
Cancel();
|
||||
}
|
||||
|
||||
private void AccountSwitchedButton_TouchUpInside(object sender, EventArgs e)
|
||||
{
|
||||
_accountSwitchingOverlayHelper.OnToolbarItemActivated(_accountSwitchingOverlayView, OverlayView);
|
||||
}
|
||||
|
||||
private void Cancel()
|
||||
{
|
||||
CPViewController.CompleteRequest();
|
||||
@ -151,6 +164,21 @@ namespace Bit.iOS.Autofill
|
||||
});
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (_accountSwitchButton != null)
|
||||
{
|
||||
_accountSwitchingOverlayHelper.DisposeAccountSwitchToolbarButtonItemImage(_accountSwitchButton);
|
||||
|
||||
_accountSwitchButton.TouchUpInside -= AccountSwitchedButton_TouchUpInside;
|
||||
}
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public class TableSource : ExtensionTableSource
|
||||
{
|
||||
private LoginListViewController _controller;
|
||||
|
23
src/iOS.Autofill/LoginListViewController.designer.cs
generated
23
src/iOS.Autofill/LoginListViewController.designer.cs
generated
@ -12,17 +12,10 @@ namespace Bit.iOS.Autofill
|
||||
[Register ("LoginListViewController")]
|
||||
partial class LoginListViewController
|
||||
{
|
||||
[Outlet]
|
||||
UIKit.UIBarButtonItem AccountSwitchingBarButton { get; set; }
|
||||
|
||||
[Outlet]
|
||||
[GeneratedCode ("iOS Designer", "1.0")]
|
||||
UIKit.UIBarButtonItem AddBarButton { get; set; }
|
||||
|
||||
[Outlet]
|
||||
[GeneratedCode ("iOS Designer", "1.0")]
|
||||
UIKit.UIBarButtonItem CancelBarButton { get; set; }
|
||||
|
||||
[Outlet]
|
||||
UIKit.UIView MainView { get; set; }
|
||||
|
||||
@ -36,15 +29,9 @@ namespace Bit.iOS.Autofill
|
||||
[Outlet]
|
||||
UIKit.UITableView TableView { get; set; }
|
||||
|
||||
[Action ("AccountSwitchingBarButton_Activated:")]
|
||||
partial void AccountSwitchingBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||
|
||||
[Action ("AddBarButton_Activated:")]
|
||||
partial void AddBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||
|
||||
[Action ("CancelBarButton_Activated:")]
|
||||
partial void CancelBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||
|
||||
[Action ("SearchBarButton_Activated:")]
|
||||
partial void SearchBarButton_Activated (UIKit.UIBarButtonItem sender);
|
||||
|
||||
@ -55,11 +42,6 @@ namespace Bit.iOS.Autofill
|
||||
AddBarButton = null;
|
||||
}
|
||||
|
||||
if (CancelBarButton != null) {
|
||||
CancelBarButton.Dispose ();
|
||||
CancelBarButton = null;
|
||||
}
|
||||
|
||||
if (MainView != null) {
|
||||
MainView.Dispose ();
|
||||
MainView = null;
|
||||
@ -79,11 +61,6 @@ namespace Bit.iOS.Autofill
|
||||
TableView.Dispose ();
|
||||
TableView = null;
|
||||
}
|
||||
|
||||
if (AccountSwitchingBarButton != null) {
|
||||
AccountSwitchingBarButton.Dispose ();
|
||||
AccountSwitchingBarButton = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22154" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="43">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="43">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22130"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
@ -185,20 +185,6 @@
|
||||
</view>
|
||||
<toolbarItems/>
|
||||
<navigationItem key="navigationItem" title="Logins" id="3734">
|
||||
<leftBarButtonItems>
|
||||
<barButtonItem 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>
|
||||
<barButtonItem title="Account" image="person.2" catalog="system" style="plain" id="I0b-et-FGw" userLabel="Accoutn Switching Button">
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<connections>
|
||||
<action selector="AccountSwitchingBarButton_Activated:" destination="2304" id="dZn-bd-bC6"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</leftBarButtonItems>
|
||||
<rightBarButtonItems>
|
||||
<barButtonItem systemItem="add" id="3736">
|
||||
<color key="tintColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@ -216,9 +202,7 @@
|
||||
</navigationItem>
|
||||
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
|
||||
<connections>
|
||||
<outlet property="AccountSwitchingBarButton" destination="I0b-et-FGw" id="KZj-EO-7wd"/>
|
||||
<outlet property="AddBarButton" destination="3736" id="name-outlet-3736"/>
|
||||
<outlet property="CancelBarButton" destination="3735" id="name-outlet-3735"/>
|
||||
<outlet property="MainView" destination="q9o-3n-3xL" id="gjJ-12-71Q"/>
|
||||
<outlet property="NavItem" destination="3734" id="name-outlet-3734"/>
|
||||
<outlet property="OverlayView" destination="Tq0-Ep-tHr" id="igj-R2-gXJ"/>
|
||||
@ -410,19 +394,6 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Verify Master Password" id="NCb-RV-Vqq">
|
||||
<leftBarButtonItems>
|
||||
<barButtonItem title="Cancel" id="Xoh-Zv-hhd">
|
||||
<connections>
|
||||
<action selector="CancelButton_Activated:" destination="cn5-F4-59n" id="1gM-mE-phn"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem title="Account" image="person.2" catalog="system" style="plain" id="nwd-aM-kFD" userLabel="Accoutn Switching Button">
|
||||
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<connections>
|
||||
<action selector="AccountSwitchingBarButton_Activated:" destination="cn5-F4-59n" id="vVZ-IM-rkU"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</leftBarButtonItems>
|
||||
<barButtonItem key="rightBarButtonItem" title="Submit" id="gju-yD-EmI">
|
||||
<connections>
|
||||
<action selector="SubmitButton_Activated:" destination="cn5-F4-59n" id="O1U-fk-BDh"/>
|
||||
@ -430,8 +401,6 @@
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
<connections>
|
||||
<outlet property="AccountSwitchingBarButton" destination="nwd-aM-kFD" id="T8F-CN-2il"/>
|
||||
<outlet property="CancelButton" destination="Xoh-Zv-hhd" id="mwi-4K-maj"/>
|
||||
<outlet property="MainTableView" destination="FcI-Ph-m9e" id="Ybv-5r-VGA"/>
|
||||
<outlet property="NavItem" destination="NCb-RV-Vqq" id="L9b-At-x0A"/>
|
||||
<outlet property="OverlayView" destination="sDX-BN-qLw" id="veu-q4-CeW"/>
|
||||
@ -601,13 +570,12 @@
|
||||
</scene>
|
||||
</scenes>
|
||||
<inferredMetricsTieBreakers>
|
||||
<segue reference="12959"/>
|
||||
<segue reference="12574"/>
|
||||
<segue reference="3731"/>
|
||||
</inferredMetricsTieBreakers>
|
||||
<resources>
|
||||
<image name="check.png" width="90" height="90"/>
|
||||
<image name="logo.png" width="282" height="44"/>
|
||||
<image name="person.2" catalog="system" width="128" height="87"/>
|
||||
<systemColor name="darkTextColor">
|
||||
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
|
@ -1,7 +1,9 @@
|
||||
using Bit.App.Controls;
|
||||
using Bit.Core.Abstractions;
|
||||
using Bit.Core.Utilities;
|
||||
using CoreGraphics;
|
||||
using Microsoft.Maui.Platform;
|
||||
using SkiaSharp.Views.iOS;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Core.Utilities
|
||||
@ -30,12 +32,19 @@ namespace Bit.iOS.Core.Utilities
|
||||
throw new NullReferenceException(nameof(_stateService));
|
||||
}
|
||||
|
||||
var avatarImageSource = new AvatarImageSource(await _stateService.GetActiveUserIdAsync(),
|
||||
await _stateService.GetNameAsync(), await _stateService.GetEmailAsync(),
|
||||
await _stateService.GetAvatarColorAsync());
|
||||
using (var avatarUIImage = await avatarImageSource.GetNativeImageAsync())
|
||||
var avatarInfo = await _stateService.GetActiveUserCustomDataAsync<AvatarInfo?>(a => a?.Profile is null
|
||||
? null
|
||||
: new AvatarInfo(a.Profile.UserId, a.Profile.Name, a.Profile.Email, a.Profile.AvatarColor));
|
||||
|
||||
if (!avatarInfo.HasValue)
|
||||
{
|
||||
return avatarUIImage?.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal) ?? UIImage.GetSystemImage(DEFAULT_SYSTEM_AVATAR_IMAGE);
|
||||
return UIImage.GetSystemImage(DEFAULT_SYSTEM_AVATAR_IMAGE);
|
||||
}
|
||||
|
||||
using (var avatarUIImage = SKAvatarImageHelper.Draw(avatarInfo.Value))
|
||||
{
|
||||
return avatarUIImage?.ToUIImage()?.ImageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal)
|
||||
?? UIImage.GetSystemImage(DEFAULT_SYSTEM_AVATAR_IMAGE);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -100,5 +109,32 @@ namespace Bit.iOS.Core.Utilities
|
||||
containerView.UserInteractionEnabled = !overlayVisible;
|
||||
containerView.Subviews[0].UserInteractionEnabled = !overlayVisible;
|
||||
}
|
||||
|
||||
public async Task<UIControl> CreateAccountSwitchToolbarButtonItemCustomViewAsync()
|
||||
{
|
||||
const float size = 40f;
|
||||
var image = await CreateAvatarImageAsync();
|
||||
var accountSwitchButton = new UIControl(new CGRect(0, 0, size, size));
|
||||
if (image != null)
|
||||
{
|
||||
var accountSwitchAvatarImageView = new UIImageView(new CGRect(0, 0, size, size))
|
||||
{
|
||||
Image = image
|
||||
};
|
||||
accountSwitchButton.AddSubview(accountSwitchAvatarImageView);
|
||||
}
|
||||
|
||||
return accountSwitchButton;
|
||||
}
|
||||
|
||||
public void DisposeAccountSwitchToolbarButtonItemImage(UIControl accountSwitchButton)
|
||||
{
|
||||
if (accountSwitchButton?.Subviews?.FirstOrDefault() is UIImageView accountSwitchImageView && accountSwitchImageView.Image != null)
|
||||
{
|
||||
var img = accountSwitchImageView.Image;
|
||||
accountSwitchImageView.Image = null;
|
||||
img.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,47 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Services;
|
||||
using Microsoft.Maui.Controls.Compatibility.Platform.iOS;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.Core.Utilities
|
||||
{
|
||||
public static class ImageSourceExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the native image from the ImageSource.
|
||||
/// Taken from https://github.com/xamarin/Xamarin.Forms/blob/02dee20dfa1365d0104758e534581d1fa5958990/Xamarin.Forms.Platform.iOS/Renderers/ImageElementManager.cs#L264
|
||||
/// </summary>
|
||||
public static async Task<UIImage> GetNativeImageAsync(this ImageSource source, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
if (source == null || source.IsEmpty)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var handler = Microsoft.Maui.Controls.Internals.Registrar.Registered.GetHandlerForObject<IImageSourceHandler>(source);
|
||||
if (handler == null)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(new InvalidOperationException("GetNativeImageAsync failed cause IImageSourceHandler couldn't be found"));
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
float scale = (float)UIScreen.MainScreen.Scale;
|
||||
return await handler.LoadImageAsync(source, scale: scale, cancelationToken: cancellationToken);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(new OperationCanceledException("GetNativeImageAsync was cancelled"));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LoggerHelper.LogEvenIfCantBeResolved(new InvalidOperationException("GetNativeImageAsync failed", ex));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +1,17 @@
|
||||
using System;
|
||||
using Bit.App.Controls;
|
||||
using Bit.Core.Utilities;
|
||||
using Bit.iOS.Core.Utilities;
|
||||
using System;
|
||||
using UIKit;
|
||||
|
||||
namespace Bit.iOS.ShareExtension
|
||||
{
|
||||
public partial class LockPasswordViewController : Core.Controllers.BaseLockPasswordViewController
|
||||
{
|
||||
UIBarButtonItem _cancelButton;
|
||||
UIControl _accountSwitchButton;
|
||||
AccountSwitchingOverlayView _accountSwitchingOverlayView;
|
||||
AccountSwitchingOverlayHelper _accountSwitchingOverlayHelper;
|
||||
private Lazy<AccountSwitchingOverlayHelper> _accountSwitchingOverlayHelper = new Lazy<AccountSwitchingOverlayHelper>(() => new AccountSwitchingOverlayHelper());
|
||||
|
||||
public LockPasswordViewController()
|
||||
{
|
||||
@ -43,15 +45,33 @@ namespace Bit.iOS.ShareExtension
|
||||
|
||||
public override async void ViewDidLoad()
|
||||
{
|
||||
_cancelButton = new UIBarButtonItem(UIBarButtonSystemItem.Cancel, CancelButton_TouchUpInside);
|
||||
|
||||
base.ViewDidLoad();
|
||||
|
||||
_cancelButton.TintColor = ThemeHelpers.NavBarTextColor;
|
||||
_submitButton.TintColor = ThemeHelpers.NavBarTextColor;
|
||||
|
||||
_accountSwitchingOverlayHelper = new AccountSwitchingOverlayHelper();
|
||||
_accountSwitchingButton.Image = await _accountSwitchingOverlayHelper.CreateAvatarImageAsync();
|
||||
_accountSwitchButton = await _accountSwitchingOverlayHelper.Value.CreateAccountSwitchToolbarButtonItemCustomViewAsync();
|
||||
_accountSwitchButton.TouchUpInside += AccountSwitchedButton_TouchUpInside;
|
||||
|
||||
_accountSwitchingOverlayView = _accountSwitchingOverlayHelper.CreateAccountSwitchingOverlayView(_overlayView);
|
||||
_navItem.SetLeftBarButtonItems(new UIBarButtonItem[]
|
||||
{
|
||||
_cancelButton,
|
||||
new UIBarButtonItem(_accountSwitchButton)
|
||||
}, false);
|
||||
|
||||
_accountSwitchingOverlayView = _accountSwitchingOverlayHelper.Value.CreateAccountSwitchingOverlayView(_overlayView);
|
||||
}
|
||||
|
||||
private void CancelButton_TouchUpInside(object sender, EventArgs e)
|
||||
{
|
||||
Cancel();
|
||||
}
|
||||
|
||||
private void AccountSwitchedButton_TouchUpInside(object sender, EventArgs e)
|
||||
{
|
||||
_accountSwitchingOverlayHelper.Value.OnToolbarItemActivated(_accountSwitchingOverlayView, _overlayView);
|
||||
}
|
||||
|
||||
protected override void UpdateNavigationBarTheme()
|
||||
@ -59,21 +79,11 @@ namespace Bit.iOS.ShareExtension
|
||||
UpdateNavigationBarTheme(_navBar);
|
||||
}
|
||||
|
||||
partial void AccountSwitchingButton_Activated(UIBarButtonItem sender)
|
||||
{
|
||||
_accountSwitchingOverlayHelper.OnToolbarItemActivated(_accountSwitchingOverlayView, _overlayView);
|
||||
}
|
||||
|
||||
partial void SubmitButton_Activated(UIBarButtonItem sender)
|
||||
{
|
||||
CheckPasswordAsync().FireAndForget();
|
||||
}
|
||||
|
||||
partial void CancelButton_Activated(UIBarButtonItem sender)
|
||||
{
|
||||
Cancel();
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
@ -82,11 +92,11 @@ namespace Bit.iOS.ShareExtension
|
||||
{
|
||||
TableView.Source?.Dispose();
|
||||
}
|
||||
if (_accountSwitchingButton?.Image != null)
|
||||
if (_accountSwitchButton != null)
|
||||
{
|
||||
var img = _accountSwitchingButton.Image;
|
||||
_accountSwitchingButton.Image = null;
|
||||
img.Dispose();
|
||||
_accountSwitchingOverlayHelper.Value.DisposeAccountSwitchToolbarButtonItemImage(_accountSwitchButton);
|
||||
|
||||
_accountSwitchButton.TouchUpInside -= AccountSwitchedButton_TouchUpInside;
|
||||
}
|
||||
if (_accountSwitchingOverlayView != null && _overlayView?.Subviews != null)
|
||||
{
|
||||
|
@ -12,12 +12,6 @@ namespace Bit.iOS.ShareExtension
|
||||
[Register ("LockPasswordViewController")]
|
||||
partial class LockPasswordViewController
|
||||
{
|
||||
[Outlet]
|
||||
UIKit.UIBarButtonItem _accountSwitchingButton { get; set; }
|
||||
|
||||
[Outlet]
|
||||
UIKit.UIBarButtonItem _cancelButton { get; set; }
|
||||
|
||||
[Outlet]
|
||||
UIKit.UITableView _mainTableView { get; set; }
|
||||
|
||||
@ -33,32 +27,21 @@ namespace Bit.iOS.ShareExtension
|
||||
[Outlet]
|
||||
UIKit.UIBarButtonItem _submitButton { get; set; }
|
||||
|
||||
[Action ("AccountSwitchingButton_Activated:")]
|
||||
partial void AccountSwitchingButton_Activated (UIKit.UIBarButtonItem sender);
|
||||
|
||||
[Action ("CancelButton_Activated:")]
|
||||
partial void CancelButton_Activated (UIKit.UIBarButtonItem sender);
|
||||
|
||||
[Action ("SubmitButton_Activated:")]
|
||||
partial void SubmitButton_Activated (UIKit.UIBarButtonItem sender);
|
||||
|
||||
void ReleaseDesignerOutlets ()
|
||||
{
|
||||
if (_accountSwitchingButton != null) {
|
||||
_accountSwitchingButton.Dispose ();
|
||||
_accountSwitchingButton = null;
|
||||
}
|
||||
|
||||
if (_cancelButton != null) {
|
||||
_cancelButton.Dispose ();
|
||||
_cancelButton = null;
|
||||
}
|
||||
|
||||
if (_mainTableView != null) {
|
||||
_mainTableView.Dispose ();
|
||||
_mainTableView = null;
|
||||
}
|
||||
|
||||
if (_navBar != null) {
|
||||
_navBar.Dispose ();
|
||||
_navBar = null;
|
||||
}
|
||||
|
||||
if (_navItem != null) {
|
||||
_navItem.Dispose ();
|
||||
_navItem = null;
|
||||
@ -73,11 +56,6 @@ namespace Bit.iOS.ShareExtension
|
||||
_submitButton.Dispose ();
|
||||
_submitButton = null;
|
||||
}
|
||||
|
||||
if (_navBar != null) {
|
||||
_navBar.Dispose ();
|
||||
_navBar = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="2vH-Do-uhk">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="2vH-Do-uhk">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
@ -14,11 +14,11 @@
|
||||
<objects>
|
||||
<viewController id="bHU-LX-EpF" customClass="LoadingViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="z2O-Vp-jY9">
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="808"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="804"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" image="logo.png" translatesAutoresizingMaskIntoConstraints="NO" id="Zdy-yw-n0p">
|
||||
<rect key="frame" x="66" y="352" width="282" height="44"/>
|
||||
<rect key="frame" x="66" y="350" width="282" height="44"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="jNx-Vd-K6U"/>
|
||||
@ -41,7 +41,7 @@
|
||||
<objects>
|
||||
<navigationController definesPresentationContext="YES" id="2vH-Do-uhk" customClass="ExtensionNavigationController" sceneMemberID="viewController">
|
||||
<navigationBar key="navigationBar" hidden="YES" contentMode="scaleToFill" translucent="NO" id="JoO-jQ-16M">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="48" width="414" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
@ -61,30 +61,17 @@
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="18" estimatedSectionHeaderHeight="-1" sectionFooterHeight="18" estimatedSectionFooterHeight="-1" translatesAutoresizingMaskIntoConstraints="NO" id="M1A-84-x5l">
|
||||
<rect key="frame" x="0.0" y="88" width="414" height="774"/>
|
||||
<rect key="frame" x="0.0" y="92" width="414" height="770"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</tableView>
|
||||
<view userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ijE-Pa-OBq" userLabel="OverlayView">
|
||||
<rect key="frame" x="0.0" y="88" width="414" height="774"/>
|
||||
<rect key="frame" x="0.0" y="92" width="414" height="770"/>
|
||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</view>
|
||||
<navigationBar contentMode="scaleToFill" translucent="NO" translatesAutoresizingMaskIntoConstraints="NO" id="fav-Fz-6ZK">
|
||||
<rect key="frame" x="0.0" y="44" width="414" height="44"/>
|
||||
<rect key="frame" x="0.0" y="48" width="414" height="44"/>
|
||||
<items>
|
||||
<navigationItem title="Verify Master Password" id="aka-In-IYk">
|
||||
<leftBarButtonItems>
|
||||
<barButtonItem title="Cancel" id="LrG-Qx-w4Q">
|
||||
<connections>
|
||||
<action selector="CancelButton_Activated:" destination="Vi7-LV-nWW" id="qyZ-i9-Dwz"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem title="Item" image="person.2" catalog="system" style="plain" id="nlD-Xn-HtM" userLabel="Account Switching Button">
|
||||
<color key="tintColor" systemColor="systemBackgroundColor"/>
|
||||
<connections>
|
||||
<action selector="AccountSwitchingButton_Activated:" destination="Vi7-LV-nWW" id="G3U-rv-UOl"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</leftBarButtonItems>
|
||||
<barButtonItem key="rightBarButtonItem" title="Submit" id="oQD-QK-YPB">
|
||||
<connections>
|
||||
<action selector="SubmitButton_Activated:" destination="Vi7-LV-nWW" id="DgO-TS-MPf"/>
|
||||
@ -116,8 +103,6 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<connections>
|
||||
<outlet property="_accountSwitchingButton" destination="nlD-Xn-HtM" id="SSG-zv-bAc"/>
|
||||
<outlet property="_cancelButton" destination="LrG-Qx-w4Q" id="aag-ZZ-Ifs"/>
|
||||
<outlet property="_mainTableView" destination="M1A-84-x5l" id="pA4-ao-Fhu"/>
|
||||
<outlet property="_navBar" destination="fav-Fz-6ZK" id="Q9p-Dw-ipx"/>
|
||||
<outlet property="_navItem" destination="aka-In-IYk" id="www-Lt-x1g"/>
|
||||
@ -132,7 +117,6 @@
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="logo.png" width="282" height="44"/>
|
||||
<image name="person.2" catalog="system" width="128" height="81"/>
|
||||
<systemColor name="systemBackgroundColor">
|
||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
</systemColor>
|
||||
|
Loading…
Reference in New Issue
Block a user