diff --git a/src/AcDream.Plugins.MossTank/MossTankPanel.cs b/src/AcDream.Plugins.MossTank/MossTankPanel.cs
index 787abb9c6..cb6983af8 100644
--- a/src/AcDream.Plugins.MossTank/MossTankPanel.cs
+++ b/src/AcDream.Plugins.MossTank/MossTankPanel.cs
@@ -850,6 +850,7 @@ internal sealed partial class MossTankPanel
public Action CreateProfile => () => CreateProfileCore(copyCurrent: false);
public Action CopyProfile => () => CreateProfileCore(copyCurrent: true);
public Action ClearProfile => ClearProfileCore;
+ public Action DeleteProfile => DeleteProfileCore;
public Action ToggleMineOnly => () =>
{
string before = _profiles.Selected;
@@ -3465,6 +3466,17 @@ internal sealed partial class MossTankPanel
ResetProfileConsumers();
}
+ private void DeleteProfileCore()
+ {
+ if (!_profiles.Delete(out string notice))
+ {
+ _profileLifecycleNotice = notice;
+ return;
+ }
+ LoadSelectedProfile();
+ _profileLifecycleNotice = notice;
+ }
+
private void LoadSelectedProfile()
{
_profiles.LoadCurrent(_allSettings, _noBuffItemNames);
diff --git a/src/AcDream.Plugins.MossTank/MossTankProfileStore.cs b/src/AcDream.Plugins.MossTank/MossTankProfileStore.cs
index 003bfc4ce..40d0c03ae 100644
--- a/src/AcDream.Plugins.MossTank/MossTankProfileStore.cs
+++ b/src/AcDream.Plugins.MossTank/MossTankProfileStore.cs
@@ -217,6 +217,33 @@ internal sealed class MossTankProfileStore
return true;
}
+ ///
+ /// Deletes the currently selected named profile's .usd file and
+ /// its side-car, then falls back to . Refuses
+ /// for itself — there is no file to delete,
+ /// only a reset (see ).
+ ///
+ public bool Delete(out string notice)
+ {
+ if (_selected.Equals(ByCharacter, StringComparison.OrdinalIgnoreCase))
+ {
+ notice = "'By char' is the built-in character profile and cannot be deleted.";
+ return false;
+ }
+ string fileName = _selected;
+ if (VtankStorage.IsAvailable)
+ VtankStorage.Delete(fileName);
+ if (_host.Storage.IsAvailable)
+ _host.Storage.Delete(SideCarKey(fileName));
+ _selected = ByCharacter;
+ _pendingLegacyBareName = null;
+ _currentDatabase = null;
+ _currentDatabaseFileName = null;
+ WriteBinding();
+ notice = $"Deleted profile {fileName}.";
+ return true;
+ }
+
public void LoadCurrent(
VtankSettingsProfileSerializer.AllSettings settings,
ISet noBuffItemNames)
diff --git a/src/AcDream.Plugins.MossTank/mosstank.xml b/src/AcDream.Plugins.MossTank/mosstank.xml
index 84dfdd7b4..f89fcff1a 100644
--- a/src/AcDream.Plugins.MossTank/mosstank.xml
+++ b/src/AcDream.Plugins.MossTank/mosstank.xml
@@ -136,6 +136,9 @@
onclick="{CreateProfile}" />
+
diff --git a/tests/AcDream.Plugins.MossTank.Tests/MossTankMarkupContractTests.cs b/tests/AcDream.Plugins.MossTank.Tests/MossTankMarkupContractTests.cs
index eddad0027..a9a491d90 100644
--- a/tests/AcDream.Plugins.MossTank.Tests/MossTankMarkupContractTests.cs
+++ b/tests/AcDream.Plugins.MossTank.Tests/MossTankMarkupContractTests.cs
@@ -88,7 +88,7 @@ public sealed class MossTankMarkupContractTests
XElement[] controls = root.Descendants()
.Where(element => interactive.Contains(element.Name.LocalName))
.ToArray();
- Assert.Equal(190, controls.Length);
+ Assert.Equal(191, controls.Length);
foreach (XElement control in controls)
{
diff --git a/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs b/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs
index dae614c9a..bc17592bb 100644
--- a/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs
+++ b/tests/AcDream.Plugins.MossTank.Tests/MossTankPanelTests.cs
@@ -846,6 +846,42 @@ public sealed class MossTankPanelTests
Assert.Equal(0.88f, panel.NormalHealthValue, precision: 2);
}
+ // Campaign VT slice 1 Part A round 2 step 5: the Profiles tab's new
+ // Delete button (mosstank.xml), bound through DeleteProfile exactly
+ // like every other markup action.
+ [Fact]
+ public void DeleteProfileRemovesTheRealFileAndFallsBackToByCharacter()
+ {
+ var storage = new MemoryStorage();
+ var automation = new FakeAutomation { Name = "Moss Wart" };
+ var panel = new MossTankPanel(new FakeHost(automation, storage));
+ panel.SetNormalHealth(0.42f);
+ panel.SetProfileNameDraft("Fellowship");
+ panel.CopyProfile();
+ const string fellowshipFile = "--Moss Wart__Fellowship.usd";
+ Assert.Equal(fellowshipFile, panel.SelectedMacroProfile);
+ Assert.Contains(fellowshipFile, panel.MacroProfileNames);
+
+ panel.DeleteProfile();
+
+ Assert.Equal(MossTankProfileStore.ByCharacter, panel.SelectedMacroProfile);
+ Assert.DoesNotContain(fellowshipFile, panel.MacroProfileNames);
+ Assert.False(storage.Text.ContainsKey(fellowshipFile));
+ Assert.Contains("Deleted", panel.ProfileLifecycleNotice, StringComparison.Ordinal);
+ }
+
+ [Fact]
+ public void DeleteProfileRefusesToRemoveByCharacter()
+ {
+ var storage = new MemoryStorage();
+ var panel = new MossTankPanel(new FakeHost(new FakeAutomation(), storage));
+
+ panel.DeleteProfile();
+
+ Assert.Equal(MossTankProfileStore.ByCharacter, panel.SelectedMacroProfile);
+ Assert.Contains("cannot be deleted", panel.ProfileLifecycleNotice, StringComparison.Ordinal);
+ }
+
// Item J (slice-1 fix round): renamed from
// NavCommandsImportAndExportExactVtankNavFiles — .af is a real writer
// output now (item E's header/fold-marker emission), not a byte-exact