feat(mosstank): add VTank-style automation PoC
This commit is contained in:
parent
f6fe0f2a4f
commit
4e6e9bc9d9
212 changed files with 49462 additions and 416 deletions
97
src/AcDream.Plugins.MossTank/MetaViewManager.cs
Normal file
97
src/AcDream.Plugins.MossTank/MetaViewManager.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using AcDream.Plugin.Abstractions;
|
||||
|
||||
namespace AcDream.Plugins.MossTank;
|
||||
|
||||
/// <summary>
|
||||
/// Owns VTank Meta-created views independently from the macro window. The
|
||||
/// official implementation replaces duplicate names and permits five normal
|
||||
/// entries (including its historical sixth-entry boundary quirk).
|
||||
/// </summary>
|
||||
internal sealed class MetaViewManager
|
||||
{
|
||||
private const int OfficialViewLimit = 5;
|
||||
private readonly IPluginHost _host;
|
||||
private readonly Dictionary<string, IDisposable> _views =
|
||||
new(StringComparer.Ordinal);
|
||||
|
||||
public MetaViewManager(IPluginHost host) =>
|
||||
_host = host ?? throw new ArgumentNullException(nameof(host));
|
||||
|
||||
public int Count => _views.Count;
|
||||
|
||||
public bool Create(string name, string markup)
|
||||
{
|
||||
if (!_host.HasUi || string.IsNullOrEmpty(name) || string.IsNullOrEmpty(markup))
|
||||
return false;
|
||||
|
||||
// bw.a(string,string) checks Count > 5 before duplicate replacement.
|
||||
// Preserve that observable VTank quirk for imported Meta profiles.
|
||||
if (_views.Count > OfficialViewLimit)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
XElement root = XDocument.Parse(markup).Root
|
||||
?? throw new InvalidDataException("View markup has no root element.");
|
||||
if (!root.Name.LocalName.Equals("panel", StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
}
|
||||
catch (Exception error) when (error is InvalidDataException or System.Xml.XmlException)
|
||||
{
|
||||
_host.Log.Warn($"MossTank Meta view '{name}' is invalid: {error.Message}");
|
||||
return false;
|
||||
}
|
||||
|
||||
Destroy(name);
|
||||
IDisposable token = _host.Ui.RegisterPanelContent(
|
||||
new PluginPanelDescriptor(WindowId(name), name)
|
||||
{
|
||||
IconText = Initials(name),
|
||||
StartVisible = true,
|
||||
ShowInSidePanel = true,
|
||||
},
|
||||
markup,
|
||||
MetaViewBinding.Instance);
|
||||
_views.Add(name, token);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Destroy(string name)
|
||||
{
|
||||
if (!_views.Remove(name, out IDisposable? registration))
|
||||
return false;
|
||||
registration.Dispose();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void DestroyAll()
|
||||
{
|
||||
IDisposable[] registrations = _views.Values.ToArray();
|
||||
_views.Clear();
|
||||
foreach (IDisposable registration in registrations)
|
||||
registration.Dispose();
|
||||
}
|
||||
|
||||
private static string WindowId(string name)
|
||||
{
|
||||
byte[] hash = SHA256.HashData(Encoding.UTF8.GetBytes(name));
|
||||
return "meta-" + Convert.ToHexString(hash.AsSpan(0, 8)).ToLowerInvariant();
|
||||
}
|
||||
|
||||
private static string Initials(string name)
|
||||
{
|
||||
string[] words = name.Split(' ', StringSplitOptions.RemoveEmptyEntries);
|
||||
if (words.Length == 0)
|
||||
return "M";
|
||||
return string.Concat(words.Take(2).Select(static word => word[0])).ToUpperInvariant();
|
||||
}
|
||||
|
||||
private sealed class MetaViewBinding
|
||||
{
|
||||
internal static MetaViewBinding Instance { get; } = new();
|
||||
public bool WindowAvailable => true;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue