You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
5.4 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using WalletConnectUnity.Core;
using WalletConnectUnity.Core.Networking;
namespace WalletConnectUnity.UI
{
public interface IImageHandler<in TImage>
{
void SetImageSprite(TImage image, Sprite sprite);
void ClearImageSprite(TImage image);
}
public static class RemoteSpriteFactory
{
private static readonly Dictionary<string, object> UriSpritesMap = new();
private static readonly Dictionary<Type, object> ImageHandlers = new();
public static void RegisterImageHandler<TImage>(IImageHandler<TImage> handler)
where TImage : class
{
ImageHandlers[typeof(TImage)] = handler;
}
public static RemoteSprite<TImage> GetRemoteSprite<TImage>(string uri)
where TImage : class
{
if (!ImageHandlers.TryGetValue(typeof(TImage), out var handlerObj) || handlerObj is not IImageHandler<TImage> handler)
throw new InvalidOperationException($"No handler registered for type {typeof(TImage).Name}.");
if (UriSpritesMap.TryGetValue(uri, out var spriteObj) && spriteObj is RemoteSprite<TImage> sprite)
{
return sprite;
}
else
{
var newSprite = new RemoteSprite<TImage>(uri, handler);
UriSpritesMap[uri] = newSprite;
return newSprite;
}
}
}
public class RemoteSprite<TImage>
where TImage : class
{
private readonly string _uri;
private bool _isLoading;
private Sprite _sprite;
private bool _isLoaded;
private readonly WCLoadingAnimator _loadingAnimator;
private readonly HashSet<TImage> _subscribedImages = new();
private readonly IImageHandler<TImage> _imageHandler;
internal RemoteSprite(string uri, IImageHandler<TImage> imageHandler)
{
_uri = uri;
_imageHandler = imageHandler;
_loadingAnimator = WCLoadingAnimator.Instance;
}
public void SubscribeImage(TImage image)
{
if (!_isLoaded && !_isLoading)
UnityEventsDispatcher.Instance.StartCoroutine(LoadRemoteSprite());
if (_isLoaded)
{
SetImage(image);
}
else
{
if (_loadingAnimator != null)
_loadingAnimator.Subscribe(image);
}
_subscribedImages.Add(image);
}
public void UnsubscribeImage(TImage image)
{
_imageHandler.ClearImageSprite(image);
_subscribedImages.Remove(image);
}
private void SetImage(TImage image)
{
if (_loadingAnimator != null)
_loadingAnimator.Unsubscribe(image);
_imageHandler.SetImageSprite(image, _sprite);
}
private IEnumerator LoadRemoteSprite()
{
_isLoading = true;
using (var uwr = UnityWebRequestTexture.GetTexture(_uri))
{
uwr.SetWalletConnectRequestHeaders().SetRequestHeader("accept", "image/jpeg,image/png");
yield return uwr.SendWebRequest();
if (uwr.result != UnityWebRequest.Result.Success)
{
Debug.LogWarning($"Failed to load remote sprite from {_uri}: {uwr.error}");
}
else
{
// While UnityWebRequest creates texture in the background (on other thread), some finishing work is done on main thread.
// Skipping a few frames here to let Unity finish its work to reduce CPU spikes.
for (var i = 0; i < 5; i++)
yield return null;
var texture = DownloadHandlerTexture.GetContent(uwr);
var rect = new Rect(0.0f, 0.0f, texture.width, texture.height);
_sprite = Sprite.Create(texture, rect, new Vector2(0.5f, 0.5f), 100.0f);
_isLoaded = true;
foreach (var image in _subscribedImages)
SetImage(image);
}
}
_isLoading = false;
}
}
public static class RemoteSpriteExtensions
{
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
internal static void Initialize()
{
RemoteSpriteFactory.RegisterImageHandler(new ImageHandlerUgui());
RemoteSpriteFactory.RegisterImageHandler(new ImageHandlerUtk());
}
}
public class ImageHandlerUgui : IImageHandler<UnityEngine.UI.Image>
{
public void SetImageSprite(UnityEngine.UI.Image image, Sprite sprite)
{
image.sprite = sprite;
image.color = Color.white;
}
public void ClearImageSprite(UnityEngine.UI.Image image)
{
image.sprite = null;
}
}
public class ImageHandlerUtk : IImageHandler<UnityEngine.UIElements.Image>
{
public void SetImageSprite(UnityEngine.UIElements.Image image, Sprite sprite)
{
image.sprite = sprite;
}
public void ClearImageSprite(UnityEngine.UIElements.Image image)
{
if (image == null)
return;
image.sprite = null;
}
}
}