Fetch Images from the url
In order to retrieve images from the URL, I initially made some modifications to the 'EventsData' class. I incorporated the 'IFetchData' interface because this class is responsible for fetching an icon from the provided URL. I added a few more variables, such as 'IconSprite', and implemented the data missing from the Interface. The updated code now appears as follows:
/// <summary>
/// Data class which will be fetched from the server
/// </summary>
[Serializable]
public class EventsData : IFetchData<Sprite>
{
/// <summary>
/// Event Title
/// </summary>
[JsonProperty("Event Title")]
public string EventTitle;
/// <summary>
/// Icon url where icon will be downloaded
/// </summary>
[JsonProperty("Icon")]
public string IconUrl;
/// <summary>
/// Icon sprite will be placed here after downloading
/// </summary>
public Sprite IconSprite;
/// <summary>
/// Type of reward
/// </summary>
[JsonProperty("Reward Type")]
public RewardType RewardType;
/// <summary>
/// Amount given in the reward
/// </summary>
[JsonProperty("Reward Amount")]
public int RewardAmount;
/// <summary>
/// Description of the event
/// </summary>
public string Description;
/// <summary>
/// Hexcode of the title color
/// </summary>
[JsonProperty("Title Color"), HideInInspector]
public string TitleColorHex;
/// <summary>
/// Hexcode of the body color
/// </summary>
[JsonProperty("Body Color"), HideInInspector]
public string BodyColorHex;
/// <summary>
/// Time of the event
/// </summary>
[JsonProperty("Event Time")]
public TimeSpan EventTime;
/// <summary>
/// Event Type
/// </summary>
[JsonProperty("Event Type")]
public EventType EventType;
/// <summary>
/// Color type of the title
/// </summary>
public Color TitleColor;
/// <summary>
/// Color type of the body
/// </summary>
public Color BodyColor;
/// <summary>
/// Downaloaded data which is sprite
/// </summary>
public Sprite _downloadedData
{
get => IconSprite;
}
/// <summary>
/// Calls when initialize
/// </summary>
public void Init()
{
TitleColor = ParseColor(TitleColorHex);
BodyColor = ParseColor(BodyColorHex);
}
/// <summary>
/// Parse Hexcode to the color type
/// </summary>
/// <param name="HexCode">Hexcode to convert</param>
/// <returns>Color Type of the given hexcode</returns>
Color ParseColor(string HexCode)
{
Color myColor = new Color();
ColorUtility.TryParseHtmlString(HexCode, out myColor);
return myColor;
}
/// <summary>
/// Fetch Icon from the given url
/// </summary>
/// <param name="url">icon url</param>
/// <param name="OnProgress">Raise when downloading is in progress</param>
/// <param name="OnCompleted">Raise when downlaoding is completed</param>
/// <returns></returns>
public IEnumerator FetchData(string url, Action<float, string> OnProgress, Action<bool, Sprite> OnCompleted)
{
UnityWebRequest webRequest = UnityWebRequestTexture.GetTexture(url);
webRequest.SendWebRequest();
while (!webRequest.isDone)
{
OnProgress?.Invoke(webRequest.downloadProgress, EventTitle);
yield return null;
}
switch (webRequest.result)
{
case UnityWebRequest.Result.ConnectionError:
OnCompleted?.Invoke(false, null);
Debug.LogError("Error Downloading Image: " + webRequest.error);
break;
case UnityWebRequest.Result.DataProcessingError:
OnCompleted?.Invoke(false, null);
Debug.LogError("Error Downloading Image: " + webRequest.error);
break;
case UnityWebRequest.Result.ProtocolError:
OnCompleted?.Invoke(false, null);
Debug.LogError("Error Downloading Image: " + webRequest.error);
break;
case UnityWebRequest.Result.Success:
// texture downloaded
Texture2D myTexture = ((DownloadHandlerTexture)webRequest.downloadHandler).texture;
// creating sprite from the downloaded texture
IconSprite = Sprite.Create(myTexture, new Rect(0, 0, myTexture.width, myTexture.height), new Vector2(0.5f, 0.5f));
OnCompleted?.Invoke(true, IconSprite);
break;
}
}
}
The implementation for downloading the image is now complete. The only remaining task is to display a loading indicator while the image is being downloaded. To accomplish this, I made modifications to the 'EventItemUI' by incorporating a loading pool and managing callbacks from the image loading coroutine.
/// <summary>
/// Attached to event Item prefab
/// </summary>
public class EventItemUI : MonoBehaviour
{
/// <summary>
/// Fetch the loading pool of image
/// </summary>
[Inject]
private EventItemLoadingPool _loaderPool;
/// <summary>
/// Data to show on this item
/// </summary>
[SerializeField]
private EventsData _data;
/// <summary>
/// Loading parent of image
/// </summary>
[SerializeField]
private Transform _loaderParent;
/// <summary>
/// UI Title BG
/// </summary>
[Header("UI")]
[SerializeField]
private Image _titleBg;
/// <summary>
/// UI Background BG
/// </summary>
[SerializeField]
private Image _backgroundBg;
/// <summary>
/// UI Icon
/// </summary>
[SerializeField]
private Image _icon;
/// <summary>
/// Title Text
/// </summary>
[SerializeField]
private TextMeshProUGUI _title;
/// <summary>
/// Time left
/// </summary>
[SerializeField]
private TextMeshProUGUI _time;
/// <summary>
/// Description of the item
/// </summary>
[SerializeField]
private TextMeshProUGUI _description;
/// <summary>
/// Button text which shows Active, Coming Soon
/// </summary>
[SerializeField]
private TextMeshProUGUI _buttonText;
/// <summary>
/// Reference of image loader
/// </summary>
private EventItemLoading _loader;
/// <summary>
/// Status of image loading
/// </summary>
private LoadingStatus _loadStatus;
/// <summary>
/// Calls when item is spawned
/// </summary>
/// <param name="parent">Parent to be of this parent</param>
/// <param name="data">data to show on this item</param>
public void Setup(Transform parent, EventsData data)
{
_data = data;
_loadStatus = LoadingStatus.InProgress;
// load icon image
StartCoroutine(_data.FetchData(_data.IconUrl, OnProgress, OnCompleted));
ImageLoadingProgress();
RectTransform transform = GetComponent<RectTransform>();
transform.parent = parent;
SetupUI();
}
/// <summary>
/// Setup UI on the item
/// </summary>
void SetupUI()
{
_titleBg.color = _data.TitleColor;
_backgroundBg.color = _data.BodyColor;
_title.text = _data.EventTitle;
_description.text = _data.Description;
_time.text = string.Format("TimeLeft: \t {0}d {1}h {2}m {3}s", _data.EventTime.Days, _data.EventTime.Hours, _data.EventTime.Minutes, _data.EventTime.Seconds);
_buttonText.text = _data.EventType.ToString();
_icon.sprite = _data.IconSprite != null ? _data.IconSprite : null;
if(_data.EventType == EventType.ComingSoon)
{
_time.gameObject.SetActive(false);
}
else if (_data.EventType == EventType.Expired)
{
_buttonText.transform.parent.gameObject.SetActive(false);
_time.text = _data.EventType.ToString();
}
}
/// <summary>
/// Loading Progress of Image
/// </summary>
void ImageLoadingProgress()
{
if (!_loader && _loadStatus == LoadingStatus.InProgress)
_loader = _loaderPool.Spawn(_loaderParent);
else if (_loader && _loadStatus != LoadingStatus.InProgress)
_loaderPool.Remove(_loader);
}
/// <summary>
/// Calls when progress is on the way
/// </summary>
/// <param name="progress">float value from 0 - 1</param>
/// <param name="info">text of the laoding</param>
void OnProgress(float progress, string info)
{
if (_loader)
_loader.ShowProgress(progress, "Loading Image...");
}
/// <summary>
/// Calls when the downloading is done
/// </summary>
/// <param name="isDone">is download successfull</param>
/// <param name="data">data to download in this case the sprite</param>
void OnCompleted(bool isDone, Sprite data)
{
_loadStatus = isDone ? LoadingStatus.Completed : LoadingStatus.Fail;
if (!isDone)
return;
SetupUI();
ImageLoadingProgress();
}
/// <summary>
/// Item Pool
/// </summary>
public class Pool : MonoMemoryPool<Transform, EventsData, EventItemUI>
{
protected override void Reinitialize(Transform p1, EventsData p2, EventItemUI item)
{
base.Reinitialize(p1, p2, item);
item.Setup(p1, p2);
}
}
}
Following all these steps, the final result appears like this.
Last updated