feat(ui): centralize retail selection state

This commit is contained in:
Erik 2026-07-11 00:51:20 +02:00
parent c7607f019c
commit 7983309d23
30 changed files with 591 additions and 108 deletions

View file

@ -8,7 +8,7 @@ namespace AcDream.App.UI;
/// target acquisition, and drag-out drops here instead of duplicating
/// ItemHolder::UseObject fragments in each panel.
/// </summary>
public sealed class ItemInteractionController
public sealed class ItemInteractionController : IDisposable
{
private static readonly EquipMask[] AutoEquipOrder =
{
@ -55,8 +55,10 @@ public sealed class ItemInteractionController
private readonly Action<uint, uint>? _sendWield;
private readonly Action<uint>? _sendDrop;
private readonly Action<string>? _toast;
private readonly InteractionState _interactionState;
private long _lastUseMs = long.MinValue / 2;
private bool _disposed;
public ItemInteractionController(
ClientObjectTable objects,
@ -66,7 +68,8 @@ public sealed class ItemInteractionController
Action<uint, uint>? sendWield,
Action<uint>? sendDrop,
Func<long>? nowMs = null,
Action<string>? toast = null)
Action<string>? toast = null,
InteractionState? interactionState = null)
{
_objects = objects ?? throw new ArgumentNullException(nameof(objects));
_playerGuid = playerGuid ?? throw new ArgumentNullException(nameof(playerGuid));
@ -76,15 +79,23 @@ public sealed class ItemInteractionController
_sendDrop = sendDrop;
_nowMs = nowMs ?? (() => Environment.TickCount64);
_toast = toast;
_interactionState = interactionState ?? new InteractionState();
_interactionState.Changed += OnInteractionModeChanged;
}
public event Action? StateChanged;
public uint PlayerGuid => _playerGuid();
public uint PendingSourceItem { get; private set; }
public InteractionState InteractionState => _interactionState;
public bool IsTargetModeActive => PendingSourceItem != 0;
public uint PendingSourceItem
=> _interactionState.Current is { Kind: InteractionModeKind.UseItemOnTarget } mode
? mode.SourceObjectId
: 0u;
public bool IsTargetModeActive
=> _interactionState.Current.Kind == InteractionModeKind.UseItemOnTarget;
public bool IsPendingSource(uint itemGuid)
=> itemGuid != 0 && itemGuid == PendingSourceItem;
@ -188,8 +199,7 @@ public sealed class ItemInteractionController
private void EnterTargetMode(uint sourceGuid)
{
PendingSourceItem = sourceGuid;
StateChanged?.Invoke();
_interactionState.EnterUseItemOnTarget(sourceGuid);
var name = _objects.Get(sourceGuid)?.Name;
if (!string.IsNullOrWhiteSpace(name))
_toast?.Invoke($"Choose a target for the {name}");
@ -197,8 +207,17 @@ public sealed class ItemInteractionController
private void ClearTargetMode()
{
PendingSourceItem = 0;
StateChanged?.Invoke();
_interactionState.Clear();
}
private void OnInteractionModeChanged(InteractionModeTransition _)
=> StateChanged?.Invoke();
public void Dispose()
{
if (_disposed) return;
_disposed = true;
_interactionState.Changed -= OnInteractionModeChanged;
}
private bool ConsumeUseThrottle()