Files
tverona1 f0838f528a Fix loading VectorDrawable icons
Fix loading VectorDrawable icons
2019-12-15 13:36:45 -08:00

163 lines
5.4 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace QuestAppLauncher
{
public class AppEntry : MonoBehaviour
{
// Sprite gameobject
public GameObject sprite = null;
public Image image = null;
public AspectRatioFitter aspectRatioFitter = null;
// TMP text
public TextMeshProUGUI text;
// Scroll view transform
public RectTransform scrollViewTransform;
// App entry contents
public string packageId;
public string appName;
public string externalIconPath = null;
public int installedApkIndex = -1;
public bool isRenameMode;
public bool dynamicallyLoadIcon;
const int MAX_FRAME_DELAYS = 35;
private float lastPos = -1f;
private bool isIconLoaded = false;
private int curFrameDelay = 0;
private int maxFrameDelays = 0;
private float maxDistance = 0f;
private System.Random rand = new System.Random();
// Start is called before the first frame update
void Start()
{
// Calculate max distance outside the visible scroll area, beyond which we'll unload the icon to reduce memory
this.maxDistance = 1.5f * this.scrollViewTransform.rect.size.y;
// Calculate the maximum frame delays when populating this icon; used to stagger loading of icons in the visible scroll area
this.maxFrameDelays = this.rand.Next(MAX_FRAME_DELAYS);
}
// Update is called once per frame
async void Update()
{
if (!this.dynamicallyLoadIcon || null == this.scrollViewTransform ||
(this.externalIconPath == null && this.installedApkIndex == -1))
{
return;
}
var localPos = this.scrollViewTransform.InverseTransformPoint(this.transform.position).y;
if (Mathf.Abs(localPos) < this.maxDistance)
{
// Don't bother loading icons while we're scrolling
if (this.lastPos == -1)
{
this.lastPos = localPos;
return;
}
if (this.lastPos != localPos)
{
this.lastPos = localPos;
return;
}
// We're within max distance, so show the icon after some delay (to stagger loading of icons)
if (this.curFrameDelay < this.maxFrameDelays)
{
this.curFrameDelay++;
return;
}
this.maxFrameDelays = this.rand.Next(MAX_FRAME_DELAYS);
this.curFrameDelay = 0;
if (!this.isIconLoaded)
{
UnloadIcon();
await LoadIcon();
this.isIconLoaded = true;
}
}
else if (this.isIconLoaded)
{
// We're outside max distance, so unload the icon
UnloadIcon();
this.isIconLoaded = false;
}
}
public async Task LoadIcon()
{
var result = await AppProcessor.GetAppIconAsync(this.externalIconPath, this.installedApkIndex, 1024 * 1024);
var image = result.Item1;
var imageWidth = result.Item2;
var imageHeight = result.Item3;
Texture2D texture = null;
if (null == image)
{
Debug.LogFormat("Error loading icon: Path: {0}, Index: {1}", this.externalIconPath, this.installedApkIndex);
return;
}
// Set the icon image
if (imageWidth == 0 || imageHeight == 0)
{
texture = new Texture2D(2, 2, TextureFormat.RGBA32, false);
texture.filterMode = FilterMode.Trilinear;
texture.anisoLevel = 16;
texture.LoadImage(image);
}
else
{
texture = new Texture2D(imageWidth, imageHeight, TextureFormat.ARGB32, false);
texture.filterMode = FilterMode.Trilinear;
texture.anisoLevel = 16;
texture.LoadRawTextureData(image);
texture.Apply();
}
var rect = new Rect(0, 0, texture.width, texture.height);
this.image.sprite = Sprite.Create(texture, rect, new Vector2(0.5f, 0.5f));
this.image.color = Color.white;
// Preserve icon's aspect ratio
this.aspectRatioFitter.aspectRatio = (float)texture.width / (float)texture.height;
}
private void UnloadIcon()
{
// We always manually create the sprite's texture object,
// so we must explicitly destroy it.
if (null != this.image.sprite)
{
if (null != this.image.sprite.texture)
{
DestroyImmediate(image.sprite.texture);
}
DestroyImmediate(this.image.sprite);
this.image.sprite = null;
this.image.color = Color.clear;
}
}
private void OnDestroy()
{
Debug.Log("AppEntry.OnDestroy");
UnloadIcon();
}
}
}