1
0
mirror of https://github.com/bitwarden/mobile synced 2026-01-04 17:43:17 +00:00

PM-3350 Fix Avatar toolbar icon on extensions to load properly and to take advantage of using directly SkiaSharp to do the native conversion to UIImage. Also improved the toolbar item so that size is set appropriately.

This commit is contained in:
Federico Maccaroni
2024-01-23 17:34:27 -03:00
parent f539bf051d
commit 63904fd303
16 changed files with 350 additions and 400 deletions

View File

@@ -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();
}
}
}
}

View File

@@ -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;
}
}
}