123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text.RegularExpressions;
- using UnityEditor;
- using UnityEditorInternal;
- using UnityEngine;
- using VRTK;
- [InitializeOnLoad]
- public sealed class VRTK_UpdatePrompt : EditorWindow
- {
- [Serializable]
- private sealed class LatestRelease
- {
- [NonSerialized]
- public Version version;
- [NonSerialized]
- public DateTime publishedDateTime;
- [NonSerialized]
- public List<string> changelogPages;
- #pragma warning disable 649
- public string html_url;
- public string tag_name;
- public string name;
- public string published_at;
- public string zipball_url;
- public string body;
- #pragma warning restore 649
- public static LatestRelease CreateFromJSON(string json)
- {
- LatestRelease latestRelease = JsonUtility.FromJson<LatestRelease>(json);
- latestRelease.version = new Version(latestRelease.tag_name);
- latestRelease.publishedDateTime = DateTime.Parse(latestRelease.published_at);
- string changelog = latestRelease.body;
- latestRelease.body = null;
- changelog = Regex.Replace(changelog, @"(?<!(\r\n){2}) \*.*\*{2}(.*)\*{2}", "\n<size=13>$2</size>");
- changelog = Regex.Replace(changelog, @"(\r\n){2} \*.*\*{2}(.*)\*{2}", "\n\n<size=13>$2</size>");
- changelog = new Regex(@"(#+)\s?(.*)\b").Replace(
- changelog,
- match => string.Format(
- "<size={0}>{1}</size>",
- 30 - match.Groups[1].Value.Length * 6,
- match.Groups[2].Value
- )
- );
- changelog = changelog.Replace(" *", "*");
- // Each char gets turned into two triangles and the mesh vertices limit is 2^16.
- // Let's use another 100 to be on the safe side.
- const int textLengthLimit = 65536 / 4 - 100;
- latestRelease.changelogPages = new List<string>((int)Mathf.Ceil(changelog.Length / (float)textLengthLimit));
- while (true)
- {
- if (changelog.Length > textLengthLimit)
- {
- int startIndex = Math.Min(changelog.Length, textLengthLimit);
- int lastIndexOf = changelog.LastIndexOf("\n", startIndex, StringComparison.Ordinal);
- if (lastIndexOf == -1)
- {
- lastIndexOf = startIndex;
- }
- latestRelease.changelogPages.Add(changelog.Substring(0, lastIndexOf));
- changelog = changelog.Substring(lastIndexOf).TrimStart('\n', '\r');
- }
- else
- {
- latestRelease.changelogPages.Add(changelog);
- break;
- }
- }
- return latestRelease;
- }
- }
- private const string remoteURL = "https://api.github.com/repos/thestonefox/vrtk/releases/latest";
- private const string assetStoreURL = "/content/64131";
- private const string hidePromptKeyFormat = "VRTK.HideVersionPrompt.v{0}";
- private const string lastCheckKey = "VRTK.VersionPromptUpdate";
- private const int checkUpdateHours = 6;
- private static bool isManualCheck;
- private static bool versionChecked;
- private static WWW versionResource;
- private static LatestRelease latestRelease;
- private static VRTK_UpdatePrompt promptWindow;
- private static Vector2 scrollPosition;
- private static Vector2 changelogScrollPosition;
- private static float changelogWidth;
- private static int changelogPageIndex;
- private static bool isChangelogFoldOut = true;
- static VRTK_UpdatePrompt()
- {
- EditorApplication.update += CheckForUpdate;
- }
- public void OnGUI()
- {
- using (GUILayout.ScrollViewScope scrollViewScope = new GUILayout.ScrollViewScope(scrollPosition))
- {
- scrollPosition = scrollViewScope.scrollPosition;
- if (versionResource != null && !versionResource.isDone)
- {
- EditorGUILayout.HelpBox("Checking for updates...", MessageType.Info);
- return;
- }
- if (latestRelease == null)
- {
- EditorGUILayout.HelpBox("There was a problem checking for updates.", MessageType.Error);
- DrawCheckAgainButton();
- return;
- }
- string newVersionName = latestRelease.name == string.Format("Version {0}", latestRelease.version)
- ? string.Empty
- : string.Format(" \"{0}\"", latestRelease.name);
- bool isUpToDate = VRTK_Defines.CurrentVersion >= latestRelease.version;
- EditorGUILayout.HelpBox(
- string.Format(
- "{0}.\n\nInstalled Version: {1}\nAvailable version: {2}{3} (published on {4})",
- isUpToDate ? "Already up to date" : "A new version of VRTK is available",
- VRTK_Defines.CurrentVersion,
- latestRelease.version,
- newVersionName,
- latestRelease.publishedDateTime.ToLocalTime()),
- isUpToDate ? MessageType.Info : MessageType.Warning);
- DrawCheckAgainButton();
- isChangelogFoldOut = EditorGUILayout.Foldout(isChangelogFoldOut, "Changelog", true);
- if (isChangelogFoldOut)
- {
- using (new EditorGUILayout.HorizontalScope())
- {
- GUILayout.Space(10);
- using (new EditorGUILayout.VerticalScope())
- {
- VRTK_EditorUtilities.DrawScrollableSelectableLabel(
- ref changelogScrollPosition,
- ref changelogWidth,
- latestRelease.changelogPages[changelogPageIndex],
- new GUIStyle(EditorStyles.textArea)
- {
- richText = true
- });
- if (latestRelease.changelogPages.Count > 0)
- {
- using (new EditorGUILayout.HorizontalScope())
- {
- using (new EditorGUI.DisabledGroupScope(changelogPageIndex == 0))
- {
- if (GUILayout.Button("Previous Page"))
- {
- changelogPageIndex = Math.Max(0, --changelogPageIndex);
- changelogScrollPosition = Vector3.zero;
- }
- }
- using (new EditorGUI.DisabledGroupScope(changelogPageIndex == latestRelease.changelogPages.Count - 1))
- {
- if (GUILayout.Button("Next Page"))
- {
- changelogPageIndex = Math.Min(latestRelease.changelogPages.Count - 1, ++changelogPageIndex);
- changelogScrollPosition = Vector3.zero;
- }
- }
- }
- }
- if (GUILayout.Button("View on GitHub"))
- {
- Application.OpenURL(latestRelease.html_url);
- }
- }
- }
- }
- if (isUpToDate)
- {
- return;
- }
- GUILayout.FlexibleSpace();
- VRTK_EditorUtilities.AddHeader("Get Latest Version");
- using (new EditorGUILayout.HorizontalScope())
- {
- if (GUILayout.Button("From Asset Store"))
- {
- AssetStore.Open(assetStoreURL);
- Close();
- }
- if (GUILayout.Button("From GitHub"))
- {
- Application.OpenURL(latestRelease.zipball_url);
- }
- }
- using (EditorGUI.ChangeCheckScope changeCheckScope = new EditorGUI.ChangeCheckScope())
- {
- string key = string.Format(hidePromptKeyFormat, latestRelease.version);
- bool hideToggle = EditorPrefs.HasKey(key);
- hideToggle = GUILayout.Toggle(hideToggle, "Do not prompt for this version again.");
- if (changeCheckScope.changed)
- {
- if (hideToggle)
- {
- EditorPrefs.SetBool(key, true);
- }
- else
- {
- EditorPrefs.DeleteKey(key);
- }
- }
- }
- }
- }
- private static void DrawCheckAgainButton()
- {
- if (GUILayout.Button("Check again"))
- {
- CheckManually();
- }
- }
- private static void CheckForUpdate()
- {
- changelogScrollPosition = Vector3.zero;
- changelogWidth = 0;
- changelogPageIndex = 0;
- if (isManualCheck)
- {
- ShowWindow();
- }
- else
- {
- if (versionChecked)
- {
- EditorApplication.update -= CheckForUpdate;
- return;
- }
- if (EditorPrefs.HasKey(lastCheckKey))
- {
- string lastCheckTicksString = EditorPrefs.GetString(lastCheckKey);
- DateTime lastCheckDateTime = new DateTime(Convert.ToInt64(lastCheckTicksString));
- if (lastCheckDateTime.AddHours(checkUpdateHours) >= DateTime.UtcNow)
- {
- versionChecked = true;
- return;
- }
- }
- }
- versionResource = versionResource == null ? new WWW(remoteURL) : versionResource;
- if (!versionResource.isDone)
- {
- return;
- }
- EditorApplication.update -= CheckForUpdate;
- if (string.IsNullOrEmpty(versionResource.error))
- {
- latestRelease = LatestRelease.CreateFromJSON(versionResource.text);
- }
- versionResource.Dispose();
- versionResource = null;
- versionChecked = true;
- EditorPrefs.SetString(lastCheckKey, DateTime.UtcNow.Ticks.ToString());
- // Clean up the existing hidePromptKeys (except the one for the current version)
- new[] { VRTK_Defines.CurrentVersion }
- .Concat(VRTK_Defines.PreviousVersions)
- .Where(version => latestRelease == null || version != latestRelease.version)
- .Select(version => string.Format(hidePromptKeyFormat, version))
- .Where(EditorPrefs.HasKey)
- .ToList()
- .ForEach(EditorPrefs.DeleteKey);
- if (!isManualCheck
- && latestRelease != null
- && (VRTK_Defines.CurrentVersion >= latestRelease.version
- || EditorPrefs.HasKey(string.Format(hidePromptKeyFormat, latestRelease.version))))
- {
- return;
- }
- ShowWindow();
- isManualCheck = false;
- }
- private static void ShowWindow()
- {
- if (promptWindow != null)
- {
- promptWindow.ShowUtility();
- promptWindow.Repaint();
- return;
- }
- promptWindow = GetWindow<VRTK_UpdatePrompt>(true);
- promptWindow.titleContent = new GUIContent("VRTK Update");
- }
- [MenuItem("Window/VRTK/Check for Updates")]
- private static void CheckManually()
- {
- isManualCheck = true;
- if (versionResource == null)
- {
- EditorApplication.update += CheckForUpdate;
- }
- }
- }
|