mirror of
https://github.com/imperialsushi/gutterball-3.git
synced 2025-06-15 05:07:42 +00:00
New Version 1.42
Moving cam replay. Fixed the bugs. New Version 1.42 Moving cam replay. Fixed the bugs. New Version 1.42 Moving cam replay, Fixed the bugs.
This commit is contained in:
parent
dcb7df5fd1
commit
1c033119df
7079 changed files with 186851 additions and 48991 deletions
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 06b575597b644fe8ba88495149d01b66
|
||||
timeCreated: 1503684160
|
|
@ -0,0 +1,563 @@
|
|||
/*
|
||||
Copyright (c) 2013 Max Hauser
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
From: https://github.com/maxhauser/semver
|
||||
*/
|
||||
|
||||
using System;
|
||||
#if !NETSTANDARD
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Permissions;
|
||||
#endif
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Semver
|
||||
{
|
||||
/// <summary>
|
||||
/// A semantic version implementation.
|
||||
/// Conforms to v2.0.0 of http://semver.org/
|
||||
/// </summary>
|
||||
#if NETSTANDARD
|
||||
public sealed class SemVersion : IComparable<SemVersion>, IComparable
|
||||
#else
|
||||
[Serializable]
|
||||
internal sealed class SemVersion : IComparable<SemVersion>, IComparable, ISerializable
|
||||
#endif
|
||||
{
|
||||
static Regex parseEx =
|
||||
new Regex(@"^(?<major>\d+)" +
|
||||
@"(\.(?<minor>\d+))?" +
|
||||
@"(\.(?<patch>\d+))?" +
|
||||
@"(\-(?<pre>[0-9A-Za-z\-\.]+))?" +
|
||||
@"(\+(?<build>[0-9A-Za-z\-\.]+))?$",
|
||||
#if NETSTANDARD
|
||||
RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture);
|
||||
#else
|
||||
RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
|
||||
#endif
|
||||
|
||||
#if !NETSTANDARD
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SemVersion" /> class.
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
/// <param name="context"></param>
|
||||
/// <exception cref="ArgumentNullException"></exception>
|
||||
private SemVersion(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
if (info == null) throw new ArgumentNullException("info");
|
||||
var semVersion = Parse(info.GetString("SemVersion"));
|
||||
Major = semVersion.Major;
|
||||
Minor = semVersion.Minor;
|
||||
Patch = semVersion.Patch;
|
||||
Prerelease = semVersion.Prerelease;
|
||||
Build = semVersion.Build;
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SemVersion" /> class.
|
||||
/// </summary>
|
||||
/// <param name="major">The major version.</param>
|
||||
/// <param name="minor">The minor version.</param>
|
||||
/// <param name="patch">The patch version.</param>
|
||||
/// <param name="prerelease">The prerelease version (eg. "alpha").</param>
|
||||
/// <param name="build">The build eg ("nightly.232").</param>
|
||||
public SemVersion(int major, int minor = 0, int patch = 0, string prerelease = "", string build = "")
|
||||
{
|
||||
this.Major = major;
|
||||
this.Minor = minor;
|
||||
this.Patch = patch;
|
||||
|
||||
this.Prerelease = prerelease ?? "";
|
||||
this.Build = build ?? "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SemVersion"/> class.
|
||||
/// </summary>
|
||||
/// <param name="version">The <see cref="System.Version"/> that is used to initialize
|
||||
/// the Major, Minor, Patch and Build properties.</param>
|
||||
public SemVersion(Version version)
|
||||
{
|
||||
if (version == null)
|
||||
throw new ArgumentNullException("version");
|
||||
|
||||
this.Major = version.Major;
|
||||
this.Minor = version.Minor;
|
||||
|
||||
if (version.Revision >= 0)
|
||||
{
|
||||
this.Patch = version.Revision;
|
||||
}
|
||||
|
||||
this.Prerelease = String.Empty;
|
||||
|
||||
if (version.Build > 0)
|
||||
{
|
||||
this.Build = version.Build.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Build = String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the specified string to a semantic version.
|
||||
/// </summary>
|
||||
/// <param name="version">The version string.</param>
|
||||
/// <param name="strict">If set to <c>true</c> minor and patch version are required, else they default to 0.</param>
|
||||
/// <returns>The SemVersion object.</returns>
|
||||
/// <exception cref="System.InvalidOperationException">When a invalid version string is passed.</exception>
|
||||
public static SemVersion Parse(string version, bool strict = false)
|
||||
{
|
||||
var match = parseEx.Match(version);
|
||||
if (!match.Success)
|
||||
{
|
||||
return new SemVersion(0);
|
||||
}
|
||||
|
||||
#if NETSTANDARD
|
||||
var major = int.Parse(match.Groups["major"].Value);
|
||||
#else
|
||||
var major = int.Parse(match.Groups["major"].Value, CultureInfo.InvariantCulture);
|
||||
#endif
|
||||
|
||||
var minorMatch = match.Groups["minor"];
|
||||
int minor = 0;
|
||||
if (minorMatch.Success)
|
||||
{
|
||||
#if NETSTANDARD
|
||||
minor = int.Parse(minorMatch.Value);
|
||||
#else
|
||||
minor = int.Parse(minorMatch.Value, CultureInfo.InvariantCulture);
|
||||
#endif
|
||||
}
|
||||
else if (strict)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid version (no minor version given in strict mode)");
|
||||
}
|
||||
|
||||
var patchMatch = match.Groups["patch"];
|
||||
int patch = 0;
|
||||
if (patchMatch.Success)
|
||||
{
|
||||
#if NETSTANDARD
|
||||
patch = int.Parse(patchMatch.Value);
|
||||
#else
|
||||
patch = int.Parse(patchMatch.Value, CultureInfo.InvariantCulture);
|
||||
#endif
|
||||
}
|
||||
else if (strict)
|
||||
{
|
||||
throw new InvalidOperationException("Invalid version (no patch version given in strict mode)");
|
||||
}
|
||||
|
||||
var prerelease = match.Groups["pre"].Value;
|
||||
var build = match.Groups["build"].Value;
|
||||
|
||||
return new SemVersion(major, minor, patch, prerelease, build);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the specified string to a semantic version.
|
||||
/// </summary>
|
||||
/// <param name="version">The version string.</param>
|
||||
/// <param name="semver">When the method returns, contains a SemVersion instance equivalent
|
||||
/// to the version string passed in, if the version string was valid, or <c>null</c> if the
|
||||
/// version string was not valid.</param>
|
||||
/// <param name="strict">If set to <c>true</c> minor and patch version are required, else they default to 0.</param>
|
||||
/// <returns><c>False</c> when a invalid version string is passed, otherwise <c>true</c>.</returns>
|
||||
public static bool TryParse(string version, out SemVersion semver, bool strict = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
semver = Parse(version, strict);
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
semver = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests the specified versions for equality.
|
||||
/// </summary>
|
||||
/// <param name="versionA">The first version.</param>
|
||||
/// <param name="versionB">The second version.</param>
|
||||
/// <returns>If versionA is equal to versionB <c>true</c>, else <c>false</c>.</returns>
|
||||
public static bool Equals(SemVersion versionA, SemVersion versionB)
|
||||
{
|
||||
if (ReferenceEquals(versionA, null))
|
||||
return ReferenceEquals(versionB, null);
|
||||
return versionA.Equals(versionB);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the specified versions.
|
||||
/// </summary>
|
||||
/// <param name="versionA">The version to compare to.</param>
|
||||
/// <param name="versionB">The version to compare against.</param>
|
||||
/// <returns>If versionA < versionB <c>< 0</c>, if versionA > versionB <c>> 0</c>,
|
||||
/// if versionA is equal to versionB <c>0</c>.</returns>
|
||||
public static int Compare(SemVersion versionA, SemVersion versionB)
|
||||
{
|
||||
if (ReferenceEquals(versionA, null))
|
||||
return ReferenceEquals(versionB, null) ? 0 : -1;
|
||||
return versionA.CompareTo(versionB);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Make a copy of the current instance with optional altered fields.
|
||||
/// </summary>
|
||||
/// <param name="major">The major version.</param>
|
||||
/// <param name="minor">The minor version.</param>
|
||||
/// <param name="patch">The patch version.</param>
|
||||
/// <param name="prerelease">The prerelease text.</param>
|
||||
/// <param name="build">The build text.</param>
|
||||
/// <returns>The new version object.</returns>
|
||||
public SemVersion Change(int? major = null, int? minor = null, int? patch = null,
|
||||
string prerelease = null, string build = null)
|
||||
{
|
||||
return new SemVersion(
|
||||
major ?? this.Major,
|
||||
minor ?? this.Minor,
|
||||
patch ?? this.Patch,
|
||||
prerelease ?? this.Prerelease,
|
||||
build ?? this.Build);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the major version.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The major version.
|
||||
/// </value>
|
||||
public int Major { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the minor version.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The minor version.
|
||||
/// </value>
|
||||
public int Minor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the patch version.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The patch version.
|
||||
/// </value>
|
||||
public int Patch { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pre-release version.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The pre-release version.
|
||||
/// </value>
|
||||
public string Prerelease { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the build version.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The build version.
|
||||
/// </value>
|
||||
public string Build { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="System.String" /> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="System.String" /> that represents this instance.
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
var version = "" + Major + "." + Minor + "." + Patch;
|
||||
if (!String.IsNullOrEmpty(Prerelease))
|
||||
version += "-" + Prerelease;
|
||||
if (!String.IsNullOrEmpty(Build))
|
||||
version += "+" + Build;
|
||||
return version;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the current instance with another object of the same type and returns an integer that indicates
|
||||
/// whether the current instance precedes, follows, or occurs in the same position in the sort order as the
|
||||
/// other object.
|
||||
/// </summary>
|
||||
/// <param name="obj">An object to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// A value that indicates the relative order of the objects being compared.
|
||||
/// The return value has these meanings: Value Meaning Less than zero
|
||||
/// This instance precedes <paramref name="obj" /> in the sort order.
|
||||
/// Zero This instance occurs in the same position in the sort order as <paramref name="obj" />. i
|
||||
/// Greater than zero This instance follows <paramref name="obj" /> in the sort order.
|
||||
/// </returns>
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
return CompareTo((SemVersion)obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares the current instance with another object of the same type and returns an integer that indicates
|
||||
/// whether the current instance precedes, follows, or occurs in the same position in the sort order as the
|
||||
/// other object.
|
||||
/// </summary>
|
||||
/// <param name="other">An object to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// A value that indicates the relative order of the objects being compared.
|
||||
/// The return value has these meanings: Value Meaning Less than zero
|
||||
/// This instance precedes <paramref name="other" /> in the sort order.
|
||||
/// Zero This instance occurs in the same position in the sort order as <paramref name="other" />. i
|
||||
/// Greater than zero This instance follows <paramref name="other" /> in the sort order.
|
||||
/// </returns>
|
||||
public int CompareTo(SemVersion other)
|
||||
{
|
||||
if (ReferenceEquals(other, null))
|
||||
return 1;
|
||||
|
||||
var r = this.CompareByPrecedence(other);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
r = CompareComponent(this.Build, other.Build);
|
||||
return r;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares to semantic versions by precedence. This does the same as a Equals, but ignores the build information.
|
||||
/// </summary>
|
||||
/// <param name="other">The semantic version.</param>
|
||||
/// <returns><c>true</c> if the version precedence matches.</returns>
|
||||
public bool PrecedenceMatches(SemVersion other)
|
||||
{
|
||||
return CompareByPrecedence(other) == 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares to semantic versions by precedence. This does the same as a Equals, but ignores the build information.
|
||||
/// </summary>
|
||||
/// <param name="other">The semantic version.</param>
|
||||
/// <returns>
|
||||
/// A value that indicates the relative order of the objects being compared.
|
||||
/// The return value has these meanings: Value Meaning Less than zero
|
||||
/// This instance precedes <paramref name="other" /> in the version precedence.
|
||||
/// Zero This instance has the same precedence as <paramref name="other" />. i
|
||||
/// Greater than zero This instance has creater precedence as <paramref name="other" />.
|
||||
/// </returns>
|
||||
public int CompareByPrecedence(SemVersion other)
|
||||
{
|
||||
if (ReferenceEquals(other, null))
|
||||
return 1;
|
||||
|
||||
var r = this.Major.CompareTo(other.Major);
|
||||
if (r != 0) return r;
|
||||
|
||||
r = this.Minor.CompareTo(other.Minor);
|
||||
if (r != 0) return r;
|
||||
|
||||
r = this.Patch.CompareTo(other.Patch);
|
||||
if (r != 0) return r;
|
||||
|
||||
r = CompareComponent(this.Prerelease, other.Prerelease, true);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int CompareComponent(string a, string b, bool lower = false)
|
||||
{
|
||||
var aEmpty = String.IsNullOrEmpty(a);
|
||||
var bEmpty = String.IsNullOrEmpty(b);
|
||||
if (aEmpty && bEmpty)
|
||||
return 0;
|
||||
|
||||
if (aEmpty)
|
||||
return lower ? 1 : -1;
|
||||
if (bEmpty)
|
||||
return lower ? -1 : 1;
|
||||
|
||||
var aComps = a.Split('.');
|
||||
var bComps = b.Split('.');
|
||||
|
||||
var minLen = Math.Min(aComps.Length, bComps.Length);
|
||||
for (int i = 0; i < minLen; i++)
|
||||
{
|
||||
var ac = aComps[i];
|
||||
var bc = bComps[i];
|
||||
int anum, bnum;
|
||||
var isanum = Int32.TryParse(ac, out anum);
|
||||
var isbnum = Int32.TryParse(bc, out bnum);
|
||||
int r;
|
||||
if (isanum && isbnum)
|
||||
{
|
||||
r = anum.CompareTo(bnum);
|
||||
if (r != 0) return anum.CompareTo(bnum);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isanum)
|
||||
return -1;
|
||||
if (isbnum)
|
||||
return 1;
|
||||
r = String.CompareOrdinal(ac, bc);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return aComps.Length.CompareTo(bComps.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="System.Object" /> is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(obj, null))
|
||||
return false;
|
||||
|
||||
if (ReferenceEquals(this, obj))
|
||||
return true;
|
||||
|
||||
var other = (SemVersion)obj;
|
||||
|
||||
return this.Major == other.Major &&
|
||||
this.Minor == other.Minor &&
|
||||
this.Patch == other.Patch &&
|
||||
string.Equals(this.Prerelease, other.Prerelease, StringComparison.Ordinal) &&
|
||||
string.Equals(this.Build, other.Build, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int result = this.Major.GetHashCode();
|
||||
result = result * 31 + this.Minor.GetHashCode();
|
||||
result = result * 31 + this.Patch.GetHashCode();
|
||||
result = result * 31 + this.Prerelease.GetHashCode();
|
||||
result = result * 31 + this.Build.GetHashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
#if !NETSTANDARD
|
||||
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
|
||||
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
if (info == null) throw new ArgumentNullException("info");
|
||||
info.AddValue("SemVersion", ToString());
|
||||
}
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Implicit conversion from string to SemVersion.
|
||||
/// </summary>
|
||||
/// <param name="version">The semantic version.</param>
|
||||
/// <returns>The SemVersion object.</returns>
|
||||
public static implicit operator SemVersion(string version)
|
||||
{
|
||||
return SemVersion.Parse(version);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The override of the equals operator.
|
||||
/// </summary>
|
||||
/// <param name="left">The left value.</param>
|
||||
/// <param name="right">The right value.</param>
|
||||
/// <returns>If left is equal to right <c>true</c>, else <c>false</c>.</returns>
|
||||
public static bool operator ==(SemVersion left, SemVersion right)
|
||||
{
|
||||
return SemVersion.Equals(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The override of the un-equal operator.
|
||||
/// </summary>
|
||||
/// <param name="left">The left value.</param>
|
||||
/// <param name="right">The right value.</param>
|
||||
/// <returns>If left is not equal to right <c>true</c>, else <c>false</c>.</returns>
|
||||
public static bool operator !=(SemVersion left, SemVersion right)
|
||||
{
|
||||
return !SemVersion.Equals(left, right);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The override of the greater operator.
|
||||
/// </summary>
|
||||
/// <param name="left">The left value.</param>
|
||||
/// <param name="right">The right value.</param>
|
||||
/// <returns>If left is greater than right <c>true</c>, else <c>false</c>.</returns>
|
||||
public static bool operator >(SemVersion left, SemVersion right)
|
||||
{
|
||||
return SemVersion.Compare(left, right) > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The override of the greater than or equal operator.
|
||||
/// </summary>
|
||||
/// <param name="left">The left value.</param>
|
||||
/// <param name="right">The right value.</param>
|
||||
/// <returns>If left is greater than or equal to right <c>true</c>, else <c>false</c>.</returns>
|
||||
public static bool operator >=(SemVersion left, SemVersion right)
|
||||
{
|
||||
return left == right || left > right;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The override of the less operator.
|
||||
/// </summary>
|
||||
/// <param name="left">The left value.</param>
|
||||
/// <param name="right">The right value.</param>
|
||||
/// <returns>If left is less than right <c>true</c>, else <c>false</c>.</returns>
|
||||
public static bool operator <(SemVersion left, SemVersion right)
|
||||
{
|
||||
return SemVersion.Compare(left, right) < 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The override of the less than or equal operator.
|
||||
/// </summary>
|
||||
/// <param name="left">The left value.</param>
|
||||
/// <param name="right">The right value.</param>
|
||||
/// <returns>If left is less than or equal to right <c>true</c>, else <c>false</c>.</returns>
|
||||
public static bool operator <=(SemVersion left, SemVersion right)
|
||||
{
|
||||
return left == right || left < right;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5075cb5aa3254b099b11b2840d7cd46e
|
||||
timeCreated: 1503684176
|
|
@ -0,0 +1,15 @@
|
|||
namespace Semver
|
||||
{
|
||||
internal static class SemVersionExtension
|
||||
{
|
||||
public static string VersionOnly(this SemVersion version)
|
||||
{
|
||||
return "" + version.Major + "." + version.Minor + "." + version.Patch;
|
||||
}
|
||||
|
||||
public static string ShortVersion(this SemVersion version)
|
||||
{
|
||||
return version.Major + "." + version.Minor;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9f17a0688211d476f8d8c9742bb9f992
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: afd7697844f4142f9aa91471c1fba506
|
||||
folderAsset: yes
|
||||
timeCreated: 1502224642
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1067213df0c64b319bc81e73be809b1a
|
||||
timeCreated: 1505249387
|
|
@ -0,0 +1,17 @@
|
|||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
class ApplicationUtil
|
||||
{
|
||||
public static bool IsPreReleaseVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
var lastToken = Application.unityVersion.Split('.').LastOrDefault();
|
||||
return lastToken.Contains("a") || lastToken.Contains("b");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7ed48dcc992234c659018e00590315b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,30 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
[Serializable]
|
||||
internal class OperationSignal<T> where T: IBaseOperation
|
||||
{
|
||||
public event Action<T> OnOperation = delegate { };
|
||||
|
||||
public T Operation { get; set; }
|
||||
|
||||
public void SetOperation(T operation)
|
||||
{
|
||||
Operation = operation;
|
||||
OnOperation(operation);
|
||||
}
|
||||
|
||||
public void WhenOperation(Action<T> callback)
|
||||
{
|
||||
if (Operation != null)
|
||||
callback(Operation);
|
||||
OnOperation += callback;
|
||||
}
|
||||
|
||||
internal void ResetEvents()
|
||||
{
|
||||
OnOperation = delegate { };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7da0c11c52b4044de81c175887699282
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,19 @@
|
|||
using UnityEngine.Experimental.UIElements;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal static class Resources
|
||||
{
|
||||
private static string TemplateRoot { get { return PackageManagerWindow.ResourcesPath + "Templates"; } }
|
||||
|
||||
private static string TemplatePath(string filename)
|
||||
{
|
||||
return string.Format("{0}/{1}", TemplateRoot, filename);
|
||||
}
|
||||
|
||||
public static VisualElement GetTemplate(string templateFilename)
|
||||
{
|
||||
return AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(TemplatePath(templateFilename)).CloneTree(null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d6a708dbb74414a6dbd60e07d9513c1c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,35 @@
|
|||
using System.Threading;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal class ThreadedDelay
|
||||
{
|
||||
public int Length { get; set; } // In milliseconds
|
||||
public bool IsDone { get; private set; }
|
||||
|
||||
public ThreadedDelay(int length = 0)
|
||||
{
|
||||
Length = length;
|
||||
IsDone = false;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (Length <= 0)
|
||||
{
|
||||
IsDone = true;
|
||||
return;
|
||||
}
|
||||
|
||||
IsDone = false;
|
||||
|
||||
Thread newThread = new Thread(() =>
|
||||
{
|
||||
Thread.Sleep(Length);
|
||||
IsDone = true;
|
||||
});
|
||||
|
||||
newThread.Start();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 490fe93dbc954e3ba3651b7f55eaba70
|
||||
timeCreated: 1505249395
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3385f7527e5be4c65b3a5294e8995ff8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal interface IAddOperation : IBaseOperation
|
||||
{
|
||||
event Action<PackageInfo> OnOperationSuccess;
|
||||
|
||||
PackageInfo PackageInfo { get; }
|
||||
|
||||
void AddPackageAsync(PackageInfo packageInfo, Action<PackageInfo> doneCallbackAction = null, Action<Error> errorCallbackAction = null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3dcbbc060dea46168ffc09a580836240
|
||||
timeCreated: 1504191596
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal interface IBaseOperation
|
||||
{
|
||||
event Action<Error> OnOperationError;
|
||||
event Action OnOperationFinalized;
|
||||
|
||||
bool IsCompleted { get; }
|
||||
|
||||
void Cancel();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2f1849b9179b464381598f68663790d3
|
||||
timeCreated: 1507041169
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal interface IListOperation : IBaseOperation
|
||||
{
|
||||
bool OfflineMode { get; set; }
|
||||
void GetPackageListAsync(Action<IEnumerable<PackageInfo>> doneCallbackAction, Action<Error> errorCallbackAction = null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b7e8a8fb69eacee439474914ea54bf9b
|
||||
timeCreated: 1502913188
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,14 @@
|
|||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// This is the Interface we will use to create the facade we need for testing.
|
||||
/// In the case of the Fake factory, we can create fake operations with doctored data we use for our tests.
|
||||
/// </summary>
|
||||
internal interface IOperationFactory
|
||||
{
|
||||
IListOperation CreateListOperation(bool offlineMode = false);
|
||||
ISearchOperation CreateSearchOperation();
|
||||
IAddOperation CreateAddOperation();
|
||||
IRemoveOperation CreateRemoveOperation();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0a1161a2ab6569948a0aa7899197218c
|
||||
timeCreated: 1502915478
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,11 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal interface IRemoveOperation : IBaseOperation
|
||||
{
|
||||
event Action<PackageInfo> OnOperationSuccess;
|
||||
|
||||
void RemovePackageAsync(PackageInfo package, Action<PackageInfo> doneCallbackAction = null, Action<Error> errorCallbackAction = null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 54e5fc61925bc4ca3b2c1e82dfb35eb5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal interface ISearchOperation : IBaseOperation
|
||||
{
|
||||
void GetAllPackageAsync(Action<IEnumerable<PackageInfo>> doneCallbackAction = null, Action<Error> errorCallbackAction = null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 85dba6b2d7204a7f9a1f976eb0a6b4d2
|
||||
timeCreated: 1508160206
|
|
@ -0,0 +1,24 @@
|
|||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal static class OperationFactory
|
||||
{
|
||||
private static IOperationFactory _instance;
|
||||
|
||||
public static IOperationFactory Instance
|
||||
{
|
||||
get {
|
||||
if (_instance == null)
|
||||
_instance = new UpmOperationFactory ();
|
||||
return _instance;
|
||||
}
|
||||
internal set {
|
||||
_instance = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void Reset()
|
||||
{
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9ec5dc72125424af38a9bfaca532acc8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e53bc96d2d054b8cbc811f0d73e761eb
|
||||
timeCreated: 1504191702
|
|
@ -0,0 +1,222 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
// History of a single package
|
||||
internal class Package : IEquatable<Package>
|
||||
{
|
||||
static public bool ShouldProposeLatestVersions
|
||||
{
|
||||
get
|
||||
{
|
||||
// Until we figure out a way to test this properly, alway show standard behavior
|
||||
// return InternalEditorUtility.IsUnityBeta() && !Unsupported.IsDeveloperMode();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// There can only be one package add/remove operation.
|
||||
private static IBaseOperation addRemoveOperationInstance;
|
||||
|
||||
public static bool AddRemoveOperationInProgress
|
||||
{
|
||||
get { return addRemoveOperationInstance != null && !addRemoveOperationInstance.IsCompleted; }
|
||||
}
|
||||
|
||||
internal const string packageManagerUIName = "com.unity.package-manager-ui";
|
||||
private readonly string packageName;
|
||||
private IEnumerable<PackageInfo> source;
|
||||
|
||||
internal Package(string packageName, IEnumerable<PackageInfo> infos)
|
||||
{
|
||||
if (string.IsNullOrEmpty(packageName))
|
||||
throw new ArgumentException("Cannot be empty or null", "packageName");
|
||||
|
||||
if (!infos.Any())
|
||||
throw new ArgumentException("Cannot be empty", "infos");
|
||||
|
||||
this.packageName = packageName;
|
||||
UpdateSource(infos);
|
||||
}
|
||||
|
||||
internal void UpdateSource(IEnumerable<PackageInfo> source)
|
||||
{
|
||||
this.source = source;
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
if (IsPackageManagerUI)
|
||||
this.source = this.source.Where(p => p != null && p.Version.Major >= 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
public PackageInfo Current { get { return Versions.FirstOrDefault(package => package.IsCurrent); } }
|
||||
|
||||
// This is the latest verified or official release (eg: 1.3.2). Not necessarily the latest verified release (eg: 1.2.4) or that latest candidate (eg: 1.4.0-beta)
|
||||
public PackageInfo LatestUpdate
|
||||
{
|
||||
get
|
||||
{
|
||||
// We want to show the absolute latest when in beta mode
|
||||
if (ShouldProposeLatestVersions)
|
||||
return Latest;
|
||||
|
||||
// Override with current when it's version locked
|
||||
var current = Current;
|
||||
if (current != null && current.IsVersionLocked)
|
||||
return current;
|
||||
|
||||
// Get all the candidates versions (verified, release, preview) that are newer than current
|
||||
var verified = Verified;
|
||||
var latestRelease = LatestRelease;
|
||||
var latestPreview = Versions.LastOrDefault(package => package.IsPreview);
|
||||
var candidates = new List<PackageInfo>
|
||||
{
|
||||
verified,
|
||||
latestRelease,
|
||||
latestPreview,
|
||||
}.Where(package => package != null && (current == null || current == package || current.Version < package.Version)).ToList();
|
||||
|
||||
if (candidates.Contains(verified))
|
||||
return verified;
|
||||
if ((current == null || !current.IsVerified ) && candidates.Contains(latestRelease))
|
||||
return latestRelease;
|
||||
if ((current == null || current.IsPreview) && candidates.Contains(latestPreview))
|
||||
return latestPreview;
|
||||
|
||||
// Show current if it exists, otherwise latest user visible, and then otherwise show the absolute latest
|
||||
return current ?? Latest;
|
||||
}
|
||||
}
|
||||
|
||||
public PackageInfo LatestPatch
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Current == null)
|
||||
return null;
|
||||
|
||||
// Get all version that have the same Major/Minor
|
||||
var versions = Versions.Where(package => package.Version.Major == Current.Version.Major && package.Version.Minor == Current.Version.Minor);
|
||||
|
||||
return versions.LastOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// This is the very latest version, including pre-releases (eg: 1.4.0-beta).
|
||||
internal PackageInfo Latest { get { return Versions.FirstOrDefault(package => package.IsLatest) ?? Versions.LastOrDefault(); } }
|
||||
|
||||
// Returns the current version if it exist, otherwise returns the latest user visible version.
|
||||
internal PackageInfo VersionToDisplay { get { return Current ?? LatestUpdate; } }
|
||||
|
||||
// Every version available for this package
|
||||
internal IEnumerable<PackageInfo> Versions { get { return source.OrderBy(package => package.Version); } }
|
||||
|
||||
// Every version that's not a pre-release (eg: not beta/alpha/preview).
|
||||
internal IEnumerable<PackageInfo> ReleaseVersions
|
||||
{
|
||||
get { return Versions.Where(package => !package.IsPreRelease); }
|
||||
}
|
||||
|
||||
internal PackageInfo LatestRelease { get {return ReleaseVersions.LastOrDefault();}}
|
||||
internal PackageInfo Verified { get {return Versions.FirstOrDefault(package => package.IsVerified);}}
|
||||
|
||||
internal bool IsAfterCurrentVersion(PackageInfo packageInfo) { return Current == null || (packageInfo != null && packageInfo.Version > Current.Version); }
|
||||
|
||||
internal bool IsBuiltIn {get { return Versions.Any() && Versions.First().IsBuiltIn; }}
|
||||
|
||||
public string Name { get { return packageName; } }
|
||||
|
||||
public bool IsPackageManagerUI
|
||||
{
|
||||
get { return Name == packageManagerUIName; }
|
||||
}
|
||||
|
||||
public bool Equals(Package other)
|
||||
{
|
||||
if (other == null)
|
||||
return false;
|
||||
|
||||
return packageName == other.packageName;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return packageName.GetHashCode();
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
internal readonly OperationSignal<IAddOperation> AddSignal = new OperationSignal<IAddOperation>();
|
||||
|
||||
private Action OnAddOperationFinalizedEvent;
|
||||
|
||||
internal void Add(PackageInfo packageInfo)
|
||||
{
|
||||
if (packageInfo == Current || AddRemoveOperationInProgress)
|
||||
return;
|
||||
|
||||
var operation = OperationFactory.Instance.CreateAddOperation();
|
||||
addRemoveOperationInstance = operation;
|
||||
OnAddOperationFinalizedEvent = () =>
|
||||
{
|
||||
AddSignal.Operation = null;
|
||||
operation.OnOperationFinalized -= OnAddOperationFinalizedEvent;
|
||||
PackageCollection.Instance.FetchListOfflineCache(true);
|
||||
};
|
||||
|
||||
operation.OnOperationFinalized += OnAddOperationFinalizedEvent;
|
||||
|
||||
AddSignal.SetOperation(operation);
|
||||
operation.AddPackageAsync(packageInfo);
|
||||
}
|
||||
|
||||
internal void Update()
|
||||
{
|
||||
Add(Latest);
|
||||
}
|
||||
|
||||
internal static void AddFromLocalDisk(string path)
|
||||
{
|
||||
if (AddRemoveOperationInProgress)
|
||||
return;
|
||||
|
||||
var packageJson = PackageJsonHelper.Load(path);
|
||||
if (null == packageJson)
|
||||
{
|
||||
Debug.LogError(string.Format("Invalid package path: cannot find \"{0}\".", path));
|
||||
return;
|
||||
}
|
||||
|
||||
var operation = OperationFactory.Instance.CreateAddOperation();
|
||||
addRemoveOperationInstance = operation;
|
||||
operation.AddPackageAsync(packageJson.PackageInfo);
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
internal readonly OperationSignal<IRemoveOperation> RemoveSignal = new OperationSignal<IRemoveOperation>();
|
||||
|
||||
private Action OnRemoveOperationFinalizedEvent;
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
if (Current == null || AddRemoveOperationInProgress)
|
||||
return;
|
||||
|
||||
var operation = OperationFactory.Instance.CreateRemoveOperation();
|
||||
addRemoveOperationInstance = operation;
|
||||
OnRemoveOperationFinalizedEvent = () =>
|
||||
{
|
||||
RemoveSignal.Operation = null;
|
||||
operation.OnOperationFinalized -= OnRemoveOperationFinalizedEvent;
|
||||
PackageCollection.Instance.FetchListOfflineCache(true);
|
||||
};
|
||||
|
||||
operation.OnOperationFinalized += OnRemoveOperationFinalizedEvent;
|
||||
RemoveSignal.SetOperation(operation);
|
||||
|
||||
operation.RemovePackageAsync(Current);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f499e12eaeb145bf9022f581c0b7fa5b
|
||||
timeCreated: 1505740170
|
|
@ -0,0 +1,21 @@
|
|||
using System.Linq;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal class PackageAssetPostprocessor : AssetPostprocessor
|
||||
{
|
||||
static bool IsPackageJsonAsset(string path)
|
||||
{
|
||||
var pathComponents = (path ?? "").Split('/');
|
||||
return pathComponents.Length == 3 && pathComponents[0] == "Packages" && pathComponents[2] == "package.json";
|
||||
}
|
||||
|
||||
static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
|
||||
{
|
||||
if (PackageCollection.Instance != null && (importedAssets.Any(IsPackageJsonAsset) || deletedAssets.Any(IsPackageJsonAsset) || movedAssets.Any(IsPackageJsonAsset)))
|
||||
{
|
||||
PackageCollection.Instance.FetchListOfflineCache(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 63e8a6023745e4347bb661e87a9be1d9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,284 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
[Serializable]
|
||||
internal class PackageCollection
|
||||
{
|
||||
private static PackageCollection instance = new PackageCollection();
|
||||
public static PackageCollection Instance { get { return instance; } }
|
||||
|
||||
public event Action<IEnumerable<Package>> OnPackagesChanged = delegate { };
|
||||
public event Action<PackageFilter> OnFilterChanged = delegate { };
|
||||
|
||||
private readonly Dictionary<string, Package> packages;
|
||||
|
||||
private PackageFilter filter;
|
||||
|
||||
private string selectedListPackage;
|
||||
private string selectedSearchPackage;
|
||||
|
||||
internal string lastUpdateTime;
|
||||
private List<PackageInfo> listPackagesOffline;
|
||||
private List<PackageInfo> listPackages;
|
||||
private List<PackageInfo> searchPackages;
|
||||
|
||||
private List<PackageError> packageErrors;
|
||||
|
||||
private int listPackagesVersion;
|
||||
private int listPackagesOfflineVersion;
|
||||
|
||||
private bool searchOperationOngoing;
|
||||
private bool listOperationOngoing;
|
||||
private bool listOperationOfflineOngoing;
|
||||
|
||||
private IListOperation listOperationOffline;
|
||||
private IListOperation listOperation;
|
||||
private ISearchOperation searchOperation;
|
||||
|
||||
public readonly OperationSignal<ISearchOperation> SearchSignal = new OperationSignal<ISearchOperation>();
|
||||
public readonly OperationSignal<IListOperation> ListSignal = new OperationSignal<IListOperation>();
|
||||
|
||||
public static void InitInstance(ref PackageCollection value)
|
||||
{
|
||||
if (value == null) // UI window opened
|
||||
{
|
||||
value = instance;
|
||||
|
||||
Instance.OnPackagesChanged = delegate { };
|
||||
Instance.OnFilterChanged = delegate { };
|
||||
Instance.SearchSignal.ResetEvents();
|
||||
Instance.ListSignal.ResetEvents();
|
||||
|
||||
Instance.FetchListOfflineCache(true);
|
||||
Instance.FetchListCache(true);
|
||||
Instance.FetchSearchCache(true);
|
||||
}
|
||||
else // Domain reload
|
||||
{
|
||||
instance = value;
|
||||
|
||||
Instance.RebuildPackageDictionary();
|
||||
|
||||
// Resume operations interrupted by domain reload
|
||||
Instance.FetchListOfflineCache(Instance.listOperationOfflineOngoing);
|
||||
Instance.FetchListCache(Instance.listOperationOngoing);
|
||||
Instance.FetchSearchCache(Instance.searchOperationOngoing);
|
||||
}
|
||||
}
|
||||
|
||||
public PackageFilter Filter
|
||||
{
|
||||
get { return filter; }
|
||||
|
||||
// For public usage, use SetFilter() instead
|
||||
private set
|
||||
{
|
||||
var changed = value != filter;
|
||||
filter = value;
|
||||
|
||||
if (changed)
|
||||
OnFilterChanged(filter);
|
||||
}
|
||||
}
|
||||
|
||||
public List<PackageInfo> LatestListPackages
|
||||
{
|
||||
get { return listPackagesVersion > listPackagesOfflineVersion? listPackages : listPackagesOffline; }
|
||||
}
|
||||
|
||||
public List<PackageInfo> LatestSearchPackages { get { return searchPackages; } }
|
||||
|
||||
public string SelectedPackage
|
||||
{
|
||||
get { return PackageFilter.All == Filter ? selectedSearchPackage : selectedListPackage; }
|
||||
set
|
||||
{
|
||||
if (PackageFilter.All == Filter)
|
||||
selectedSearchPackage = value;
|
||||
else
|
||||
selectedListPackage = value;
|
||||
}
|
||||
}
|
||||
|
||||
private PackageCollection()
|
||||
{
|
||||
packages = new Dictionary<string, Package>();
|
||||
|
||||
listPackagesOffline = new List<PackageInfo>();
|
||||
listPackages = new List<PackageInfo>();
|
||||
searchPackages = new List<PackageInfo>();
|
||||
|
||||
packageErrors = new List<PackageError>();
|
||||
|
||||
listPackagesVersion = 0;
|
||||
listPackagesOfflineVersion = 0;
|
||||
|
||||
searchOperationOngoing = false;
|
||||
listOperationOngoing = false;
|
||||
listOperationOfflineOngoing = false;
|
||||
|
||||
Filter = PackageFilter.All;
|
||||
}
|
||||
|
||||
public bool SetFilter(PackageFilter value, bool refresh = true)
|
||||
{
|
||||
if (value == Filter)
|
||||
return false;
|
||||
|
||||
Filter = value;
|
||||
if (refresh)
|
||||
{
|
||||
UpdatePackageCollection();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void UpdatePackageCollection(bool rebuildDictionary = false)
|
||||
{
|
||||
if (rebuildDictionary)
|
||||
{
|
||||
lastUpdateTime = DateTime.Now.ToString("HH:mm");
|
||||
RebuildPackageDictionary();
|
||||
}
|
||||
if (packages.Any())
|
||||
OnPackagesChanged(OrderedPackages());
|
||||
}
|
||||
|
||||
internal void FetchListOfflineCache(bool forceRefetch = false)
|
||||
{
|
||||
if (!forceRefetch && (listOperationOfflineOngoing || listPackagesOffline.Any())) return;
|
||||
if (listOperationOffline != null)
|
||||
listOperationOffline.Cancel();
|
||||
listOperationOfflineOngoing = true;
|
||||
listOperationOffline = OperationFactory.Instance.CreateListOperation(true);
|
||||
listOperationOffline.OnOperationFinalized += () =>
|
||||
{
|
||||
listOperationOfflineOngoing = false;
|
||||
UpdatePackageCollection(true);
|
||||
};
|
||||
listOperationOffline.GetPackageListAsync(
|
||||
infos =>
|
||||
{
|
||||
var version = listPackagesVersion;
|
||||
UpdateListPackageInfosOffline(infos, version);
|
||||
},
|
||||
error => { Debug.LogError("Error fetching package list (offline mode)."); });
|
||||
}
|
||||
|
||||
internal void FetchListCache(bool forceRefetch = false)
|
||||
{
|
||||
if (!forceRefetch && (listOperationOngoing || listPackages.Any())) return;
|
||||
if (listOperation != null)
|
||||
listOperation.Cancel();
|
||||
listOperationOngoing = true;
|
||||
listOperation = OperationFactory.Instance.CreateListOperation();
|
||||
listOperation.OnOperationFinalized += () =>
|
||||
{
|
||||
listOperationOngoing = false;
|
||||
UpdatePackageCollection(true);
|
||||
};
|
||||
listOperation.GetPackageListAsync(UpdateListPackageInfos,
|
||||
error => { Debug.LogError("Error fetching package list."); });
|
||||
ListSignal.SetOperation(listOperation);
|
||||
}
|
||||
|
||||
internal void FetchSearchCache(bool forceRefetch = false)
|
||||
{
|
||||
if (!forceRefetch && (searchOperationOngoing || searchPackages.Any())) return;
|
||||
if (searchOperation != null)
|
||||
searchOperation.Cancel();
|
||||
searchOperationOngoing = true;
|
||||
searchOperation = OperationFactory.Instance.CreateSearchOperation();
|
||||
searchOperation.OnOperationFinalized += () =>
|
||||
{
|
||||
searchOperationOngoing = false;
|
||||
UpdatePackageCollection(true);
|
||||
};
|
||||
searchOperation.GetAllPackageAsync(UpdateSearchPackageInfos,
|
||||
error => { Debug.LogError("Error searching packages online."); });
|
||||
SearchSignal.SetOperation(searchOperation);
|
||||
}
|
||||
|
||||
private void UpdateListPackageInfosOffline(IEnumerable<PackageInfo> newInfos, int version)
|
||||
{
|
||||
listPackagesOfflineVersion = version;
|
||||
listPackagesOffline = newInfos.Where(p => p.IsUserVisible).ToList();
|
||||
}
|
||||
|
||||
private void UpdateListPackageInfos(IEnumerable<PackageInfo> newInfos)
|
||||
{
|
||||
// Each time we fetch list packages, the cache for offline mode will be updated
|
||||
// We keep track of the list packages version so that we know which version of cache
|
||||
// we are getting with the offline fetch operation.
|
||||
listPackagesVersion++;
|
||||
listPackages = newInfos.Where(p => p.IsUserVisible).ToList();
|
||||
listPackagesOffline = listPackages;
|
||||
}
|
||||
|
||||
private void UpdateSearchPackageInfos(IEnumerable<PackageInfo> newInfos)
|
||||
{
|
||||
searchPackages = newInfos.Where(p => p.IsUserVisible).ToList();
|
||||
}
|
||||
|
||||
private IEnumerable<Package> OrderedPackages()
|
||||
{
|
||||
return packages.Values.OrderBy(pkg => pkg.Versions.LastOrDefault() == null ? pkg.Name : pkg.Versions.Last().DisplayName).AsEnumerable();
|
||||
}
|
||||
|
||||
public Package GetPackageByName(string name)
|
||||
{
|
||||
Package package;
|
||||
packages.TryGetValue(name, out package);
|
||||
return package;
|
||||
}
|
||||
|
||||
public Error GetPackageError(Package package)
|
||||
{
|
||||
if (null == package) return null;
|
||||
var firstMatchingError = packageErrors.FirstOrDefault(p => p.PackageName == package.Name);
|
||||
return firstMatchingError != null ? firstMatchingError.Error : null;
|
||||
}
|
||||
|
||||
public void AddPackageError(Package package, Error error)
|
||||
{
|
||||
if (null == package || null == error) return;
|
||||
packageErrors.Add(new PackageError(package.Name, error));
|
||||
}
|
||||
|
||||
public void RemovePackageErrors(Package package)
|
||||
{
|
||||
if (null == package) return;
|
||||
packageErrors.RemoveAll(p => p.PackageName == package.Name);
|
||||
}
|
||||
|
||||
private void RebuildPackageDictionary()
|
||||
{
|
||||
// Merge list & search packages
|
||||
var allPackageInfos = new List<PackageInfo>(LatestListPackages);
|
||||
var installedPackageIds = new HashSet<string>(allPackageInfos.Select(p => p.PackageId));
|
||||
allPackageInfos.AddRange(searchPackages.Where(p => !installedPackageIds.Contains(p.PackageId)));
|
||||
|
||||
if (!PackageManagerPrefs.ShowPreviewPackages)
|
||||
{
|
||||
allPackageInfos = allPackageInfos.Where(p => !p.IsPreRelease || installedPackageIds.Contains(p.PackageId)).ToList();
|
||||
}
|
||||
|
||||
// Rebuild packages dictionary
|
||||
packages.Clear();
|
||||
foreach (var p in allPackageInfos)
|
||||
{
|
||||
var packageName = p.Name;
|
||||
if (packages.ContainsKey(packageName))
|
||||
continue;
|
||||
|
||||
var packageQuery = from pkg in allPackageInfos where pkg.Name == packageName select pkg;
|
||||
var package = new Package(packageName, packageQuery);
|
||||
packages[packageName] = package;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 61d72cb49da3040d5ade3edfd6eccfc1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
[Serializable]
|
||||
internal class PackageError
|
||||
{
|
||||
public string PackageName;
|
||||
public Error Error;
|
||||
|
||||
public PackageError(string packageName, Error error)
|
||||
{
|
||||
PackageName = packageName;
|
||||
Error = error;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b7c10e584b708734ba6141e7d4797931
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
[Serializable]
|
||||
internal enum PackageFilter
|
||||
{
|
||||
None,
|
||||
All,
|
||||
Local,
|
||||
Modules
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 03ffb9844f8d40e8a2f59dd2aff561eb
|
||||
timeCreated: 1508251051
|
|
@ -0,0 +1,8 @@
|
|||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal enum PackageGroupOrigins
|
||||
{
|
||||
Packages,
|
||||
BuiltInPackages
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0e372f1bbea04aa9bd68055d4105bd84
|
||||
timeCreated: 1508855779
|
|
@ -0,0 +1,198 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Semver;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
[Serializable]
|
||||
internal class PackageInfo : IEquatable<PackageInfo>
|
||||
{
|
||||
// Module package.json files contain a documentation url embedded in the description.
|
||||
// We parse that to have the "View Documentation" button direct to it, instead of showing
|
||||
// the link in the description text.
|
||||
private const string builtinPackageDocsUrlKey = "Scripting API: ";
|
||||
|
||||
public string Name;
|
||||
public string DisplayName;
|
||||
private string _PackageId;
|
||||
public SemVersion Version;
|
||||
public string Description;
|
||||
public string Category;
|
||||
public PackageState State;
|
||||
public bool IsCurrent;
|
||||
public bool IsLatest;
|
||||
public string Group;
|
||||
public PackageSource Origin;
|
||||
public List<Error> Errors;
|
||||
public bool IsVerified;
|
||||
public string Author;
|
||||
|
||||
public PackageManager.PackageInfo Info { get; set; }
|
||||
|
||||
public string PackageId {
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_PackageId ))
|
||||
return _PackageId;
|
||||
return string.Format("{0}@{1}", Name.ToLower(), Version);
|
||||
}
|
||||
set
|
||||
{
|
||||
_PackageId = value;
|
||||
}
|
||||
}
|
||||
|
||||
// This will always be <name>@<version>, even for an embedded package.
|
||||
public string VersionId { get { return string.Format("{0}@{1}", Name.ToLower(), Version); } }
|
||||
public string ShortVersionId { get { return string.Format("{0}@{1}", Name.ToLower(), Version.ShortVersion()); } }
|
||||
|
||||
public string BuiltInDescription { get {
|
||||
if (IsBuiltIn)
|
||||
return string.Format("This built in package controls the presence of the {0} module.", DisplayName);
|
||||
else
|
||||
return Description.Split(new[] {builtinPackageDocsUrlKey}, StringSplitOptions.None)[0];
|
||||
} }
|
||||
|
||||
private static Version ParseShortVersion(string shortVersionId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var versionToken = shortVersionId.Split('@')[1];
|
||||
return new Version(versionToken);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Keep default version 0.0 on exception
|
||||
return new Version();
|
||||
}
|
||||
}
|
||||
|
||||
// Method content must be matched in package manager UI
|
||||
public static string GetPackageUrlRedirect(string packageName, string shortVersionId)
|
||||
{
|
||||
var redirectUrl = "";
|
||||
if (packageName == "com.unity.ads")
|
||||
redirectUrl = "https://docs.unity3d.com/Manual/UnityAds.html";
|
||||
else if (packageName == "com.unity.analytics")
|
||||
{
|
||||
if (ParseShortVersion(shortVersionId) < new Version(3, 2))
|
||||
redirectUrl = "https://docs.unity3d.com/Manual/UnityAnalytics.html";
|
||||
}
|
||||
else if (packageName == "com.unity.purchasing")
|
||||
redirectUrl = "https://docs.unity3d.com/Manual/UnityIAP.html";
|
||||
else if (packageName == "com.unity.standardevents")
|
||||
redirectUrl = "https://docs.unity3d.com/Manual/UnityAnalyticsStandardEvents.html";
|
||||
else if (packageName == "com.unity.xiaomi")
|
||||
redirectUrl = "https://unity3d.com/cn/partners/xiaomi/guide";
|
||||
else if (packageName == "com.unity.shadergraph")
|
||||
{
|
||||
if (ParseShortVersion(shortVersionId) < new Version(4, 1))
|
||||
redirectUrl = "https://github.com/Unity-Technologies/ShaderGraph/wiki";
|
||||
}
|
||||
|
||||
return redirectUrl;
|
||||
}
|
||||
|
||||
public bool RedirectsToManual(PackageInfo packageInfo)
|
||||
{
|
||||
return !string.IsNullOrEmpty(GetPackageUrlRedirect(packageInfo.Name, packageInfo.ShortVersionId));
|
||||
}
|
||||
|
||||
public bool HasChangelog(PackageInfo packageInfo)
|
||||
{
|
||||
// Packages with no docs have no third party notice
|
||||
return !RedirectsToManual(packageInfo);
|
||||
}
|
||||
|
||||
public string GetDocumentationUrl()
|
||||
{
|
||||
if (IsBuiltIn)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Description))
|
||||
{
|
||||
var split = Description.Split(new[] {builtinPackageDocsUrlKey}, StringSplitOptions.None);
|
||||
if (split.Length > 1)
|
||||
return split[1];
|
||||
}
|
||||
}
|
||||
return string.Format("http://docs.unity3d.com/Packages/{0}/index.html", ShortVersionId);
|
||||
}
|
||||
|
||||
public string GetChangelogUrl()
|
||||
{
|
||||
return string.Format("http://docs.unity3d.com/Packages/{0}/changelog/CHANGELOG.html", ShortVersionId);
|
||||
}
|
||||
|
||||
public string GetLicensesUrl()
|
||||
{
|
||||
var url = string.Format("http://docs.unity3d.com/Packages/{0}/license/index.html", ShortVersionId);
|
||||
if (RedirectsToManual(this))
|
||||
url = "https://unity3d.com/legal/licenses/Unity_Companion_License";
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
public bool Equals(PackageInfo other)
|
||||
{
|
||||
if (other == null)
|
||||
return false;
|
||||
if (other == this)
|
||||
return true;
|
||||
|
||||
return Name == other.Name && Version == other.Version;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return PackageId.GetHashCode();
|
||||
}
|
||||
|
||||
public bool HasVersionTag(string tag)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Version.Prerelease))
|
||||
return false;
|
||||
|
||||
return String.Equals(Version.Prerelease.Split('.').First(), tag, StringComparison.CurrentCultureIgnoreCase);
|
||||
}
|
||||
|
||||
public bool HasVersionTag(PackageTag tag)
|
||||
{
|
||||
return HasVersionTag(tag.ToString());
|
||||
}
|
||||
|
||||
// Is it a pre-release (alpha/beta/experimental/preview)?
|
||||
// Current logic is any tag is considered pre-release, except recommended
|
||||
public bool IsPreRelease
|
||||
{
|
||||
get { return !string.IsNullOrEmpty(Version.Prerelease) || Version.Major == 0; }
|
||||
}
|
||||
|
||||
public bool IsPreview
|
||||
{
|
||||
get { return HasVersionTag(PackageTag.preview) || Version.Major == 0; }
|
||||
}
|
||||
|
||||
// A version is user visible if it has a supported tag (or no tag at all)
|
||||
public bool IsUserVisible
|
||||
{
|
||||
get { return IsCurrent || string.IsNullOrEmpty(Version.Prerelease) || HasVersionTag(PackageTag.preview) || IsVerified; }
|
||||
}
|
||||
|
||||
public bool IsInDevelopment { get { return Origin == PackageSource.Embedded; } }
|
||||
public bool IsLocal { get { return Origin == PackageSource.Local; } }
|
||||
public bool IsBuiltIn { get { return Origin == PackageSource.BuiltIn; } }
|
||||
|
||||
public string VersionWithoutTag { get { return Version.VersionOnly(); } }
|
||||
|
||||
public bool IsVersionLocked
|
||||
{
|
||||
get { return Origin == PackageSource.Embedded || Origin == PackageSource.Git || Origin == PackageSource.BuiltIn; }
|
||||
}
|
||||
|
||||
public bool CanBeRemoved
|
||||
{
|
||||
get { return Origin == PackageSource.Registry || Origin == PackageSource.BuiltIn || Origin == PackageSource.Local; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b9f324f08cd904ec986357c98dd9eaa6
|
||||
timeCreated: 1502224642
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,37 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal static class PackageInfoListExtensions
|
||||
{
|
||||
public static IEnumerable<PackageInfo> ByName(this IEnumerable<PackageInfo> list, string name)
|
||||
{
|
||||
return from package in list where package.Name == name select package;
|
||||
}
|
||||
|
||||
public static void SetCurrent(this IEnumerable<PackageInfo> list, bool current = true)
|
||||
{
|
||||
foreach (var package in list)
|
||||
{
|
||||
package.IsCurrent = current;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetLatest(this IEnumerable<PackageInfo> list, bool latest = true)
|
||||
{
|
||||
foreach (var package in list)
|
||||
{
|
||||
package.IsLatest = latest;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetGroup(this IEnumerable<PackageInfo> list, string group)
|
||||
{
|
||||
foreach (var package in list)
|
||||
{
|
||||
package.Group = group;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a7b89acd74e047778b42209a7a733d39
|
||||
timeCreated: 1505740214
|
|
@ -0,0 +1,34 @@
|
|||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal class PackageJsonHelper
|
||||
{
|
||||
[SerializeField]
|
||||
private string name = string.Empty;
|
||||
|
||||
private string path = string.Empty;
|
||||
|
||||
public static string GetPackagePath(string jsonPath)
|
||||
{
|
||||
return Path.GetDirectoryName(jsonPath).Replace("\\", "/");
|
||||
}
|
||||
|
||||
public static PackageJsonHelper Load(string path)
|
||||
{
|
||||
// If the path is a directory, find the `package.json` file path
|
||||
var jsonPath = Directory.Exists(path) ? Path.Combine(path, "package.json") : path;
|
||||
if (!File.Exists(jsonPath))
|
||||
return null;
|
||||
var packageJson = JsonUtility.FromJson<PackageJsonHelper>(File.ReadAllText(jsonPath));
|
||||
packageJson.path = GetPackagePath(jsonPath);
|
||||
return string.IsNullOrEmpty(packageJson.name) ? null : packageJson;
|
||||
}
|
||||
|
||||
public PackageInfo PackageInfo
|
||||
{
|
||||
get { return new PackageInfo {PackageId = string.Format("{0}@file:{1}", name, path)}; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b9374526debed24449d75f8cc6d0103f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,13 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal static class PackageListExtensions
|
||||
{
|
||||
public static IEnumerable<Package> Current(this IEnumerable<Package> list)
|
||||
{
|
||||
return (from package in list where package.Current != null select package);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7a74094b34f74992a5121c0586ccf6ea
|
||||
timeCreated: 1506458921
|
|
@ -0,0 +1,9 @@
|
|||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal enum PackageOrigin
|
||||
{
|
||||
Unknown,
|
||||
Builtin,
|
||||
Registry
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a98bc92072da64d49a393088e55ce2a0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
[Serializable]
|
||||
internal class PackageSearchFilter
|
||||
{
|
||||
private static PackageSearchFilter instance = new PackageSearchFilter();
|
||||
public static PackageSearchFilter Instance { get { return instance; } }
|
||||
|
||||
public string SearchText { get; set; }
|
||||
|
||||
public static void InitInstance(ref PackageSearchFilter value)
|
||||
{
|
||||
if (value == null) // UI window opened
|
||||
value = instance;
|
||||
else // Domain reload
|
||||
instance = value;
|
||||
}
|
||||
|
||||
public void ResetSearch()
|
||||
{
|
||||
SearchText = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8d65a43500ec84d9186cb6d9ab681277
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal enum PackageState {
|
||||
UpToDate,
|
||||
Outdated,
|
||||
InProgress,
|
||||
Error
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0a822dba3d5c4c85b150866e5442a5ec
|
||||
timeCreated: 1505740158
|
|
@ -0,0 +1,10 @@
|
|||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal enum PackageTag
|
||||
{
|
||||
preview,
|
||||
verified,
|
||||
inDevelopment,
|
||||
local
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2a3f4f8c4e2df41108f55825c24ff694
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 669717f3193a457b9bad9665ebcae836
|
||||
timeCreated: 1504191654
|
|
@ -0,0 +1,34 @@
|
|||
using System;
|
||||
using UnityEditor.PackageManager.Requests;
|
||||
using System.Linq;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal class UpmAddOperation : UpmBaseOperation, IAddOperation
|
||||
{
|
||||
public PackageInfo PackageInfo { get; protected set; }
|
||||
|
||||
public event Action<PackageInfo> OnOperationSuccess = delegate { };
|
||||
|
||||
public void AddPackageAsync(PackageInfo packageInfo, Action<PackageInfo> doneCallbackAction = null, Action<Error> errorCallbackAction = null)
|
||||
{
|
||||
PackageInfo = packageInfo;
|
||||
OnOperationError += errorCallbackAction;
|
||||
OnOperationSuccess += doneCallbackAction;
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
protected override Request CreateRequest()
|
||||
{
|
||||
return Client.Add(PackageInfo.PackageId);
|
||||
}
|
||||
|
||||
protected override void ProcessData()
|
||||
{
|
||||
var request = CurrentRequest as AddRequest;
|
||||
var package = FromUpmPackageInfo(request.Result).First();
|
||||
OnOperationSuccess(package);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9f091dea68a1452cb6c04a6dfa73d5f5
|
||||
timeCreated: 1504190581
|
|
@ -0,0 +1,229 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Semver;
|
||||
using UnityEngine;
|
||||
using UnityEditor.PackageManager.Requests;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal abstract class UpmBaseOperation : IBaseOperation
|
||||
{
|
||||
public static string GroupName(PackageSource origin)
|
||||
{
|
||||
var group = PackageGroupOrigins.Packages.ToString();
|
||||
if (origin == PackageSource.BuiltIn)
|
||||
group = PackageGroupOrigins.BuiltInPackages.ToString();
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
protected static IEnumerable<PackageInfo> FromUpmPackageInfo(PackageManager.PackageInfo info, bool isCurrent=true)
|
||||
{
|
||||
var packages = new List<PackageInfo>();
|
||||
var displayName = info.displayName;
|
||||
if (string.IsNullOrEmpty(displayName))
|
||||
{
|
||||
displayName = info.name.Replace("com.unity.modules.", "");
|
||||
displayName = displayName.Replace("com.unity.", "");
|
||||
displayName = new CultureInfo("en-US").TextInfo.ToTitleCase(displayName);
|
||||
}
|
||||
|
||||
string author = info.author.name;
|
||||
if (string.IsNullOrEmpty(info.author.name) && info.name.StartsWith("com.unity."))
|
||||
author = "Unity Technologies Inc.";
|
||||
|
||||
var lastCompatible = info.versions.latestCompatible;
|
||||
var versions = new List<string>();
|
||||
versions.AddRange(info.versions.compatible);
|
||||
if (versions.FindIndex(version => version == info.version) == -1)
|
||||
{
|
||||
versions.Add(info.version);
|
||||
|
||||
versions.Sort((left, right) =>
|
||||
{
|
||||
if (left == null || right == null) return 0;
|
||||
|
||||
SemVersion leftVersion = left;
|
||||
SemVersion righVersion = right;
|
||||
return leftVersion.CompareByPrecedence(righVersion);
|
||||
});
|
||||
|
||||
SemVersion packageVersion = info.version;
|
||||
if (!string.IsNullOrEmpty(lastCompatible))
|
||||
{
|
||||
SemVersion lastCompatibleVersion =
|
||||
string.IsNullOrEmpty(lastCompatible) ? (SemVersion) null : lastCompatible;
|
||||
if (packageVersion != null && string.IsNullOrEmpty(packageVersion.Prerelease) &&
|
||||
packageVersion.CompareByPrecedence(lastCompatibleVersion) > 0)
|
||||
lastCompatible = info.version;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (packageVersion != null && string.IsNullOrEmpty(packageVersion.Prerelease))
|
||||
lastCompatible = info.version;
|
||||
}
|
||||
}
|
||||
|
||||
foreach(var version in versions)
|
||||
{
|
||||
var isVersionCurrent = version == info.version && isCurrent;
|
||||
var isBuiltIn = info.source == PackageSource.BuiltIn;
|
||||
var isVerified = string.IsNullOrEmpty(SemVersion.Parse(version).Prerelease) && version == info.versions.recommended;
|
||||
var state = (isBuiltIn || info.version == lastCompatible || !isCurrent ) ? PackageState.UpToDate : PackageState.Outdated;
|
||||
|
||||
// Happens mostly when using a package that hasn't been in production yet.
|
||||
if (info.versions.all.Length <= 0)
|
||||
state = PackageState.UpToDate;
|
||||
|
||||
if (info.errors.Length > 0)
|
||||
state = PackageState.Error;
|
||||
|
||||
var packageInfo = new PackageInfo
|
||||
{
|
||||
Name = info.name,
|
||||
DisplayName = displayName,
|
||||
PackageId = version == info.version ? info.packageId : null,
|
||||
Version = version,
|
||||
Description = info.description,
|
||||
Category = info.category,
|
||||
IsCurrent = isVersionCurrent,
|
||||
IsLatest = version == lastCompatible,
|
||||
IsVerified = isVerified,
|
||||
Errors = info.errors.ToList(),
|
||||
Group = GroupName(info.source),
|
||||
State = state,
|
||||
Origin = isBuiltIn || isVersionCurrent ? info.source : PackageSource.Registry,
|
||||
Author = author,
|
||||
Info = info
|
||||
};
|
||||
|
||||
packages.Add(packageInfo);
|
||||
}
|
||||
|
||||
return packages;
|
||||
}
|
||||
|
||||
public static event Action<UpmBaseOperation> OnOperationStart = delegate { };
|
||||
|
||||
public event Action<Error> OnOperationError = delegate { };
|
||||
public event Action OnOperationFinalized = delegate { };
|
||||
|
||||
public Error ForceError { get; set; } // Allow external component to force an error on the requests (eg: testing)
|
||||
public Error Error { get; protected set; } // Keep last error
|
||||
|
||||
public bool IsCompleted { get; private set; }
|
||||
|
||||
protected abstract Request CreateRequest();
|
||||
|
||||
[SerializeField]
|
||||
protected Request CurrentRequest;
|
||||
public readonly ThreadedDelay Delay = new ThreadedDelay();
|
||||
|
||||
protected abstract void ProcessData();
|
||||
|
||||
protected void Start()
|
||||
{
|
||||
Error = null;
|
||||
OnOperationStart(this);
|
||||
|
||||
Delay.Start();
|
||||
|
||||
if (TryForcedError())
|
||||
return;
|
||||
|
||||
EditorApplication.update += Progress;
|
||||
}
|
||||
|
||||
// Common progress code for all classes
|
||||
private void Progress()
|
||||
{
|
||||
if (!Delay.IsDone)
|
||||
return;
|
||||
|
||||
// Create the request after the delay
|
||||
if (CurrentRequest == null)
|
||||
{
|
||||
CurrentRequest = CreateRequest();
|
||||
}
|
||||
|
||||
// Since CurrentRequest's error property is private, we need to simulate
|
||||
// an error instead of just setting it.
|
||||
if (TryForcedError())
|
||||
return;
|
||||
|
||||
if (CurrentRequest.IsCompleted)
|
||||
{
|
||||
if (CurrentRequest.Status == StatusCode.Success)
|
||||
OnDone();
|
||||
else if (CurrentRequest.Status >= StatusCode.Failure)
|
||||
OnError(CurrentRequest.Error);
|
||||
else
|
||||
Debug.LogError("Unsupported progress state " + CurrentRequest.Status);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnError(Error error)
|
||||
{
|
||||
try
|
||||
{
|
||||
Error = error;
|
||||
|
||||
var message = "Cannot perform upm operation.";
|
||||
if (error != null)
|
||||
message = "Cannot perform upm operation: " + Error.message + " [" + Error.errorCode + "]";
|
||||
|
||||
Debug.LogError(message);
|
||||
|
||||
OnOperationError(Error);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Debug.LogError("Package Manager Window had an error while reporting an error in an operation: " + exception);
|
||||
}
|
||||
|
||||
FinalizeOperation();
|
||||
}
|
||||
|
||||
private void OnDone()
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessData();
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
Debug.LogError("Package Manager Window had an error while completing an operation: " + error);
|
||||
}
|
||||
|
||||
FinalizeOperation();
|
||||
}
|
||||
|
||||
private void FinalizeOperation()
|
||||
{
|
||||
EditorApplication.update -= Progress;
|
||||
OnOperationFinalized();
|
||||
IsCompleted = true;
|
||||
}
|
||||
|
||||
public void Cancel()
|
||||
{
|
||||
EditorApplication.update -= Progress;
|
||||
OnOperationError = delegate { };
|
||||
OnOperationFinalized = delegate { };
|
||||
IsCompleted = true;
|
||||
}
|
||||
|
||||
private bool TryForcedError()
|
||||
{
|
||||
if (ForceError != null)
|
||||
{
|
||||
OnError(ForceError);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4e830e2dbc3315b4b97cd5311a54e4fe
|
||||
timeCreated: 1502918867
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor.PackageManager.Requests;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal class UpmListOperation : UpmBaseOperation, IListOperation
|
||||
{
|
||||
[SerializeField]
|
||||
private Action<IEnumerable<PackageInfo>> _doneCallbackAction;
|
||||
|
||||
public UpmListOperation(bool offlineMode) : base()
|
||||
{
|
||||
OfflineMode = offlineMode;
|
||||
}
|
||||
|
||||
public bool OfflineMode { get; set; }
|
||||
|
||||
public void GetPackageListAsync(Action<IEnumerable<PackageInfo>> doneCallbackAction, Action<Error> errorCallbackAction = null)
|
||||
{
|
||||
this._doneCallbackAction = doneCallbackAction;
|
||||
OnOperationError += errorCallbackAction;
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
protected override Request CreateRequest()
|
||||
{
|
||||
return Client.List(OfflineMode);
|
||||
}
|
||||
|
||||
protected override void ProcessData()
|
||||
{
|
||||
var request = CurrentRequest as ListRequest;
|
||||
var packages = new List<PackageInfo>();
|
||||
foreach (var upmPackage in request.Result)
|
||||
{
|
||||
var packageInfos = FromUpmPackageInfo(upmPackage);
|
||||
packages.AddRange(packageInfos);
|
||||
}
|
||||
|
||||
_doneCallbackAction(packages);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9a2c874c382e2419184b302497279dd9
|
||||
timeCreated: 1502224642
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal class UpmOperationFactory : IOperationFactory
|
||||
{
|
||||
public IListOperation CreateListOperation(bool offlineMode = false)
|
||||
{
|
||||
return new UpmListOperation(offlineMode);
|
||||
}
|
||||
|
||||
public ISearchOperation CreateSearchOperation()
|
||||
{
|
||||
return new UpmSearchOperation();
|
||||
}
|
||||
|
||||
public IAddOperation CreateAddOperation()
|
||||
{
|
||||
return new UpmAddOperation();
|
||||
}
|
||||
|
||||
public IRemoveOperation CreateRemoveOperation()
|
||||
{
|
||||
return new UpmRemoveOperation();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e6925bb38494e6a43ba0921e65e424fe
|
||||
timeCreated: 1502915478
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEditor.PackageManager.Requests;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal class UpmRemoveOperation : UpmBaseOperation, IRemoveOperation
|
||||
{
|
||||
[SerializeField]
|
||||
private PackageInfo _package;
|
||||
|
||||
public event Action<PackageInfo> OnOperationSuccess = delegate { };
|
||||
|
||||
public void RemovePackageAsync(PackageInfo package, Action<PackageInfo> doneCallbackAction = null, Action<Error> errorCallbackAction = null)
|
||||
{
|
||||
_package = package;
|
||||
OnOperationError += errorCallbackAction;
|
||||
OnOperationSuccess += doneCallbackAction;
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
protected override Request CreateRequest()
|
||||
{
|
||||
return Client.Remove(_package.Name);
|
||||
}
|
||||
|
||||
protected override void ProcessData()
|
||||
{
|
||||
OnOperationSuccess(_package);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d5a61f8cc87394b28aec6b88b4083217
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,38 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor.PackageManager.Requests;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal class UpmSearchOperation : UpmBaseOperation, ISearchOperation
|
||||
{
|
||||
[SerializeField]
|
||||
private Action<IEnumerable<PackageInfo>> _doneCallbackAction;
|
||||
|
||||
public void GetAllPackageAsync(Action<IEnumerable<PackageInfo>> doneCallbackAction = null, Action<Error> errorCallbackAction = null)
|
||||
{
|
||||
_doneCallbackAction = doneCallbackAction;
|
||||
OnOperationError += errorCallbackAction;
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
protected override Request CreateRequest()
|
||||
{
|
||||
return Client.SearchAll();
|
||||
}
|
||||
|
||||
protected override void ProcessData()
|
||||
{
|
||||
var request = CurrentRequest as SearchRequest;
|
||||
var packages = new List<PackageInfo>();
|
||||
foreach (var upmPackage in request.Result)
|
||||
{
|
||||
var packageInfos = FromUpmPackageInfo(upmPackage, false);
|
||||
packages.AddRange(packageInfos);
|
||||
}
|
||||
_doneCallbackAction(packages);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ef5a2781610c4f12a79939f717f789cf
|
||||
timeCreated: 1508160183
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 301fbaa0e62e44fd2a7383bd338a2898
|
||||
folderAsset: yes
|
||||
timeCreated: 1502224642
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 42064bc130be4c44b288d249a44b356f
|
||||
timeCreated: 1504191962
|
|
@ -0,0 +1,74 @@
|
|||
using System;
|
||||
using UnityEngine.Experimental.UIElements;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
internal class AlertFactory : UxmlFactory<Alert>
|
||||
{
|
||||
protected override Alert DoCreate(IUxmlAttributes bag, CreationContext cc)
|
||||
{
|
||||
return new Alert();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal class Alert : VisualElement
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
internal new class UxmlFactory : UxmlFactory<Alert> { }
|
||||
#endif
|
||||
|
||||
private const string TemplatePath = PackageManagerWindow.ResourcesPath + "Templates/Alert.uxml";
|
||||
private readonly VisualElement root;
|
||||
private const float originalPositionRight = 5.0f;
|
||||
private const float positionRightWithScroll = 12.0f;
|
||||
|
||||
public Action OnCloseError;
|
||||
|
||||
public Alert()
|
||||
{
|
||||
UIUtils.SetElementDisplay(this, false);
|
||||
|
||||
root = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(TemplatePath).CloneTree(null);
|
||||
Add(root);
|
||||
root.StretchToParentSize();
|
||||
|
||||
CloseButton.clickable.clicked += () =>
|
||||
{
|
||||
if (null != OnCloseError)
|
||||
OnCloseError();
|
||||
ClearError();
|
||||
};
|
||||
}
|
||||
|
||||
public void SetError(Error error)
|
||||
{
|
||||
var message = "An error occured.";
|
||||
if (error != null)
|
||||
message = error.message ?? string.Format("An error occurred ({0})", error.errorCode.ToString());
|
||||
|
||||
AlertMessage.text = message;
|
||||
UIUtils.SetElementDisplay(this, true);
|
||||
}
|
||||
|
||||
public void ClearError()
|
||||
{
|
||||
UIUtils.SetElementDisplay(this, false);
|
||||
AdjustSize(false);
|
||||
AlertMessage.text = "";
|
||||
OnCloseError = null;
|
||||
}
|
||||
|
||||
public void AdjustSize(bool verticalScrollerVisible)
|
||||
{
|
||||
if (verticalScrollerVisible)
|
||||
style.positionRight = originalPositionRight + positionRightWithScroll;
|
||||
else
|
||||
style.positionRight = originalPositionRight;
|
||||
}
|
||||
|
||||
private Label AlertMessage { get { return root.Q<Label>("alertMessage"); } }
|
||||
private Button CloseButton { get { return root.Q<Button>("close"); } }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b274f3d1ea05d4bd8a13f4556f7797d2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,87 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Experimental.UIElements;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
internal class LoadingSpinnerFactory : UxmlFactory<LoadingSpinner>
|
||||
{
|
||||
protected override LoadingSpinner DoCreate(IUxmlAttributes bag, CreationContext cc)
|
||||
{
|
||||
return new LoadingSpinner();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal class LoadingSpinner : VisualElement
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
internal new class UxmlFactory : UxmlFactory<LoadingSpinner, UxmlTraits>
|
||||
{
|
||||
}
|
||||
|
||||
// This works around an issue with UXML instantiation
|
||||
// See https://fogbugz.unity3d.com/f/cases/1046459/
|
||||
internal new class UxmlTraits : VisualElement.UxmlTraits
|
||||
{
|
||||
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
|
||||
{
|
||||
base.Init(ve, bag, cc);
|
||||
UIUtils.SetElementDisplay(ve, false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public bool InvertColor { get; set; }
|
||||
public bool Started { get; private set; }
|
||||
|
||||
private int rotation;
|
||||
|
||||
public LoadingSpinner()
|
||||
{
|
||||
InvertColor = false;
|
||||
Started = false;
|
||||
UIUtils.SetElementDisplay(this, false);
|
||||
}
|
||||
|
||||
private void UpdateProgress()
|
||||
{
|
||||
if (parent == null)
|
||||
return;
|
||||
|
||||
parent.transform.rotation = Quaternion.Euler(0, 0, rotation);
|
||||
rotation += 3;
|
||||
if (rotation > 360)
|
||||
rotation -= 360;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (Started)
|
||||
return;
|
||||
|
||||
// Weird hack to make sure loading spinner doesn't generate an error every frame.
|
||||
// Cannot put in constructor as it give really strange result.
|
||||
if (parent != null && parent.parent != null)
|
||||
parent.parent.clippingOptions = ClippingOptions.ClipAndCacheContents;
|
||||
|
||||
rotation = 0;
|
||||
|
||||
EditorApplication.update += UpdateProgress;
|
||||
|
||||
Started = true;
|
||||
UIUtils.SetElementDisplay(this, true);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (!Started)
|
||||
return;
|
||||
|
||||
EditorApplication.update -= UpdateProgress;
|
||||
|
||||
Started = false;
|
||||
UIUtils.SetElementDisplay(this, false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 06f8e3404d534cab82fe852ff33dad77
|
||||
timeCreated: 1504191988
|
|
@ -0,0 +1,186 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.UIElements;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
internal class PopupField<T> : Experimental.UIElements.PopupField<T>
|
||||
{
|
||||
private Func<T, string> m_Callback;
|
||||
|
||||
public override T value
|
||||
{
|
||||
get { return base.value; }
|
||||
set
|
||||
{
|
||||
base.value = value;
|
||||
if (m_Callback != null)
|
||||
m_TextElement.text = m_Callback(m_Value);
|
||||
else
|
||||
m_TextElement.text = m_Value.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback that will return the string to be set in the field's label.
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
public void SetLabelCallback(Func<T, string> callback)
|
||||
{
|
||||
m_Callback = callback;
|
||||
}
|
||||
|
||||
public PopupField(List<T> choices, T defaultValue) :
|
||||
base(choices, defaultValue)
|
||||
{
|
||||
}
|
||||
|
||||
public PopupField(List<T> choices, int defaultIndex) :
|
||||
base(choices, defaultIndex)
|
||||
{
|
||||
}
|
||||
}
|
||||
#else
|
||||
internal class PopupField<T> : BaseTextElement, INotifyValueChanged<T>
|
||||
{
|
||||
private readonly List<T> m_PossibleValues;
|
||||
private Func<T, string> m_Callback;
|
||||
private EventCallback<ChangeEvent<T>> m_valueCallback;
|
||||
private T m_Value;
|
||||
public T value
|
||||
{
|
||||
get { return m_Value; }
|
||||
set
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(m_Value, value))
|
||||
return;
|
||||
|
||||
if (!m_PossibleValues.Contains(value))
|
||||
throw new ArgumentException(string.Format("Value {0} is not present in the list of possible values", value));
|
||||
|
||||
m_Value = value;
|
||||
m_Index = m_PossibleValues.IndexOf(m_Value);
|
||||
if (m_Callback != null)
|
||||
text = m_Callback(m_Value);
|
||||
else
|
||||
text = m_Value.ToString();
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
MarkDirtyRepaint();
|
||||
#else
|
||||
Dirty(ChangeType.Repaint);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private int m_Index = -1;
|
||||
public int index
|
||||
{
|
||||
get { return m_Index; }
|
||||
set
|
||||
{
|
||||
if (value != m_Index)
|
||||
{
|
||||
if (value >= m_PossibleValues.Count || value < 0)
|
||||
throw new ArgumentException(string.Format("Index {0} is beyond the scope of possible value", value));
|
||||
m_Index = value;
|
||||
this.value = m_PossibleValues[m_Index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback that will return the string to be set in the field's label.
|
||||
/// </summary>
|
||||
/// <param name="callback"></param>
|
||||
public void SetLabelCallback(Func<T, string> callback)
|
||||
{
|
||||
m_Callback = callback;
|
||||
}
|
||||
|
||||
private PopupField(List<T> possibleValues)
|
||||
{
|
||||
if (possibleValues == null)
|
||||
throw new ArgumentNullException("possibleValues can't be null");
|
||||
|
||||
m_PossibleValues = possibleValues;
|
||||
|
||||
AddToClassList("popupField");
|
||||
}
|
||||
|
||||
public PopupField(List<T> possibleValues, T defaultValue) :
|
||||
this(possibleValues)
|
||||
{
|
||||
if (defaultValue == null)
|
||||
throw new ArgumentNullException("defaultValue can't be null");
|
||||
|
||||
if (!m_PossibleValues.Contains(defaultValue))
|
||||
throw new ArgumentException(string.Format("Default value {0} is not present in the list of possible values", defaultValue));
|
||||
|
||||
// note: idx will be set when setting value
|
||||
value = defaultValue;
|
||||
}
|
||||
|
||||
public PopupField(List<T> possibleValues, int defaultIndex) :
|
||||
this(possibleValues)
|
||||
{
|
||||
if (defaultIndex >= m_PossibleValues.Count || defaultIndex < 0)
|
||||
throw new ArgumentException(string.Format("Default Index {0} is beyond the scope of possible value", value));
|
||||
|
||||
// note: value will be set when setting idx
|
||||
index = defaultIndex;
|
||||
}
|
||||
|
||||
public void SetValueAndNotify(T newValue)
|
||||
{
|
||||
if (!EqualityComparer<T>.Default.Equals(newValue, value))
|
||||
{
|
||||
using (ChangeEvent<T> evt = ChangeEvent<T>.GetPooled(value, newValue))
|
||||
{
|
||||
value = newValue;
|
||||
if (m_valueCallback != null)
|
||||
m_valueCallback(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnValueChanged(EventCallback<ChangeEvent<T>> callback)
|
||||
{
|
||||
m_valueCallback = callback;
|
||||
RegisterCallback(callback);
|
||||
}
|
||||
|
||||
protected override void ExecuteDefaultAction(EventBase evt)
|
||||
{
|
||||
base.ExecuteDefaultAction(evt);
|
||||
|
||||
if (evt.GetEventTypeId() == MouseDownEvent.TypeId())
|
||||
OnMouseDown();
|
||||
}
|
||||
|
||||
private void OnMouseDown()
|
||||
{
|
||||
var menu = new GenericMenu();
|
||||
|
||||
foreach (T item in m_PossibleValues)
|
||||
{
|
||||
bool isSelected = EqualityComparer<T>.Default.Equals(item, value);
|
||||
menu.AddItem(new GUIContent(item.ToString()), isSelected,
|
||||
() => ChangeValueFromMenu(item));
|
||||
}
|
||||
|
||||
var menuPosition = new Vector2(0.0f, layout.height);
|
||||
menuPosition = this.LocalToWorld(menuPosition);
|
||||
var menuRect = new Rect(menuPosition, Vector2.zero);
|
||||
menu.DropDown(menuRect);
|
||||
}
|
||||
|
||||
private void ChangeValueFromMenu(T menuItem)
|
||||
{
|
||||
SetValueAndNotify(menuItem);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9e69df8ff024a4dc1a9e5c22725e4863
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,55 @@
|
|||
using UnityEngine.Experimental.UIElements;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal static class UIUtils
|
||||
{
|
||||
private const string DisplayNone = "display-none";
|
||||
|
||||
public static void SetElementDisplay(VisualElement element, bool value)
|
||||
{
|
||||
if (element == null)
|
||||
return;
|
||||
|
||||
if (value)
|
||||
element.RemoveFromClassList(DisplayNone);
|
||||
else
|
||||
element.AddToClassList(DisplayNone);
|
||||
|
||||
element.visible = value;
|
||||
}
|
||||
|
||||
public static void SetElementDisplayNonEmpty(Label element)
|
||||
{
|
||||
if (element == null)
|
||||
return;
|
||||
|
||||
var empty = string.IsNullOrEmpty(element.text);
|
||||
if (empty)
|
||||
element.AddToClassList(DisplayNone);
|
||||
else
|
||||
element.RemoveFromClassList(DisplayNone);
|
||||
|
||||
element.visible = !empty;
|
||||
}
|
||||
|
||||
public static void SetElementDisplayNonEmpty(Button element)
|
||||
{
|
||||
if (element == null)
|
||||
return;
|
||||
|
||||
var empty = string.IsNullOrEmpty(element.text);
|
||||
if (empty)
|
||||
element.AddToClassList(DisplayNone);
|
||||
else
|
||||
element.RemoveFromClassList(DisplayNone);
|
||||
|
||||
element.visible = !empty;
|
||||
}
|
||||
|
||||
public static bool IsElementVisible(VisualElement element)
|
||||
{
|
||||
return element.visible && !element.ClassListContains(DisplayNone);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0edd86f97b0648f685604a5582cff608
|
||||
timeCreated: 1508956933
|
|
@ -0,0 +1,66 @@
|
|||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal class VersionItem
|
||||
{
|
||||
internal PackageInfo Version;
|
||||
|
||||
public string MenuName { get; set; }
|
||||
|
||||
// Base label
|
||||
public string Label
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Version == null)
|
||||
return MenuName;
|
||||
|
||||
var label = Version.VersionWithoutTag;
|
||||
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
public string DropdownLabel
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Version == null)
|
||||
return MenuName;
|
||||
|
||||
var label = MenuName + Label;
|
||||
|
||||
if (Version.IsLocal)
|
||||
label += " - local";
|
||||
if (Version.IsCurrent)
|
||||
label += " - current";
|
||||
if (Version.IsVerified)
|
||||
label += " - verified";
|
||||
else if (!string.IsNullOrEmpty(Version.Version.Prerelease))
|
||||
label += string.Format(" - {0}", Version.Version.Prerelease);
|
||||
else if (Version.IsPreview)
|
||||
label += " - preview";
|
||||
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return DropdownLabel;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(obj, null)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
|
||||
var other = (VersionItem)obj;
|
||||
return Version == other.Version;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Version.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3877b2be7ee07495d8918dc8937e6de2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bfd715cd54ab84c22b128149c12b516c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,34 @@
|
|||
using UnityEngine.Experimental.UIElements;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface for Package Manager UI Extension
|
||||
/// </summary>
|
||||
public interface IPackageManagerExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates the extension UI visual element.
|
||||
/// </summary>
|
||||
/// <returns>A visual element that represents the UI or null if none</returns>
|
||||
VisualElement CreateExtensionUI();
|
||||
|
||||
/// <summary>
|
||||
/// Called by the Package Manager UI when the package selection changed.
|
||||
/// </summary>
|
||||
/// <param name="packageInfo">The newly selected package information (can be null)</param>
|
||||
void OnPackageSelectionChange(PackageManager.PackageInfo packageInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Called by the Package Manager UI when a package is added or updated.
|
||||
/// </summary>
|
||||
/// <param name="packageInfo">The package information</param>
|
||||
void OnPackageAddedOrUpdated(PackageManager.PackageInfo packageInfo);
|
||||
|
||||
/// <summary>
|
||||
/// Called by the Package Manager UI when a package is removed.
|
||||
/// </summary>
|
||||
/// <param name="packageInfo">The package information</param>
|
||||
void OnPackageRemoved(PackageManager.PackageInfo packageInfo);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 66083b7f6dc2e433eae33f3244b2ce88
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,134 @@
|
|||
using UnityEngine;
|
||||
using UnityEngine.Experimental.UIElements;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
internal class PackageAddFromUrlFieldFactory : UxmlFactory<PackageAddFromUrlField>
|
||||
{
|
||||
protected override PackageAddFromUrlField DoCreate(IUxmlAttributes bag, CreationContext cc)
|
||||
{
|
||||
return new PackageAddFromUrlField();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal class PackageAddFromUrlField : VisualElement
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
internal new class UxmlFactory : UxmlFactory<PackageAddFromUrlField> { }
|
||||
#endif
|
||||
private string urlText;
|
||||
|
||||
private readonly VisualElement root;
|
||||
|
||||
public PackageAddFromUrlField()
|
||||
{
|
||||
root = Resources.GetTemplate("PackageAddFromUrlField.uxml");
|
||||
Add(root);
|
||||
|
||||
UrlTextField.value = urlText;
|
||||
|
||||
AddButton.SetEnabled(!string.IsNullOrEmpty(urlText));
|
||||
AddButton.clickable.clicked += OnAddButtonClick;
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(OnEnterPanel);
|
||||
RegisterCallback<DetachFromPanelEvent>(OnLeavePanel);
|
||||
}
|
||||
|
||||
private void OnUrlTextFieldChange(ChangeEvent<string> evt)
|
||||
{
|
||||
urlText = evt.newValue;
|
||||
AddButton.SetEnabled(!string.IsNullOrEmpty(urlText));
|
||||
}
|
||||
|
||||
private void OnUrlTextFieldFocus(FocusEvent evt)
|
||||
{
|
||||
Show();
|
||||
}
|
||||
|
||||
private void OnUrlTextFieldFocusOut(FocusOutEvent evt)
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void OnContainerFocus(FocusEvent evt)
|
||||
{
|
||||
UrlTextField.Focus();
|
||||
}
|
||||
|
||||
private void OnContainerFocusOut(FocusOutEvent evt)
|
||||
{
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void OnEnterPanel(AttachToPanelEvent evt)
|
||||
{
|
||||
AddFromUrlFieldContainer.RegisterCallback<FocusEvent>(OnContainerFocus);
|
||||
AddFromUrlFieldContainer.RegisterCallback<FocusOutEvent>(OnContainerFocusOut);
|
||||
UrlTextField.RegisterCallback<FocusEvent>(OnUrlTextFieldFocus);
|
||||
UrlTextField.RegisterCallback<FocusOutEvent>(OnUrlTextFieldFocusOut);
|
||||
UrlTextField.RegisterCallback<ChangeEvent<string>>(OnUrlTextFieldChange);
|
||||
UrlTextField.RegisterCallback<KeyDownEvent>(OnKeyDownShortcut);
|
||||
Hide();
|
||||
}
|
||||
|
||||
private void OnLeavePanel(DetachFromPanelEvent evt)
|
||||
{
|
||||
AddFromUrlFieldContainer.UnregisterCallback<FocusEvent>(OnContainerFocus);
|
||||
AddFromUrlFieldContainer.UnregisterCallback<FocusOutEvent>(OnContainerFocusOut);
|
||||
UrlTextField.UnregisterCallback<FocusEvent>(OnUrlTextFieldFocus);
|
||||
UrlTextField.UnregisterCallback<FocusOutEvent>(OnUrlTextFieldFocusOut);
|
||||
UrlTextField.UnregisterCallback<ChangeEvent<string>>(OnUrlTextFieldChange);
|
||||
UrlTextField.UnregisterCallback<KeyDownEvent>(OnKeyDownShortcut);
|
||||
}
|
||||
|
||||
private void OnKeyDownShortcut(KeyDownEvent evt)
|
||||
{
|
||||
switch (evt.keyCode)
|
||||
{
|
||||
case KeyCode.Escape:
|
||||
Hide();
|
||||
break;
|
||||
case KeyCode.Return:
|
||||
case KeyCode.KeypadEnter:
|
||||
OnAddButtonClick();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAddButtonClick()
|
||||
{
|
||||
var path = urlText;
|
||||
if (!string.IsNullOrEmpty(path) && !Package.AddRemoveOperationInProgress)
|
||||
{
|
||||
Package.AddFromLocalDisk(path);
|
||||
Hide();
|
||||
}
|
||||
}
|
||||
|
||||
internal void Hide()
|
||||
{
|
||||
UIUtils.SetElementDisplay(this, false);
|
||||
}
|
||||
|
||||
internal void Show(bool reset = false)
|
||||
{
|
||||
if (reset)
|
||||
Reset();
|
||||
UIUtils.SetElementDisplay(this, true);
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
UrlTextField.value = string.Empty;
|
||||
urlText = string.Empty;
|
||||
AddButton.SetEnabled(false);
|
||||
UrlTextField.Focus();
|
||||
}
|
||||
|
||||
private VisualElement AddFromUrlFieldContainer { get { return root.Q<VisualElement>("addFromUrlFieldContainer"); }}
|
||||
private TextField UrlTextField { get { return root.Q<TextField>("urlTextField"); } }
|
||||
private Button AddButton{ get { return root.Q<Button>("addFromUrlButton"); }}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 40f980217d9196e4baa9ebd2ac1328af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,626 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Semver;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Experimental.UIElements;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
internal class PackageDetailsFactory : UxmlFactory<PackageDetails>
|
||||
{
|
||||
protected override PackageDetails DoCreate(IUxmlAttributes bag, CreationContext cc)
|
||||
{
|
||||
return new PackageDetails();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal class PackageDetails : VisualElement
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
internal new class UxmlFactory : UxmlFactory<PackageDetails> { }
|
||||
#endif
|
||||
|
||||
private readonly VisualElement root;
|
||||
private Package package;
|
||||
private const string emptyDescriptionClass = "empty";
|
||||
private List<VersionItem> VersionItems;
|
||||
internal PopupField<VersionItem> VersionPopup;
|
||||
private PackageInfo DisplayPackage;
|
||||
|
||||
private PackageInfo SelectedPackage
|
||||
{
|
||||
get { return VersionPopup.value.Version != null ? VersionPopup.value.Version : null; }
|
||||
}
|
||||
|
||||
internal enum PackageAction
|
||||
{
|
||||
Add,
|
||||
Remove,
|
||||
Update,
|
||||
Downgrade,
|
||||
Enable,
|
||||
Disable,
|
||||
UpToDate,
|
||||
Current,
|
||||
Local,
|
||||
Git,
|
||||
Embedded
|
||||
}
|
||||
|
||||
private static readonly VersionItem EmptyVersion = new VersionItem {Version = null};
|
||||
internal static readonly string[] PackageActionVerbs = { "Install", "Remove", "Update to", "Update to", "Enable", "Disable", "Up to date", "Current", "Local", "Git", "Embedded" };
|
||||
internal static readonly string[] PackageActionInProgressVerbs = { "Installing", "Removing", "Updating to", "Updating to", "Enabling", "Disabling", "Up to date", "Current", "Local", "Git", "Embedded" };
|
||||
|
||||
public PackageDetails()
|
||||
{
|
||||
UIUtils.SetElementDisplay(this, false);
|
||||
|
||||
root = Resources.GetTemplate("PackageDetails.uxml");
|
||||
Add(root);
|
||||
|
||||
foreach (var extension in PackageManagerExtensions.Extensions)
|
||||
CustomContainer.Add(extension.CreateExtensionUI());
|
||||
|
||||
root.StretchToParentSize();
|
||||
|
||||
SetUpdateVisibility(false);
|
||||
RemoveButton.visible = false;
|
||||
UpdateBuiltIn.visible = false;
|
||||
|
||||
UpdateButton.clickable.clicked += UpdateClick;
|
||||
UpdateBuiltIn.clickable.clicked += UpdateClick;
|
||||
RemoveButton.clickable.clicked += RemoveClick;
|
||||
ViewDocButton.clickable.clicked += ViewDocClick;
|
||||
ViewChangelogButton.clickable.clicked += ViewChangelogClick;
|
||||
ViewLicenses.clickable.clicked += ViewLicensesClick;
|
||||
|
||||
VersionItems = new List<VersionItem> {EmptyVersion};
|
||||
VersionPopup = new PopupField<VersionItem>(VersionItems, 0);
|
||||
VersionPopup.SetLabelCallback(VersionSelectionSetLabel);
|
||||
VersionPopup.AddToClassList("popup");
|
||||
VersionPopup.OnValueChanged(VersionSelectionChanged);
|
||||
|
||||
if (VersionItems.Count == 1)
|
||||
VersionPopup.SetEnabled(false);
|
||||
|
||||
UpdateDropdownContainer.Add(VersionPopup);
|
||||
VersionPopup.StretchToParentSize();
|
||||
|
||||
|
||||
// Fix button on dark skin but overlapping edge pixel perfectly
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
VersionPopup.style.positionLeft = -1;
|
||||
UpdateDropdownContainer.style.sliceLeft = 4;
|
||||
}
|
||||
}
|
||||
|
||||
private string VersionSelectionSetLabel(VersionItem item)
|
||||
{
|
||||
return item.Label;
|
||||
}
|
||||
|
||||
private void VersionSelectionChanged(ChangeEvent<VersionItem> e)
|
||||
{
|
||||
RefreshAddButton();
|
||||
}
|
||||
|
||||
private void SetUpdateVisibility(bool value)
|
||||
{
|
||||
if (UpdateContainer != null)
|
||||
UIUtils.SetElementDisplay(UpdateContainer, value);
|
||||
}
|
||||
|
||||
internal void SetDisplayPackage(PackageInfo packageInfo)
|
||||
{
|
||||
DisplayPackage = packageInfo;
|
||||
|
||||
var detailVisible = true;
|
||||
Error error = null;
|
||||
|
||||
if (package == null || DisplayPackage == null)
|
||||
{
|
||||
detailVisible = false;
|
||||
UIUtils.SetElementDisplay(DocumentationContainer, false);
|
||||
UIUtils.SetElementDisplay(CustomContainer, false);
|
||||
UIUtils.SetElementDisplay(UpdateBuiltIn, false);
|
||||
|
||||
foreach (var extension in PackageManagerExtensions.Extensions)
|
||||
extension.OnPackageSelectionChange(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetUpdateVisibility(true);
|
||||
UIUtils.SetElementDisplay(ViewDocButton, true);
|
||||
RemoveButton.visible = true;
|
||||
|
||||
if (string.IsNullOrEmpty(DisplayPackage.Description))
|
||||
{
|
||||
DetailDesc.text = "There is no description for this package.";
|
||||
DetailDesc.AddToClassList(emptyDescriptionClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
DetailDesc.text = DisplayPackage.Description;
|
||||
DetailDesc.RemoveFromClassList(emptyDescriptionClass);
|
||||
}
|
||||
|
||||
root.Q<Label>("detailTitle").text = DisplayPackage.DisplayName;
|
||||
DetailVersion.text = "Version " + DisplayPackage.VersionWithoutTag;
|
||||
|
||||
if (DisplayPackage.IsInDevelopment || DisplayPackage.HasVersionTag(PackageTag.preview))
|
||||
UIUtils.SetElementDisplay(GetTag(PackageTag.verified), false);
|
||||
else
|
||||
{
|
||||
var unityVersionParts = Application.unityVersion.Split('.');
|
||||
var unityVersion = string.Format("{0}.{1}", unityVersionParts[0], unityVersionParts[1]);
|
||||
VerifyLabel.text = unityVersion + " verified";
|
||||
UIUtils.SetElementDisplay(GetTag(PackageTag.verified), DisplayPackage.IsVerified);
|
||||
}
|
||||
|
||||
UIUtils.SetElementDisplay(GetTag(PackageTag.inDevelopment), DisplayPackage.IsInDevelopment);
|
||||
UIUtils.SetElementDisplay(GetTag(PackageTag.local), DisplayPackage.IsLocal);
|
||||
UIUtils.SetElementDisplay(GetTag(PackageTag.preview), DisplayPackage.IsPreview);
|
||||
|
||||
UIUtils.SetElementDisplay(DocumentationContainer, DisplayPackage.Origin != PackageSource.BuiltIn);
|
||||
UIUtils.SetElementDisplay(ChangelogContainer, DisplayPackage.HasChangelog(DisplayPackage));
|
||||
|
||||
root.Q<Label>("detailName").text = DisplayPackage.Name;
|
||||
root.Q<ScrollView>("detailView").scrollOffset = new Vector2(0, 0);
|
||||
|
||||
DetailModuleReference.text = "";
|
||||
var isBuiltIn = DisplayPackage.IsBuiltIn;
|
||||
if (isBuiltIn)
|
||||
DetailModuleReference.text = DisplayPackage.BuiltInDescription;
|
||||
|
||||
DetailAuthor.text = "";
|
||||
if (!string.IsNullOrEmpty(DisplayPackage.Author))
|
||||
DetailAuthor.text = string.Format("Author: {0}", DisplayPackage.Author);
|
||||
|
||||
UIUtils.SetElementDisplay(DetailDesc, !isBuiltIn);
|
||||
UIUtils.SetElementDisplay(DetailVersion, !isBuiltIn);
|
||||
UIUtils.SetElementDisplayNonEmpty(DetailModuleReference);
|
||||
UIUtils.SetElementDisplayNonEmpty(DetailAuthor);
|
||||
|
||||
if (DisplayPackage.Errors.Count > 0)
|
||||
error = DisplayPackage.Errors.First();
|
||||
|
||||
RefreshAddButton();
|
||||
RefreshRemoveButton();
|
||||
UIUtils.SetElementDisplay(CustomContainer, true);
|
||||
|
||||
package.AddSignal.OnOperation += OnAddOperation;
|
||||
package.RemoveSignal.OnOperation += OnRemoveOperation;
|
||||
foreach (var extension in PackageManagerExtensions.Extensions)
|
||||
extension.OnPackageSelectionChange(DisplayPackage.Info);
|
||||
}
|
||||
|
||||
// Set visibility
|
||||
root.Q<VisualElement>("detail").visible = detailVisible;
|
||||
|
||||
if (null == error)
|
||||
error = PackageCollection.Instance.GetPackageError(package);
|
||||
|
||||
if (error != null)
|
||||
SetError(error);
|
||||
else
|
||||
DetailError.ClearError();
|
||||
}
|
||||
|
||||
private void ResetVersionItems(PackageInfo displayPackage)
|
||||
{
|
||||
VersionItems.Clear();
|
||||
VersionPopup.SetEnabled(true);
|
||||
|
||||
if (displayPackage == null)
|
||||
return;
|
||||
|
||||
//
|
||||
// Get key versions -- Latest, Verified, LatestPatch, Current.
|
||||
var keyVersions = new List<PackageInfo>();
|
||||
if (package.LatestRelease != null) keyVersions.Add(package.LatestRelease);
|
||||
if (package.Current != null) keyVersions.Add(package.Current);
|
||||
if (package.Verified != null && package.Verified != package.Current) keyVersions.Add(package.Verified);
|
||||
if (package.LatestPatch != null && package.IsAfterCurrentVersion(package.LatestPatch)) keyVersions.Add(package.LatestPatch);
|
||||
if (package.Current == null && package.LatestRelease == null && package.Latest != null) keyVersions.Add(package.Latest);
|
||||
if (Package.ShouldProposeLatestVersions && package.Latest != package.LatestRelease && package.Latest != null) keyVersions.Add(package.Latest);
|
||||
keyVersions.Add(package.LatestUpdate); // Make sure LatestUpdate is always in the list.
|
||||
|
||||
foreach (var version in keyVersions.OrderBy(package => package.Version).Reverse())
|
||||
{
|
||||
var item = new VersionItem {Version = version};
|
||||
VersionItems.Add(item);
|
||||
|
||||
if (version == package.LatestUpdate)
|
||||
VersionPopup.value = item;
|
||||
}
|
||||
|
||||
//
|
||||
// Add all versions
|
||||
foreach (var version in package.Versions.Reverse())
|
||||
{
|
||||
var item = new VersionItem {Version = version};
|
||||
item.MenuName = "All Versions/";
|
||||
VersionItems.Add(item);
|
||||
}
|
||||
|
||||
if (VersionItems.Count == 0)
|
||||
{
|
||||
VersionItems.Add(EmptyVersion);
|
||||
VersionPopup.value = EmptyVersion;
|
||||
VersionPopup.SetEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetPackage(Package package)
|
||||
{
|
||||
if (this.package != null)
|
||||
{
|
||||
if (this.package.AddSignal.Operation != null)
|
||||
{
|
||||
this.package.AddSignal.Operation.OnOperationError -= OnAddOperationError;
|
||||
this.package.AddSignal.Operation.OnOperationSuccess -= OnAddOperationSuccess;
|
||||
}
|
||||
this.package.AddSignal.ResetEvents();
|
||||
|
||||
if (this.package.RemoveSignal.Operation != null)
|
||||
{
|
||||
this.package.RemoveSignal.Operation.OnOperationSuccess -= OnRemoveOperationSuccess;
|
||||
this.package.RemoveSignal.Operation.OnOperationError -= OnRemoveOperationError;
|
||||
}
|
||||
this.package.RemoveSignal.ResetEvents();
|
||||
}
|
||||
|
||||
UIUtils.SetElementDisplay(this, true);
|
||||
|
||||
this.package = package;
|
||||
var displayPackage = package != null ? package.VersionToDisplay : null;
|
||||
ResetVersionItems(displayPackage);
|
||||
SetDisplayPackage(displayPackage);
|
||||
}
|
||||
|
||||
private void SetError(Error error)
|
||||
{
|
||||
DetailError.AdjustSize(DetailView.verticalScroller.visible);
|
||||
DetailError.SetError(error);
|
||||
DetailError.OnCloseError = () =>
|
||||
{
|
||||
PackageCollection.Instance.RemovePackageErrors(package);
|
||||
PackageCollection.Instance.UpdatePackageCollection();
|
||||
};
|
||||
}
|
||||
|
||||
private void OnAddOperation(IAddOperation operation)
|
||||
{
|
||||
operation.OnOperationError += OnAddOperationError;
|
||||
operation.OnOperationSuccess += OnAddOperationSuccess;
|
||||
}
|
||||
|
||||
private void OnAddOperationError(Error error)
|
||||
{
|
||||
if (package != null && package.AddSignal.Operation != null)
|
||||
{
|
||||
package.AddSignal.Operation.OnOperationSuccess -= OnAddOperationSuccess;
|
||||
package.AddSignal.Operation.OnOperationError -= OnAddOperationError;
|
||||
package.AddSignal.Operation = null;
|
||||
}
|
||||
|
||||
PackageCollection.Instance.AddPackageError(package, error);
|
||||
|
||||
SetError(error);
|
||||
if (package != null)
|
||||
ResetVersionItems(package.VersionToDisplay);
|
||||
PackageCollection.Instance.UpdatePackageCollection();
|
||||
}
|
||||
|
||||
private void OnAddOperationSuccess(PackageInfo packageInfo)
|
||||
{
|
||||
if (package != null && package.AddSignal.Operation != null)
|
||||
{
|
||||
package.AddSignal.Operation.OnOperationSuccess -= OnAddOperationSuccess;
|
||||
package.AddSignal.Operation.OnOperationError -= OnAddOperationError;
|
||||
package.AddSignal.Operation = null;
|
||||
}
|
||||
|
||||
foreach (var extension in PackageManagerExtensions.Extensions)
|
||||
extension.OnPackageAddedOrUpdated(packageInfo.Info);
|
||||
}
|
||||
|
||||
private void OnRemoveOperation(IRemoveOperation operation)
|
||||
{
|
||||
// Make sure we are not already registered
|
||||
operation.OnOperationError -= OnRemoveOperationError;
|
||||
operation.OnOperationSuccess -= OnRemoveOperationSuccess;
|
||||
|
||||
operation.OnOperationError += OnRemoveOperationError;
|
||||
operation.OnOperationSuccess += OnRemoveOperationSuccess;
|
||||
}
|
||||
|
||||
private void OnRemoveOperationError(Error error)
|
||||
{
|
||||
if (package != null && package.RemoveSignal.Operation != null)
|
||||
{
|
||||
package.RemoveSignal.Operation.OnOperationSuccess -= OnRemoveOperationSuccess;
|
||||
package.RemoveSignal.Operation.OnOperationError -= OnRemoveOperationError;
|
||||
package.RemoveSignal.Operation = null;
|
||||
}
|
||||
|
||||
PackageCollection.Instance.AddPackageError(package, error);
|
||||
|
||||
SetError(error);
|
||||
PackageCollection.Instance.UpdatePackageCollection();
|
||||
}
|
||||
|
||||
private void OnRemoveOperationSuccess(PackageInfo packageInfo)
|
||||
{
|
||||
if (package != null && package.RemoveSignal.Operation != null)
|
||||
{
|
||||
package.RemoveSignal.Operation.OnOperationSuccess -= OnRemoveOperationSuccess;
|
||||
package.RemoveSignal.Operation.OnOperationError -= OnRemoveOperationError;
|
||||
package.RemoveSignal.Operation = null;
|
||||
}
|
||||
|
||||
foreach (var extension in PackageManagerExtensions.Extensions)
|
||||
extension.OnPackageRemoved(packageInfo.Info);
|
||||
}
|
||||
|
||||
private void RefreshAddButton()
|
||||
{
|
||||
if (package.Current != null && package.Current.IsInDevelopment)
|
||||
{
|
||||
UIUtils.SetElementDisplay(UpdateBuiltIn, false);
|
||||
UIUtils.SetElementDisplay(UpdateCombo, false);
|
||||
UIUtils.SetElementDisplay(UpdateButton, false);
|
||||
return;
|
||||
}
|
||||
|
||||
var targetVersion = SelectedPackage;
|
||||
if (targetVersion == null)
|
||||
return;
|
||||
|
||||
var enableButton = !Package.AddRemoveOperationInProgress;
|
||||
var enableVersionButton = true;
|
||||
|
||||
var action = PackageAction.Update;
|
||||
var inprogress = false;
|
||||
var isBuiltIn = package.IsBuiltIn;
|
||||
SemVersion version = null;
|
||||
|
||||
if (package.AddSignal.Operation != null)
|
||||
{
|
||||
if (isBuiltIn)
|
||||
{
|
||||
action = PackageAction.Enable;
|
||||
inprogress = true;
|
||||
enableButton = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var addOperationVersion = package.AddSignal.Operation.PackageInfo.Version;
|
||||
if (package.Current == null)
|
||||
{
|
||||
action = PackageAction.Add;
|
||||
inprogress = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
action = addOperationVersion.CompareByPrecedence(package.Current.Version) >= 0
|
||||
? PackageAction.Update : PackageAction.Downgrade;
|
||||
inprogress = true;
|
||||
}
|
||||
|
||||
enableButton = false;
|
||||
enableVersionButton = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (package.Current != null)
|
||||
{
|
||||
// Installed
|
||||
if (package.Current.IsVersionLocked)
|
||||
{
|
||||
if (package.Current.Origin == PackageSource.Embedded)
|
||||
action = PackageAction.Embedded;
|
||||
else if (package.Current.Origin == PackageSource.Git)
|
||||
action = PackageAction.Git;
|
||||
|
||||
enableButton = false;
|
||||
enableVersionButton = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (targetVersion.IsCurrent)
|
||||
{
|
||||
if (targetVersion == package.LatestUpdate)
|
||||
action = PackageAction.UpToDate;
|
||||
else
|
||||
action = PackageAction.Current;
|
||||
|
||||
enableButton = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
action = targetVersion.Version.CompareByPrecedence(package.Current.Version) >= 0
|
||||
? PackageAction.Update : PackageAction.Downgrade;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not Installed
|
||||
if (package.Versions.Any())
|
||||
{
|
||||
if (isBuiltIn)
|
||||
action = PackageAction.Enable;
|
||||
else
|
||||
action = PackageAction.Add;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (package.RemoveSignal.Operation != null)
|
||||
enableButton = false;
|
||||
|
||||
if (EditorApplication.isCompiling)
|
||||
{
|
||||
enableButton = false;
|
||||
enableVersionButton = false;
|
||||
|
||||
EditorApplication.update -= CheckCompilationStatus;
|
||||
EditorApplication.update += CheckCompilationStatus;
|
||||
}
|
||||
|
||||
var button = isBuiltIn ? UpdateBuiltIn : UpdateButton;
|
||||
button.SetEnabled(enableButton);
|
||||
VersionPopup.SetEnabled(enableVersionButton);
|
||||
button.text = GetButtonText(action, inprogress, version);
|
||||
|
||||
var visibleFlag = !(package.Current != null && package.Current.IsVersionLocked);
|
||||
UIUtils.SetElementDisplay(UpdateBuiltIn, isBuiltIn && visibleFlag);
|
||||
UIUtils.SetElementDisplay(UpdateCombo, !isBuiltIn && visibleFlag);
|
||||
UIUtils.SetElementDisplay(UpdateButton, !isBuiltIn && visibleFlag);
|
||||
}
|
||||
|
||||
private void RefreshRemoveButton()
|
||||
{
|
||||
var visibleFlag = false;
|
||||
|
||||
var current = package.Current;
|
||||
|
||||
// Show only if there is a current package installed
|
||||
if (current != null)
|
||||
{
|
||||
visibleFlag = current.CanBeRemoved && !package.IsPackageManagerUI;
|
||||
|
||||
var action = current.IsBuiltIn ? PackageAction.Disable : PackageAction.Remove;
|
||||
var inprogress = package.RemoveSignal.Operation != null;
|
||||
|
||||
var enableButton = visibleFlag && !EditorApplication.isCompiling && !inprogress && !Package.AddRemoveOperationInProgress;
|
||||
|
||||
if (EditorApplication.isCompiling)
|
||||
{
|
||||
EditorApplication.update -= CheckCompilationStatus;
|
||||
EditorApplication.update += CheckCompilationStatus;
|
||||
}
|
||||
|
||||
RemoveButton.SetEnabled(enableButton);
|
||||
RemoveButton.text = GetButtonText(action, inprogress);
|
||||
}
|
||||
|
||||
UIUtils.SetElementDisplay(RemoveButton, visibleFlag);
|
||||
}
|
||||
|
||||
private void CheckCompilationStatus()
|
||||
{
|
||||
if (EditorApplication.isCompiling)
|
||||
return;
|
||||
|
||||
RefreshAddButton();
|
||||
RefreshRemoveButton();
|
||||
EditorApplication.update -= CheckCompilationStatus;
|
||||
}
|
||||
|
||||
private static string GetButtonText(PackageAction action, bool inProgress = false, SemVersion version = null)
|
||||
{
|
||||
return version == null ?
|
||||
string.Format("{0}", inProgress ? PackageActionInProgressVerbs[(int) action] : PackageActionVerbs[(int) action]) :
|
||||
string.Format("{0} {1}", inProgress ? PackageActionInProgressVerbs[(int) action] : PackageActionVerbs[(int) action], version);
|
||||
}
|
||||
|
||||
private void UpdateClick()
|
||||
{
|
||||
if (package.IsPackageManagerUI)
|
||||
{
|
||||
// Let's not allow updating of the UI if there are build errrors, as for now, that will prevent the UI from reloading properly.
|
||||
if (EditorUtility.scriptCompilationFailed)
|
||||
{
|
||||
EditorUtility.DisplayDialog("Unity Package Manager", "The Package Manager UI cannot be updated while there are script compilation errors in your project. Please fix the errors and try again.", "Ok");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EditorUtility.DisplayDialog("Unity Package Manager", "Updating this package will close the Package Manager window. You will have to re-open it after the update is done. Do you want to continue?", "Yes", "No"))
|
||||
return;
|
||||
|
||||
if (package.AddSignal.Operation != null)
|
||||
{
|
||||
package.AddSignal.Operation.OnOperationSuccess -= OnAddOperationSuccess;
|
||||
package.AddSignal.Operation.OnOperationError -= OnAddOperationError;
|
||||
package.AddSignal.ResetEvents();
|
||||
package.AddSignal.Operation = null;
|
||||
}
|
||||
|
||||
DetailError.ClearError();
|
||||
EditorApplication.update += CloseAndUpdate;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DetailError.ClearError();
|
||||
package.Add(SelectedPackage);
|
||||
RefreshAddButton();
|
||||
RefreshRemoveButton();
|
||||
}
|
||||
|
||||
private void CloseAndUpdate()
|
||||
{
|
||||
EditorApplication.update -= CloseAndUpdate;
|
||||
package.Add(SelectedPackage);
|
||||
|
||||
var windows = UnityEngine.Resources.FindObjectsOfTypeAll<PackageManagerWindow>();
|
||||
if (windows.Length > 0)
|
||||
{
|
||||
windows[0].Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void RemoveClick()
|
||||
{
|
||||
DetailError.ClearError();
|
||||
package.Remove();
|
||||
RefreshRemoveButton();
|
||||
RefreshAddButton();
|
||||
}
|
||||
|
||||
|
||||
private void ViewDocClick()
|
||||
{
|
||||
Application.OpenURL(DisplayPackage.GetDocumentationUrl());
|
||||
}
|
||||
|
||||
private void ViewChangelogClick()
|
||||
{
|
||||
Application.OpenURL(DisplayPackage.GetChangelogUrl());
|
||||
}
|
||||
|
||||
private void ViewLicensesClick()
|
||||
{
|
||||
Application.OpenURL(DisplayPackage.GetLicensesUrl());
|
||||
}
|
||||
|
||||
private Label DetailDesc { get { return root.Q<Label>("detailDesc"); } }
|
||||
internal Button UpdateButton { get { return root.Q<Button>("update"); } }
|
||||
private Button RemoveButton { get { return root.Q<Button>("remove"); } }
|
||||
private Button ViewDocButton { get { return root.Q<Button>("viewDocumentation"); } }
|
||||
private VisualElement DocumentationContainer { get { return root.Q<VisualElement>("documentationContainer"); } }
|
||||
private Button ViewChangelogButton { get { return root.Q<Button>("viewChangelog"); } }
|
||||
private VisualElement ChangelogContainer { get { return root.Q<VisualElement>("changeLogContainer"); } }
|
||||
private VisualElement ViewLicensesContainer { get { return root.Q<VisualElement>("viewLicensesContainer"); } }
|
||||
private Button ViewLicenses { get { return root.Q<Button>("viewLicenses"); } }
|
||||
private VisualElement UpdateContainer { get { return root.Q<VisualElement>("updateContainer"); } }
|
||||
private Alert DetailError { get { return root.Q<Alert>("detailError"); } }
|
||||
private ScrollView DetailView { get { return root.Q<ScrollView>("detailView"); } }
|
||||
private Label DetailModuleReference { get { return root.Q<Label>("detailModuleReference"); } }
|
||||
private Label DetailVersion { get { return root.Q<Label>("detailVersion"); }}
|
||||
private Label DetailAuthor { get { return root.Q<Label>("detailAuthor"); }}
|
||||
private Label VerifyLabel { get { return root.Q<Label>("tagVerify"); } }
|
||||
private VisualElement CustomContainer { get { return root.Q<VisualElement>("detailCustomContainer"); } }
|
||||
internal VisualElement GetTag(PackageTag tag) {return root.Q<VisualElement>("tag-" + tag); }
|
||||
private VisualElement UpdateDropdownContainer { get { return root.Q<VisualElement>("updateDropdownContainer"); } }
|
||||
internal VisualElement UpdateCombo { get { return root.Q<VisualElement>("updateCombo"); } }
|
||||
internal Button UpdateBuiltIn { get { return root.Q<Button>("updateBuiltIn"); } }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3f3e22b18940a4e828a5170574a3617e
|
||||
timeCreated: 1502224642
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityEngine.Experimental.UIElements;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
internal static class PackageFiltering
|
||||
{
|
||||
private static bool FilterByText(PackageInfo info, string text)
|
||||
{
|
||||
if (info == null)
|
||||
return false;
|
||||
|
||||
if (info.Name.IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0)
|
||||
return true;
|
||||
|
||||
if (!string.IsNullOrEmpty(info.DisplayName) && info.DisplayName.IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0)
|
||||
return true;
|
||||
|
||||
if (!info.IsBuiltIn)
|
||||
{
|
||||
var prerelease = text.StartsWith("-") ? text.Substring(1) : text;
|
||||
if (info.Version != null && info.Version.Prerelease.IndexOf(prerelease, StringComparison.CurrentCultureIgnoreCase) >= 0)
|
||||
return true;
|
||||
|
||||
if (info.VersionWithoutTag.StartsWith(text, StringComparison.CurrentCultureIgnoreCase))
|
||||
return true;
|
||||
|
||||
if (info.IsPreview)
|
||||
{
|
||||
if (PackageTag.preview.ToString().IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (info.IsVerified)
|
||||
{
|
||||
if (PackageTag.verified.ToString().IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool FilterByText(Package package, string text)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return true;
|
||||
|
||||
var trimText = text.Trim(' ', '\t');
|
||||
trimText = Regex.Replace(trimText, @"[ ]{2,}", " ");
|
||||
return string.IsNullOrEmpty(trimText) || FilterByText(package.Current ?? package.Latest, trimText);
|
||||
}
|
||||
|
||||
private static bool FilterByText(PackageItem item, string text)
|
||||
{
|
||||
return item.package != null && FilterByText(item.package, text);
|
||||
}
|
||||
|
||||
public static void FilterPackageList(PackageList packageList)
|
||||
{
|
||||
PackageItem firstItem = null;
|
||||
PackageItem lastItem = null;
|
||||
var selectedItemInFilter = false;
|
||||
var selectedItem = packageList.selectedItem;
|
||||
var packageItems = packageList.Query<PackageItem>().ToList();
|
||||
foreach (var item in packageItems)
|
||||
{
|
||||
if (FilterByText(item, PackageSearchFilter.Instance.SearchText))
|
||||
{
|
||||
if (firstItem == null)
|
||||
firstItem = item;
|
||||
if (item == selectedItem)
|
||||
selectedItemInFilter = true;
|
||||
|
||||
UIUtils.SetElementDisplay(item, true);
|
||||
|
||||
if (lastItem != null)
|
||||
lastItem.nextItem = item;
|
||||
|
||||
item.previousItem = lastItem;
|
||||
item.nextItem = null;
|
||||
|
||||
lastItem = item;
|
||||
}
|
||||
else
|
||||
UIUtils.SetElementDisplay(item, false);
|
||||
}
|
||||
|
||||
if (firstItem == null)
|
||||
packageList.ShowNoResults();
|
||||
else
|
||||
packageList.ShowResults(selectedItemInFilter ? selectedItem : firstItem);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5ffd2adf615994485991e37bacbf735c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,75 @@
|
|||
using System.Linq;
|
||||
using UnityEngine.Experimental.UIElements;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
internal class PackageGroupFactory : UxmlFactory<PackageGroup>
|
||||
{
|
||||
protected override PackageGroup DoCreate(IUxmlAttributes bag, CreationContext cc)
|
||||
{
|
||||
return new PackageGroup(bag.GetPropertyString("name"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal class PackageGroup : VisualElement
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
internal new class UxmlFactory : UxmlFactory<PackageGroup> { }
|
||||
#endif
|
||||
|
||||
private readonly VisualElement root;
|
||||
internal readonly PackageGroupOrigins Origin;
|
||||
|
||||
public PackageGroup previousGroup;
|
||||
public PackageGroup nextGroup;
|
||||
|
||||
public PackageItem firstPackage;
|
||||
public PackageItem lastPackage;
|
||||
|
||||
public PackageGroup() : this(string.Empty)
|
||||
{
|
||||
}
|
||||
|
||||
public PackageGroup(string groupName)
|
||||
{
|
||||
name = groupName;
|
||||
root = Resources.GetTemplate("PackageGroup.uxml");
|
||||
Add(root);
|
||||
|
||||
if (string.IsNullOrEmpty(groupName) || groupName != PackageGroupOrigins.BuiltInPackages.ToString())
|
||||
{
|
||||
HeaderTitle.text = "Packages";
|
||||
Origin = PackageGroupOrigins.Packages;
|
||||
}
|
||||
else
|
||||
{
|
||||
HeaderTitle.text = "Built In Packages";
|
||||
Origin = PackageGroupOrigins.BuiltInPackages;
|
||||
}
|
||||
}
|
||||
|
||||
internal PackageItem AddPackage(Package package)
|
||||
{
|
||||
var packageItem = new PackageItem(package) {packageGroup = this};
|
||||
var lastItem = List.Children().LastOrDefault() as PackageItem;
|
||||
if (lastItem != null)
|
||||
{
|
||||
lastItem.nextItem = packageItem;
|
||||
packageItem.previousItem = lastItem;
|
||||
packageItem.nextItem = null;
|
||||
}
|
||||
|
||||
List.Add(packageItem);
|
||||
|
||||
if (firstPackage == null) firstPackage = packageItem;
|
||||
lastPackage = packageItem;
|
||||
|
||||
return packageItem;
|
||||
}
|
||||
|
||||
private VisualElement List { get { return root.Q<VisualElement>("groupContainer"); } }
|
||||
private Label HeaderTitle { get { return root.Q<Label>("headerTitle"); } }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 760934a36e5f490db3c9fcaf497625a4
|
||||
timeCreated: 1508509771
|
|
@ -0,0 +1,150 @@
|
|||
using UnityEngine.Experimental.UIElements;
|
||||
using System;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
internal class PackageItemFactory : UxmlFactory<PackageItem>
|
||||
{
|
||||
protected override PackageItem DoCreate(IUxmlAttributes bag, CreationContext cc)
|
||||
{
|
||||
return new PackageItem();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal class PackageItem : VisualElement
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
internal new class UxmlFactory : UxmlFactory<PackageItem> { }
|
||||
#endif
|
||||
|
||||
public static string SelectedClassName = "selected";
|
||||
|
||||
public event Action<PackageItem> OnSelected = delegate { };
|
||||
|
||||
private readonly VisualElement root;
|
||||
private string currentStateClass;
|
||||
public Package package { get; private set; }
|
||||
|
||||
public PackageItem previousItem;
|
||||
public PackageItem nextItem;
|
||||
|
||||
public PackageGroup packageGroup;
|
||||
|
||||
public PackageItem() : this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public PackageItem(Package package)
|
||||
{
|
||||
root = Resources.GetTemplate("PackageItem.uxml");
|
||||
Add(root);
|
||||
|
||||
root.AddManipulator(new Clickable(Select));
|
||||
SetItem(package);
|
||||
}
|
||||
|
||||
private void Select()
|
||||
{
|
||||
OnSelected(this);
|
||||
}
|
||||
|
||||
public void SetSelected(bool value)
|
||||
{
|
||||
if (value)
|
||||
PackageContainer.AddToClassList(SelectedClassName);
|
||||
else
|
||||
PackageContainer.RemoveFromClassList(SelectedClassName);
|
||||
|
||||
Spinner.InvertColor = value;
|
||||
}
|
||||
|
||||
private void SetItem(Package package)
|
||||
{
|
||||
var displayPackage = package != null ? package.VersionToDisplay : null;
|
||||
if (displayPackage == null)
|
||||
return;
|
||||
|
||||
this.package = package;
|
||||
OnPackageChanged();
|
||||
this.package.AddSignal.WhenOperation(OnPackageAdd);
|
||||
this.package.RemoveSignal.WhenOperation(OnPackageRemove);
|
||||
}
|
||||
|
||||
private void OnPackageRemove(IRemoveOperation operation)
|
||||
{
|
||||
operation.OnOperationError += error => StopSpinner();
|
||||
OnPackageUpdate();
|
||||
}
|
||||
|
||||
private void OnPackageAdd(IAddOperation operation)
|
||||
{
|
||||
operation.OnOperationError += error => StopSpinner();
|
||||
OnPackageUpdate();
|
||||
}
|
||||
|
||||
private void OnPackageChanged()
|
||||
{
|
||||
var displayPackage = package != null ? package.VersionToDisplay : null;
|
||||
if (displayPackage == null)
|
||||
return;
|
||||
|
||||
NameLabel.text = displayPackage.DisplayName;
|
||||
VersionLabel.text = displayPackage.Version.ToString();
|
||||
|
||||
var stateClass = GetIconStateId(displayPackage);
|
||||
if (displayPackage.State == PackageState.Outdated && package.LatestUpdate == package.Current)
|
||||
stateClass = GetIconStateId(PackageState.UpToDate);
|
||||
if (PackageCollection.Instance.GetPackageError(package) != null)
|
||||
stateClass = GetIconStateId(PackageState.Error);
|
||||
if (stateClass == GetIconStateId(PackageState.UpToDate) && package.Current != null)
|
||||
stateClass = "installed";
|
||||
|
||||
StateLabel.RemoveFromClassList(currentStateClass);
|
||||
StateLabel.AddToClassList(stateClass);
|
||||
|
||||
UIUtils.SetElementDisplay(VersionLabel, !displayPackage.IsBuiltIn);
|
||||
|
||||
currentStateClass = stateClass;
|
||||
if (displayPackage.State != PackageState.InProgress && Spinner.Started)
|
||||
StopSpinner();
|
||||
}
|
||||
|
||||
private void OnPackageUpdate()
|
||||
{
|
||||
StartSpinner();
|
||||
}
|
||||
|
||||
private void StartSpinner()
|
||||
{
|
||||
Spinner.Start();
|
||||
StateLabel.AddToClassList("no-icon");
|
||||
}
|
||||
|
||||
private void StopSpinner()
|
||||
{
|
||||
Spinner.Stop();
|
||||
StateLabel.RemoveFromClassList("no-icon");
|
||||
}
|
||||
|
||||
private Label NameLabel { get { return root.Q<Label>("packageName"); } }
|
||||
private Label StateLabel { get { return root.Q<Label>("packageState"); } }
|
||||
private Label VersionLabel { get { return root.Q<Label>("packageVersion"); } }
|
||||
private VisualElement PackageContainer { get { return root.Q<VisualElement>("packageContainer"); } }
|
||||
private LoadingSpinner Spinner { get { return root.Q<LoadingSpinner>("packageSpinner"); } }
|
||||
|
||||
public static string GetIconStateId(PackageInfo packageInfo)
|
||||
{
|
||||
if (packageInfo == null)
|
||||
return "";
|
||||
|
||||
return GetIconStateId(packageInfo.State);
|
||||
}
|
||||
|
||||
public static string GetIconStateId(PackageState state)
|
||||
{
|
||||
return state.ToString().ToLower();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c68ba5b432ef64e67ae0bf74960908a8
|
||||
timeCreated: 1502224642
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,408 @@
|
|||
using UnityEngine.Experimental.UIElements;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
internal class PackageListFactory : UxmlFactory<PackageList>
|
||||
{
|
||||
protected override PackageList DoCreate(IUxmlAttributes bag, CreationContext cc)
|
||||
{
|
||||
return new PackageList();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
internal class PackageList : VisualElement
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
internal new class UxmlFactory : UxmlFactory<PackageList> { }
|
||||
#endif
|
||||
|
||||
public event Action<Package> OnSelected = delegate { };
|
||||
public event Action OnLoaded = delegate { };
|
||||
public event Action OnFocusChange = delegate { };
|
||||
|
||||
private readonly VisualElement root;
|
||||
internal PackageItem selectedItem;
|
||||
private List<PackageGroup> Groups;
|
||||
|
||||
public PackageList()
|
||||
{
|
||||
Groups = new List<PackageGroup>();
|
||||
|
||||
root = Resources.GetTemplate("PackageList.uxml");
|
||||
Add(root);
|
||||
root.StretchToParentSize();
|
||||
|
||||
UIUtils.SetElementDisplay(Empty, false);
|
||||
UIUtils.SetElementDisplay(NoResult, false);
|
||||
|
||||
PackageCollection.Instance.OnPackagesChanged += SetPackages;
|
||||
|
||||
RegisterCallback<AttachToPanelEvent>(OnEnterPanel);
|
||||
RegisterCallback<DetachFromPanelEvent>(OnLeavePanel);
|
||||
|
||||
Reload();
|
||||
}
|
||||
|
||||
public void GrabFocus()
|
||||
{
|
||||
if (selectedItem == null)
|
||||
return;
|
||||
|
||||
selectedItem.Focus();
|
||||
}
|
||||
|
||||
public void ShowResults(PackageItem item)
|
||||
{
|
||||
NoResultText.text = string.Empty;
|
||||
UIUtils.SetElementDisplay(NoResult, false);
|
||||
|
||||
Select(item);
|
||||
|
||||
EditorApplication.delayCall += ScrollIfNeeded;
|
||||
|
||||
UpdateGroups();
|
||||
}
|
||||
|
||||
public void ShowNoResults()
|
||||
{
|
||||
NoResultText.text = string.Format("No results for \"{0}\"", PackageSearchFilter.Instance.SearchText);
|
||||
UIUtils.SetElementDisplay(NoResult, true);
|
||||
foreach (var group in Groups)
|
||||
{
|
||||
UIUtils.SetElementDisplay(group, false);
|
||||
}
|
||||
Select(null);
|
||||
OnSelected(null);
|
||||
}
|
||||
|
||||
private void UpdateGroups()
|
||||
{
|
||||
foreach (var group in Groups)
|
||||
{
|
||||
PackageItem firstPackage = null;
|
||||
PackageItem lastPackage = null;
|
||||
|
||||
var listGroup = group.Query<PackageItem>().ToList();
|
||||
foreach (var item in listGroup)
|
||||
{
|
||||
if (!item.visible)
|
||||
continue;
|
||||
|
||||
if (firstPackage == null) firstPackage = item;
|
||||
lastPackage = item;
|
||||
}
|
||||
|
||||
if (firstPackage == null && lastPackage == null)
|
||||
{
|
||||
UIUtils.SetElementDisplay(group, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
UIUtils.SetElementDisplay(group, true);
|
||||
group.firstPackage = firstPackage;
|
||||
group.lastPackage = lastPackage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnterPanel(AttachToPanelEvent e)
|
||||
{
|
||||
panel.visualTree.RegisterCallback<KeyDownEvent>(OnKeyDownShortcut);
|
||||
}
|
||||
|
||||
private void OnLeavePanel(DetachFromPanelEvent e)
|
||||
{
|
||||
panel.visualTree.UnregisterCallback<KeyDownEvent>(OnKeyDownShortcut);
|
||||
}
|
||||
|
||||
private void ScrollIfNeeded()
|
||||
{
|
||||
EditorApplication.delayCall -= ScrollIfNeeded;
|
||||
|
||||
if (selectedItem == null)
|
||||
return;
|
||||
|
||||
var minY = List.worldBound.yMin;
|
||||
var maxY = List.worldBound.yMax;
|
||||
var itemMinY = selectedItem.worldBound.yMin;
|
||||
var itemMaxY = selectedItem.worldBound.yMax;
|
||||
var scroll = List.scrollOffset;
|
||||
|
||||
if (itemMinY < minY)
|
||||
{
|
||||
scroll.y -= minY - itemMinY;
|
||||
if (scroll.y <= minY)
|
||||
scroll.y = 0;
|
||||
List.scrollOffset = scroll;
|
||||
}
|
||||
else if (itemMaxY > maxY)
|
||||
{
|
||||
scroll.y += itemMaxY - maxY;
|
||||
List.scrollOffset = scroll;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnKeyDownShortcut(KeyDownEvent evt)
|
||||
{
|
||||
if (selectedItem == null)
|
||||
return;
|
||||
|
||||
if (evt.keyCode == KeyCode.Tab)
|
||||
{
|
||||
OnFocusChange();
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.keyCode == KeyCode.UpArrow)
|
||||
{
|
||||
if (selectedItem.previousItem != null)
|
||||
{
|
||||
Select(selectedItem.previousItem);
|
||||
ScrollIfNeeded();
|
||||
}
|
||||
else if (selectedItem.packageGroup.previousGroup != null && selectedItem.packageGroup.previousGroup.visible)
|
||||
{
|
||||
Select(selectedItem.packageGroup.previousGroup.lastPackage);
|
||||
ScrollIfNeeded();
|
||||
}
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.keyCode == KeyCode.DownArrow)
|
||||
{
|
||||
if (selectedItem.nextItem != null)
|
||||
{
|
||||
Select(selectedItem.nextItem);
|
||||
ScrollIfNeeded();
|
||||
}
|
||||
else if (selectedItem.packageGroup.nextGroup != null && selectedItem.packageGroup.nextGroup.visible)
|
||||
{
|
||||
Select(selectedItem.packageGroup.nextGroup.firstPackage);
|
||||
ScrollIfNeeded();
|
||||
}
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.keyCode == KeyCode.PageUp)
|
||||
{
|
||||
if (selectedItem.packageGroup != null)
|
||||
{
|
||||
if (selectedItem == selectedItem.packageGroup.lastPackage && selectedItem != selectedItem.packageGroup.firstPackage)
|
||||
{
|
||||
Select(selectedItem.packageGroup.firstPackage);
|
||||
ScrollIfNeeded();
|
||||
}
|
||||
else if (selectedItem == selectedItem.packageGroup.firstPackage && selectedItem.packageGroup.previousGroup != null && selectedItem.packageGroup.previousGroup.visible)
|
||||
{
|
||||
Select(selectedItem.packageGroup.previousGroup.lastPackage);
|
||||
ScrollIfNeeded();
|
||||
}
|
||||
else if (selectedItem != selectedItem.packageGroup.lastPackage && selectedItem != selectedItem.packageGroup.firstPackage)
|
||||
{
|
||||
Select(selectedItem.packageGroup.firstPackage);
|
||||
ScrollIfNeeded();
|
||||
}
|
||||
}
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.keyCode == KeyCode.PageDown)
|
||||
{
|
||||
if (selectedItem.packageGroup != null)
|
||||
{
|
||||
if (selectedItem == selectedItem.packageGroup.firstPackage && selectedItem != selectedItem.packageGroup.lastPackage)
|
||||
{
|
||||
Select(selectedItem.packageGroup.lastPackage);
|
||||
ScrollIfNeeded();
|
||||
}
|
||||
else if (selectedItem == selectedItem.packageGroup.lastPackage && selectedItem.packageGroup.nextGroup != null && selectedItem.packageGroup.nextGroup.visible)
|
||||
{
|
||||
Select(selectedItem.packageGroup.nextGroup.firstPackage);
|
||||
ScrollIfNeeded();
|
||||
}
|
||||
else if (selectedItem != selectedItem.packageGroup.firstPackage && selectedItem != selectedItem.packageGroup.lastPackage)
|
||||
{
|
||||
Select(selectedItem.packageGroup.lastPackage);
|
||||
ScrollIfNeeded();
|
||||
}
|
||||
}
|
||||
evt.StopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
private void Reload()
|
||||
{
|
||||
// Force a re-init to initial condition
|
||||
PackageCollection.Instance.UpdatePackageCollection();
|
||||
SelectLastSelection();
|
||||
}
|
||||
|
||||
private void ClearAll()
|
||||
{
|
||||
List.Clear();
|
||||
Groups.Clear();
|
||||
|
||||
UIUtils.SetElementDisplay(Empty, false);
|
||||
UIUtils.SetElementDisplay(NoResult, false);
|
||||
}
|
||||
|
||||
private void SetPackages(IEnumerable<Package> packages)
|
||||
{
|
||||
if (PackageCollection.Instance.Filter == PackageFilter.Modules)
|
||||
{
|
||||
packages = packages.Where(pkg => pkg.IsBuiltIn);
|
||||
}
|
||||
else if (PackageCollection.Instance.Filter== PackageFilter.All)
|
||||
{
|
||||
packages = packages.Where(pkg => !pkg.IsBuiltIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
packages = packages.Where(pkg => !pkg.IsBuiltIn);
|
||||
packages = packages.Where(pkg => pkg.Current != null);
|
||||
}
|
||||
|
||||
OnLoaded();
|
||||
ClearAll();
|
||||
|
||||
var packagesGroup = new PackageGroup(PackageGroupOrigins.Packages.ToString());
|
||||
Groups.Add(packagesGroup);
|
||||
List.Add(packagesGroup);
|
||||
packagesGroup.previousGroup = null;
|
||||
|
||||
var builtInGroup = new PackageGroup(PackageGroupOrigins.BuiltInPackages.ToString());
|
||||
Groups.Add(builtInGroup);
|
||||
List.Add(builtInGroup);
|
||||
|
||||
if ((PackageCollection.Instance.Filter & PackageFilter.Modules) == PackageFilter.Modules)
|
||||
{
|
||||
packagesGroup.nextGroup = builtInGroup;
|
||||
builtInGroup.previousGroup = packagesGroup;
|
||||
builtInGroup.nextGroup = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
packagesGroup.nextGroup = null;
|
||||
UIUtils.SetElementDisplay(builtInGroup, false);
|
||||
}
|
||||
|
||||
var lastSelection = PackageCollection.Instance.SelectedPackage;
|
||||
Select(null);
|
||||
|
||||
PackageItem defaultSelection = null;
|
||||
|
||||
foreach (var package in packages.OrderBy(pkg => pkg.Versions.FirstOrDefault() == null ? pkg.Name : pkg.Versions.FirstOrDefault().DisplayName))
|
||||
{
|
||||
var item = AddPackage(package);
|
||||
|
||||
if (null == selectedItem && defaultSelection == null)
|
||||
defaultSelection = item;
|
||||
|
||||
if (null == selectedItem && !string.IsNullOrEmpty(lastSelection) && package.Name.Equals(lastSelection))
|
||||
Select(item);
|
||||
}
|
||||
|
||||
if (selectedItem == null)
|
||||
Select(defaultSelection);
|
||||
|
||||
PackageFiltering.FilterPackageList(this);
|
||||
}
|
||||
|
||||
public void SelectLastSelection()
|
||||
{
|
||||
var lastSelection = PackageCollection.Instance.SelectedPackage;
|
||||
if (lastSelection == null)
|
||||
return;
|
||||
|
||||
var list = List.Query<PackageItem>().ToList();
|
||||
PackageItem defaultSelection = null;
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
if (defaultSelection == null)
|
||||
defaultSelection = item;
|
||||
|
||||
if (!string.IsNullOrEmpty(lastSelection) && item.package.Name.Equals(lastSelection))
|
||||
{
|
||||
defaultSelection = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
selectedItem = null;
|
||||
Select(defaultSelection);
|
||||
}
|
||||
|
||||
private PackageItem AddPackage(Package package)
|
||||
{
|
||||
var groupName = package.Latest != null ? package.Latest.Group : package.Current.Group;
|
||||
var group = GetOrCreateGroup(groupName);
|
||||
var packageItem = group.AddPackage(package);
|
||||
|
||||
packageItem.OnSelected += Select;
|
||||
|
||||
return packageItem;
|
||||
}
|
||||
|
||||
private PackageGroup GetOrCreateGroup(string groupName)
|
||||
{
|
||||
foreach (var g in Groups)
|
||||
{
|
||||
if (g.name == groupName)
|
||||
return g;
|
||||
}
|
||||
|
||||
var group = new PackageGroup(groupName);
|
||||
var latestGroup = Groups.LastOrDefault();
|
||||
Groups.Add(group);
|
||||
List.Add(group);
|
||||
|
||||
group.previousGroup = null;
|
||||
if (latestGroup != null)
|
||||
{
|
||||
latestGroup.nextGroup = group;
|
||||
group.previousGroup = latestGroup;
|
||||
group.nextGroup = null;
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
private void Select(PackageItem packageItem)
|
||||
{
|
||||
if (packageItem == selectedItem)
|
||||
return;
|
||||
|
||||
var selectedPackageName = packageItem != null ? packageItem.package.Name : null;
|
||||
PackageCollection.Instance.SelectedPackage = selectedPackageName;
|
||||
|
||||
if (selectedItem != null)
|
||||
selectedItem.SetSelected(false); // Clear Previous selection
|
||||
|
||||
selectedItem = packageItem;
|
||||
if (selectedItem == null)
|
||||
{
|
||||
OnSelected(null);
|
||||
return;
|
||||
}
|
||||
|
||||
selectedItem.SetSelected(true);
|
||||
ScrollIfNeeded();
|
||||
OnSelected(selectedItem.package);
|
||||
}
|
||||
|
||||
private ScrollView List { get { return root.Q<ScrollView>("scrollView"); } }
|
||||
private VisualElement Empty { get { return root.Q<VisualElement>("emptyArea"); } }
|
||||
private VisualElement NoResult { get { return root.Q<VisualElement>("noResult"); } }
|
||||
private Label NoResultText { get { return root.Q<Label>("noResultText"); } }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2d77b2d58287d46a6a61f12c861bfc2f
|
||||
timeCreated: 1502224642
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.PackageManager.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Package Manager UI Extensions
|
||||
/// </summary>
|
||||
public static class PackageManagerExtensions
|
||||
{
|
||||
internal static List<IPackageManagerExtension> Extensions { get { return extensions ?? (extensions = new List<IPackageManagerExtension>()); } }
|
||||
private static List<IPackageManagerExtension> extensions;
|
||||
|
||||
/// <summary>
|
||||
/// Registers a new Package Manager UI extension
|
||||
/// </summary>
|
||||
/// <param name="extension">A Package Manager UI extension</param>
|
||||
public static void RegisterExtension(IPackageManagerExtension extension)
|
||||
{
|
||||
if (extension == null)
|
||||
return;
|
||||
|
||||
Extensions.Add(extension);
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue