feat(vt): round 3 item 10 — Delete action for Meta/Route/Loot profiles
Round 2 step 5 gave the settings Profiles tab a Delete action; Meta, Route, and Loot never got the same verb. Added MossTankMetaProfileStore.Delete, MossTankRouteProfileStore.Delete, and MossTankLootProfileStore.Delete (same contract as Settings: remove the selected named profile's real file, fall back to By char; refuse for By char itself, which has nothing to delete — see each store's ClearCurrent for that case), wired through MossTankPanel.DeleteMetaProfile/DeleteRouteProfile/DeleteLootProfile to three new "Delete" buttons in mosstank.xml (Route tab row, the Meta tab's button row, and the Loot rule editor's button row). MossTankMarkupContractTests' interactive-control count moves 191 -> 194 for the three new buttons. Mutation: reverted all four .cs files and mosstank.xml to HEAD (keeping only the new/changed tests) — the test project failed to even COMPILE (DeleteRouteProfile/DeleteMetaProfile/DeleteLootProfile do not exist on MossTankPanel), confirming the six new behavioral tests (DeleteRouteProfile/DeleteMetaProfile/DeleteLootProfile, each with a successful-delete and a refuse-by-char case) and the markup-count update all depend on this commit's code. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
43482c1380
commit
fbb584436b
7 changed files with 213 additions and 3 deletions
|
|
@ -238,6 +238,29 @@ internal sealed class MossTankLootProfileStore
|
|||
WriteUtl(fileName, profile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round 3 item 10: deletes the currently selected named loot profile's
|
||||
/// real <c>.utl</c> file, then falls back to <see cref="ByCharacter"/>.
|
||||
/// Refuses for <see cref="ByCharacter"/> itself — there is no file to
|
||||
/// delete, only a reset (see <see cref="ClearCurrent"/>), matching
|
||||
/// <see cref="MossTankProfileStore.Delete"/>'s own contract.
|
||||
/// </summary>
|
||||
public bool Delete(out string notice)
|
||||
{
|
||||
if (_selected.Equals(ByCharacter, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
notice = "'By char' is the built-in loot profile and cannot be deleted.";
|
||||
return false;
|
||||
}
|
||||
string fileName = _selected;
|
||||
if (VtankStorage.IsAvailable)
|
||||
VtankStorage.Delete(fileName);
|
||||
_selected = ByCharacter;
|
||||
WriteBinding();
|
||||
notice = $"Deleted loot profile {StripUtl(fileName)}.";
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ClearCurrent(List<LootRule> target, LootSettings? settings = null)
|
||||
{
|
||||
target.Clear();
|
||||
|
|
|
|||
|
|
@ -261,6 +261,30 @@ internal sealed class MossTankMetaProfileStore
|
|||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round 3 item 10: deletes the currently selected named Meta profile's
|
||||
/// real <c>.af</c> file, then falls back to <see cref="ByCharacter"/>.
|
||||
/// Refuses for <see cref="ByCharacter"/> itself — there is no file to
|
||||
/// delete, only a reset (see <see cref="ClearCurrent"/>), matching
|
||||
/// <see cref="MossTankProfileStore.Delete"/>'s own contract.
|
||||
/// </summary>
|
||||
public bool Delete(out string notice)
|
||||
{
|
||||
if (_selected.Equals(ByCharacter, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
notice = "'By char' is the built-in Meta profile and cannot be deleted.";
|
||||
return false;
|
||||
}
|
||||
string fileName = _selected;
|
||||
if (VtankStorage.IsAvailable)
|
||||
VtankStorage.Delete(fileName);
|
||||
_selected = ByCharacter;
|
||||
_pendingLegacyBareName = null;
|
||||
WriteBinding();
|
||||
notice = $"Deleted Meta profile {fileName}.";
|
||||
return true;
|
||||
}
|
||||
|
||||
public MetaProfile ClearCurrent()
|
||||
{
|
||||
var empty = new MetaProfile();
|
||||
|
|
|
|||
|
|
@ -594,6 +594,7 @@ internal sealed partial class MossTankPanel
|
|||
public Action CopyLootProfile => () =>
|
||||
CreateLootProfileCore(copyCurrent: true);
|
||||
public Action ClearLootProfile => ClearLootProfileCore;
|
||||
public Action DeleteLootProfile => DeleteLootProfileCore;
|
||||
public Action CloseLootEditor => () => _lootEditorVisible = false;
|
||||
public Action<int> SelectLootRule => SelectLootRuleCore;
|
||||
public Action<string> SetLootExpressionDraft => value =>
|
||||
|
|
@ -756,6 +757,7 @@ internal sealed partial class MossTankPanel
|
|||
public Action CopyRouteProfile => () =>
|
||||
CreateRouteProfileCore(copyCurrent: true);
|
||||
public Action ClearRouteProfile => ClearRouteProfileCore;
|
||||
public Action DeleteRouteProfile => DeleteRouteProfileCore;
|
||||
public Action SetFollowTarget => CaptureFollowTarget;
|
||||
|
||||
// ── Meta profile / editor ────────────────────────────────────────────
|
||||
|
|
@ -826,6 +828,7 @@ internal sealed partial class MossTankPanel
|
|||
public Action CreateMetaProfile => () => CreateMetaProfileCore(copyCurrent: false);
|
||||
public Action CopyMetaProfile => () => CreateMetaProfileCore(copyCurrent: true);
|
||||
public Action ClearMetaProfile => ClearMetaProfileCore;
|
||||
public Action DeleteMetaProfile => DeleteMetaProfileCore;
|
||||
|
||||
// ── Profiles tab ─────────────────────────────────────────────────────
|
||||
public IReadOnlyList<string> MacroProfileNames => _profiles.AvailableNames;
|
||||
|
|
@ -1425,6 +1428,17 @@ internal sealed partial class MossTankPanel
|
|||
_lootEditorNotice = $"Cleared {_lootProfiles.Selected}.";
|
||||
}
|
||||
|
||||
private void DeleteLootProfileCore()
|
||||
{
|
||||
if (!_lootProfiles.Delete(out string notice))
|
||||
{
|
||||
_lootEditorNotice = notice;
|
||||
return;
|
||||
}
|
||||
LoadLootProfile();
|
||||
_lootEditorNotice = notice;
|
||||
}
|
||||
|
||||
private void LoadLootProfile()
|
||||
{
|
||||
if (!_lootProfiles.LoadCurrent(
|
||||
|
|
@ -1784,6 +1798,17 @@ internal sealed partial class MossTankPanel
|
|||
_routeNotice = $"Cleared {_routeProfiles.Selected}.";
|
||||
}
|
||||
|
||||
private void DeleteRouteProfileCore()
|
||||
{
|
||||
if (!_routeProfiles.Delete(out string notice))
|
||||
{
|
||||
_routeNotice = notice;
|
||||
return;
|
||||
}
|
||||
LoadRouteProfile();
|
||||
_routeNotice = notice;
|
||||
}
|
||||
|
||||
private void LoadRouteProfile()
|
||||
{
|
||||
if (!_routeProfiles.LoadCurrent(_navigationSettings, _host.Automation.Spells))
|
||||
|
|
@ -2380,6 +2405,17 @@ internal sealed partial class MossTankPanel
|
|||
_metaNotice = $"Cleared Meta profile {_metaProfiles.Selected}.";
|
||||
}
|
||||
|
||||
private void DeleteMetaProfileCore()
|
||||
{
|
||||
if (!_metaProfiles.Delete(out string notice))
|
||||
{
|
||||
_metaNotice = notice;
|
||||
return;
|
||||
}
|
||||
LoadMetaProfile();
|
||||
_metaNotice = notice;
|
||||
}
|
||||
|
||||
private void LoadMetaProfile()
|
||||
{
|
||||
_metaProfile = _metaProfiles.LoadCurrent();
|
||||
|
|
|
|||
|
|
@ -228,6 +228,30 @@ internal sealed class MossTankRouteProfileStore
|
|||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Round 3 item 10: deletes the currently selected named route's real
|
||||
/// <c>.af</c> file, then falls back to <see cref="ByCharacter"/>.
|
||||
/// Refuses for <see cref="ByCharacter"/> itself — there is no file to
|
||||
/// delete, only a reset (see <see cref="ClearCurrent"/>), matching
|
||||
/// <see cref="MossTankProfileStore.Delete"/>'s own contract.
|
||||
/// </summary>
|
||||
public bool Delete(out string notice)
|
||||
{
|
||||
if (_selected.Equals(ByCharacter, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
notice = "'By char' is the built-in route profile and cannot be deleted.";
|
||||
return false;
|
||||
}
|
||||
string fileName = _selected;
|
||||
if (VtankStorage.IsAvailable)
|
||||
VtankStorage.Delete(fileName);
|
||||
_selected = ByCharacter;
|
||||
_pendingLegacyBareName = null;
|
||||
WriteBinding();
|
||||
notice = $"Deleted route profile {Strip(fileName)}.";
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets only the fields this store owns (Mode/Waypoints/FollowTarget)
|
||||
/// — Enabled/Priority/MinimumDistanceMeters/FollowAroundCorners/
|
||||
|
|
|
|||
|
|
@ -158,6 +158,9 @@
|
|||
onclick="{CreateRouteProfile}" />
|
||||
<button x="560" y="64" w="84" h="22" text="Clear route"
|
||||
onclick="{ClearRouteProfile}" />
|
||||
<button x="650" y="64" w="70" h="22" text="Delete"
|
||||
onclick="{DeleteRouteProfile}"
|
||||
tooltip="Delete the selected named route's real .af file. Not available for By char." />
|
||||
<toggle x="4" y="92" w="150" h="20" text="Enable Looting"
|
||||
checked="{LootEnabled}" onclick="{ToggleLooting}" />
|
||||
<menu x="156" y="90" w="116" h="22" items="{LootProfileNames}"
|
||||
|
|
@ -457,9 +460,12 @@
|
|||
onclick="{CopyMetaProfile}" />
|
||||
<button x="378" y="0" w="48" h="21" text="Clear"
|
||||
onclick="{ClearMetaProfile}" />
|
||||
<toggle x="446" y="2" w="112" h="20" text="Enable Meta"
|
||||
<button x="428" y="0" w="66" h="21" text="Delete"
|
||||
onclick="{DeleteMetaProfile}"
|
||||
tooltip="Delete the selected named Meta profile's real .af file. Not available for By char." />
|
||||
<toggle x="500" y="2" w="112" h="20" text="Enable Meta"
|
||||
checked="{MetaEnabled}" onclick="{ToggleMeta}" />
|
||||
<label x="566" y="4" text="{MetaStateText}" color="#FFE8DEC3" />
|
||||
<label x="620" y="4" text="{MetaStateText}" color="#FFE8DEC3" />
|
||||
|
||||
<list x="4" y="26" w="776" h="68" rowheight="17"
|
||||
items="{MetaRows}" selected="{SelectedMetaRuleIndex}"
|
||||
|
|
@ -533,6 +539,9 @@
|
|||
onclick="{CopyLootProfile}" />
|
||||
<button x="494" y="0" w="58" h="21" text="Clear"
|
||||
onclick="{ClearLootProfile}" />
|
||||
<button x="560" y="0" w="64" h="21" text="Delete"
|
||||
onclick="{DeleteLootProfile}"
|
||||
tooltip="Delete the selected named loot profile's real .utl file. Not available for By char." />
|
||||
<button x="684" y="0" w="92" h="21" text="Back"
|
||||
onclick="{CloseLootEditor}" />
|
||||
<list x="4" y="24" w="520" h="82" rowheight="17"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue