diff --git a/src/App/App.csproj b/src/App/App.csproj
index 4de5cea2a..63f1a9b76 100644
--- a/src/App/App.csproj
+++ b/src/App/App.csproj
@@ -99,7 +99,6 @@
-
diff --git a/src/Core/Controls/AuthenticatorViewCell/AuthenticatorViewCell.xaml b/src/Core/Controls/AuthenticatorViewCell/AuthenticatorViewCell.xaml
index 99c56791c..b93603bea 100644
--- a/src/Core/Controls/AuthenticatorViewCell/AuthenticatorViewCell.xaml
+++ b/src/Core/Controls/AuthenticatorViewCell/AuthenticatorViewCell.xaml
@@ -18,17 +18,16 @@
-
_iconImage;
+ protected override Image Icon => _iconImage;
protected override IconLabel IconPlaceholder => _iconPlaceholderImage;
+
+ private async void Image_OnLoaded(object sender, EventArgs e)
+ {
+ if (Handler?.MauiContext == null) { return; }
+ if (_iconImage?.Source == null) { return; }
+
+ try
+ {
+ var result = await _iconImage.Source.GetPlatformImageAsync(Handler.MauiContext);
+ if (result == null)
+ {
+ Icon_Error(sender, e);
+ }
+ else
+ {
+ Icon_Success(sender, e);
+ }
+ }
+ catch (InvalidOperationException) //Can occur with incorrect/malformed uris
+ {
+ Icon_Error(sender, e);
+ }
+ catch (Exception ex)
+ {
+ LoggerHelper.LogEvenIfCantBeResolved(ex);
+ Icon_Error(sender, e);
+ }
+ }
}
}
diff --git a/src/Core/Controls/CachedImage.cs b/src/Core/Controls/CachedImage.cs
deleted file mode 100644
index 3f95dc1bf..000000000
--- a/src/Core/Controls/CachedImage.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-namespace Bit.App.Controls
-{
-#if !UT
- public class CachedImage : FFImageLoading.Maui.CachedImage
- {
- }
-#else
- ///
- /// Given that FFImageLoading package doesn't support net8.0 then for Unit tests projects to build and run correctly
- /// we need to not include the reference to FFImageLoading and therefore wrap this class
- /// to provide a stub one that does nothing so this project doesn't break and we can run the tests.
- ///
- public class CachedImage : View
- {
- public static readonly BindableProperty SourceProperty = BindableProperty.Create(
- nameof(Source), typeof(ImageSource), typeof(CachedImage));
-
- public static readonly BindableProperty AspectProperty = BindableProperty.Create(
- nameof(Aspect), typeof(Aspect), typeof(CachedImage));
-
- public bool BitmapOptimizations { get; set; }
- public string ErrorPlaceholder { get; set; }
- public string LoadingPlaceholder { get; set; }
-
- public ImageSource Source
- {
- get { return (ImageSource)GetValue(SourceProperty); }
- set { SetValue(SourceProperty, value); }
- }
- public Aspect Aspect
- {
- get { return (Aspect)GetValue(AspectProperty); }
- set { SetValue(AspectProperty, value); }
- }
-
- public bool IsLoading { get; set; }
-
- public event EventHandler Success;
- public event EventHandler Error;
- }
-#endif
-}
diff --git a/src/Core/Controls/CipherViewCell/BaseCipherViewCell.cs b/src/Core/Controls/CipherViewCell/BaseCipherViewCell.cs
index 78dbf82ad..baa952127 100644
--- a/src/Core/Controls/CipherViewCell/BaseCipherViewCell.cs
+++ b/src/Core/Controls/CipherViewCell/BaseCipherViewCell.cs
@@ -4,7 +4,7 @@ namespace Bit.App.Controls
{
public abstract class BaseCipherViewCell : ExtendedGrid
{
- protected virtual CachedImage Icon { get; }
+ protected virtual Image Icon { get; }
protected virtual IconLabel IconPlaceholder { get; }
@@ -15,7 +15,7 @@ public abstract class BaseCipherViewCell : ExtendedGrid
// the app would crash because there can't be any lock files by the app when it gets suspended.
// So, the approach has changed to reuse the IconLabel default icon to use it for these placeholders
// as well. In order to do that both icon controls change their visibility dynamically here reacting to
- // CachedImage events and binding context changes.
+ // Image OnLoaded event and binding context changes.
protected override void OnBindingContextChanged()
{
@@ -47,8 +47,7 @@ private void UpdateIconImages(bool showIcon)
});
}
-#if !UT
- public void Icon_Success(object sender, FFImageLoading.Maui.CachedImageEvents.SuccessEventArgs e)
+ public void Icon_Success(object sender, EventArgs e)
{
if (BindingContext is CipherItemViewModel cipherItemVM)
{
@@ -62,7 +61,7 @@ public void Icon_Success(object sender, FFImageLoading.Maui.CachedImageEvents.Su
}
}
- public void Icon_Error(object sender, FFImageLoading.Maui.CachedImageEvents.ErrorEventArgs e)
+ public void Icon_Error(object sender, EventArgs e)
{
if (BindingContext is CipherItemViewModel cipherItemVM)
{
@@ -74,38 +73,5 @@ public void Icon_Error(object sender, FFImageLoading.Maui.CachedImageEvents.Erro
IconPlaceholder.IsVisible = true;
});
}
-#else
- private void Icon_Success(object sender, EventArgs e) {}
- private void Icon_Error(object sender, EventArgs e) {}
-#endif
- }
-
- public class StubBaseCipherViewCellSoLinkerDoesntRemoveMethods : BaseCipherViewCell
- {
- protected override CachedImage Icon => new CachedImage();
- protected override IconLabel IconPlaceholder => new IconLabel();
-
- public static void CallThisSoLinkerDoesntRemoveMethods()
- {
-#if !UT
- var stub = new StubBaseCipherViewCellSoLinkerDoesntRemoveMethods();
-
- try
- {
- stub.Icon_Success(stub, new FFImageLoading.Maui.CachedImageEvents.SuccessEventArgs(new FFImageLoading.Work.ImageInformation(), FFImageLoading.Work.LoadingResult.Disk));
- }
- catch (Exception)
- {
- }
-
- try
- {
- stub.Icon_Error(stub, new FFImageLoading.Maui.CachedImageEvents.ErrorEventArgs(new InvalidOperationException("stub")));
- }
- catch (Exception)
- {
- }
-#endif
- }
}
}
diff --git a/src/Core/Controls/CipherViewCell/CipherViewCell.xaml b/src/Core/Controls/CipherViewCell/CipherViewCell.xaml
index 4a8ebaeba..99da933aa 100644
--- a/src/Core/Controls/CipherViewCell/CipherViewCell.xaml
+++ b/src/Core/Controls/CipherViewCell/CipherViewCell.xaml
@@ -29,18 +29,17 @@
-
diff --git a/src/Core/Controls/CipherViewCell/CipherViewCell.xaml.cs b/src/Core/Controls/CipherViewCell/CipherViewCell.xaml.cs
index fd163bce3..ed6b78339 100644
--- a/src/Core/Controls/CipherViewCell/CipherViewCell.xaml.cs
+++ b/src/Core/Controls/CipherViewCell/CipherViewCell.xaml.cs
@@ -1,6 +1,7 @@
using System.Windows.Input;
using Bit.App.Abstractions;
using Bit.App.Pages;
+using Bit.Core.Services;
using Bit.Core.Utilities;
namespace Bit.App.Controls
@@ -23,7 +24,7 @@ public CipherViewCell()
_iconImage.HeightRequest = ICON_IMAGE_DEFAULT_WIDTH * fontScale;
}
- protected override CachedImage Icon => _iconImage;
+ protected override Image Icon => _iconImage;
protected override IconLabel IconPlaceholder => _iconPlaceholderImage;
@@ -40,5 +41,33 @@ private void MoreButton_Clicked(object sender, EventArgs e)
ButtonCommand?.Execute(cipherItem.Cipher);
}
}
+
+ private async void Image_OnLoaded(object sender, EventArgs e)
+ {
+ if (Handler?.MauiContext == null) { return; }
+ if (_iconImage?.Source == null) { return; }
+
+ try
+ {
+ var result = await _iconImage.Source.GetPlatformImageAsync(Handler.MauiContext);
+ if (result == null)
+ {
+ Icon_Error(sender, e);
+ }
+ else
+ {
+ Icon_Success(sender, e);
+ }
+ }
+ catch (InvalidOperationException) //Can occur with incorrect/malformed uris
+ {
+ Icon_Error(sender, e);
+ }
+ catch (Exception ex)
+ {
+ LoggerHelper.LogEvenIfCantBeResolved(ex);
+ Icon_Error(sender, e);
+ }
+ }
}
}
diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj
index 3f880f911..09db4bf31 100644
--- a/src/Core/Core.csproj
+++ b/src/Core/Core.csproj
@@ -48,7 +48,6 @@
-
diff --git a/src/Core/MauiProgram.cs b/src/Core/MauiProgram.cs
index 43fdfd843..5020dd82a 100644
--- a/src/Core/MauiProgram.cs
+++ b/src/Core/MauiProgram.cs
@@ -1,12 +1,8 @@
-using Bit.App.Controls;
+
using Camera.MAUI;
using CommunityToolkit.Maui;
-#if !UT
-using FFImageLoading.Maui;
-#endif
using Microsoft.Extensions.Logging;
using Microsoft.Maui.Controls.Compatibility.Hosting;
-using Microsoft.Maui.Handlers;
using SkiaSharp.Views.Maui.Controls.Hosting;
using AppEffects = Bit.App.Effects;
@@ -26,9 +22,6 @@ public static MauiAppBuilder ConfigureMauiAppBuilder(Action cus
.UseMauiCompatibility()
.UseMauiCameraView()
.UseSkiaSharp()
-#if !UT
- .UseFFImageLoading()
-#endif
.ConfigureEffects(effects =>
{
#if ANDROID
@@ -63,13 +56,6 @@ public static MauiAppBuilder ConfigureMauiAppBuilder(Action cus
builder.Logging.AddDebug();
#endif
- ExplicitlyPreventThingsGetRemovedBecauseOfLinker();
-
return builder;
}
-
- private static void ExplicitlyPreventThingsGetRemovedBecauseOfLinker()
- {
- StubBaseCipherViewCellSoLinkerDoesntRemoveMethods.CallThisSoLinkerDoesntRemoveMethods();
- }
}
diff --git a/src/Core/Pages/Vault/CipherItemViewModel.cs b/src/Core/Pages/Vault/CipherItemViewModel.cs
index a5f094d9d..5136e81d2 100644
--- a/src/Core/Pages/Vault/CipherItemViewModel.cs
+++ b/src/Core/Pages/Vault/CipherItemViewModel.cs
@@ -7,7 +7,7 @@ namespace Bit.App.Pages
public class CipherItemViewModel : ExtendedViewModel, IGroupingsPageListItem
{
private readonly bool _websiteIconsEnabled;
- private string _iconImageSource = string.Empty;
+ private UriImageSource _iconImageSource = null;
public CipherItemViewModel(CipherView cipherView, bool websiteIconsEnabled, bool fuzzyAutofill = false)
{
@@ -27,14 +27,23 @@ public bool ShowIconImage
&& IconImageSource != null;
}
- public string IconImageSource
+ public UriImageSource IconImageSource
{
get
{
- if (_iconImageSource == string.Empty) // default value since icon source can return null
+ if (_iconImageSource == null) // default value since icon source can return null
{
- _iconImageSource = IconImageHelper.GetIconImage(Cipher);
+ var iconImageStr = IconImageHelper.GetIconImage(Cipher);
+ if (string.IsNullOrWhiteSpace(iconImageStr)) { return null; }
+
+ _iconImageSource = new UriImageSource
+ {
+ Uri = new Uri(iconImageStr),
+ CacheValidity = TimeSpan.FromDays(90),
+ CachingEnabled = true
+ };
}
+
return _iconImageSource;
}
}