feat(input): expose state API, wire settings cog, add test hooks
This commit is contained in:
@@ -111,6 +111,7 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
|||||||
internal IpcManager Ipc { get; private set; } = null!;
|
internal IpcManager Ipc { get; private set; } = null!;
|
||||||
internal ExtraChat ExtraChat { get; private set; } = null!;
|
internal ExtraChat ExtraChat { get; private set; } = null!;
|
||||||
internal TypingIpc TypingIpc { get; private set; } = null!;
|
internal TypingIpc TypingIpc { get; private set; } = null!;
|
||||||
|
internal Ui.Components.InputBar InputBar { get; private set; } = null!;
|
||||||
internal FontManager FontManager { get; private set; } = null!;
|
internal FontManager FontManager { get; private set; } = null!;
|
||||||
internal Themes.ThemeRegistry ThemeRegistry { get; private set; } = null!;
|
internal Themes.ThemeRegistry ThemeRegistry { get; private set; } = null!;
|
||||||
internal Integrations.HonorificService HonorificService { get; private set; } = null!;
|
internal Integrations.HonorificService HonorificService { get; private set; } = null!;
|
||||||
@@ -292,6 +293,7 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
|||||||
MessageManager = _host.Services.GetRequiredService<MessageManager>();
|
MessageManager = _host.Services.GetRequiredService<MessageManager>();
|
||||||
AutoTellTabsService = _host.Services.GetRequiredService<AutoTellTabsService>();
|
AutoTellTabsService = _host.Services.GetRequiredService<AutoTellTabsService>();
|
||||||
|
|
||||||
|
InputBar = _host.Services.GetRequiredService<Ui.Components.InputBar>();
|
||||||
MainWindow = _host.Services.GetRequiredService<Ui.Windows.MainWindow>();
|
MainWindow = _host.Services.GetRequiredService<Ui.Windows.MainWindow>();
|
||||||
SettingsWindow = _host.Services.GetRequiredService<SettingsWindow>();
|
SettingsWindow = _host.Services.GetRequiredService<SettingsWindow>();
|
||||||
DbViewer = _host.Services.GetRequiredService<DbViewer>();
|
DbViewer = _host.Services.GetRequiredService<DbViewer>();
|
||||||
|
|||||||
@@ -139,7 +139,8 @@ internal static class PluginHostFactory
|
|||||||
sp.GetRequiredService<FontManager>(),
|
sp.GetRequiredService<FontManager>(),
|
||||||
sp.GetRequiredService<ThemeRegistry>(),
|
sp.GetRequiredService<ThemeRegistry>(),
|
||||||
sp.GetRequiredService<Ui.StyleEngine.TokenResolver>(),
|
sp.GetRequiredService<Ui.StyleEngine.TokenResolver>(),
|
||||||
sp.GetRequiredService<ILogger<Ui.Components.InputBar>>()
|
sp.GetRequiredService<ILogger<Ui.Components.InputBar>>(),
|
||||||
|
() => sp.GetRequiredService<Plugin>().SettingsWindow.Toggle()
|
||||||
));
|
));
|
||||||
services.AddSingleton(sp => new Ui.Components.StatusBar(
|
services.AddSingleton(sp => new Ui.Components.StatusBar(
|
||||||
sp.GetRequiredService<ThemeRegistry>(),
|
sp.GetRequiredService<ThemeRegistry>(),
|
||||||
|
|||||||
@@ -30,15 +30,19 @@ internal sealed class InputBar
|
|||||||
private readonly ThemeRegistry _themes;
|
private readonly ThemeRegistry _themes;
|
||||||
private readonly TokenResolver _resolver;
|
private readonly TokenResolver _resolver;
|
||||||
private readonly ILogger<InputBar> _logger;
|
private readonly ILogger<InputBar> _logger;
|
||||||
|
private readonly Action _onOpenSettings;
|
||||||
|
|
||||||
private string _pendingMessage = string.Empty;
|
private string _pendingMessage = string.Empty;
|
||||||
|
private bool _isFocused;
|
||||||
|
private bool? _isFocusedOverride; // Test-only; null = honour per-frame Draw() value.
|
||||||
|
|
||||||
public InputBar(
|
public InputBar(
|
||||||
SymbolPicker symbolPicker,
|
SymbolPicker symbolPicker,
|
||||||
FontManager fonts,
|
FontManager fonts,
|
||||||
ThemeRegistry themes,
|
ThemeRegistry themes,
|
||||||
TokenResolver resolver,
|
TokenResolver resolver,
|
||||||
ILogger<InputBar> logger
|
ILogger<InputBar> logger,
|
||||||
|
Action onOpenSettings
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
_symbolPicker = symbolPicker;
|
_symbolPicker = symbolPicker;
|
||||||
@@ -46,9 +50,22 @@ internal sealed class InputBar
|
|||||||
_themes = themes;
|
_themes = themes;
|
||||||
_resolver = resolver;
|
_resolver = resolver;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_onOpenSettings = onOpenSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string PendingMessage => _pendingMessage;
|
public string PendingMessage => _pendingMessage;
|
||||||
|
public int PendingLength => _pendingMessage.Length;
|
||||||
|
|
||||||
|
// IsFocused respects the test override first so a SelfTest can pin focus
|
||||||
|
// state without racing against per-frame ImGui.IsItemFocused() in Draw().
|
||||||
|
// Note: when MainWindow is closed, DrawInputField never runs, so
|
||||||
|
// _isFocused keeps the last value written by the previous draw pass.
|
||||||
|
// The consumer that actually pushes this state across the IPC boundary
|
||||||
|
// (TypingIpc.BuildState, see F3 Step 2) gates on Plugin.MainWindow.IsOpen
|
||||||
|
// itself, so the stale backing-field never leaks to subscribers. Mirroring
|
||||||
|
// the gate here would require an extra Plugin-backref in InputBar that the
|
||||||
|
// rest of the component doesn't need.
|
||||||
|
public bool IsFocused => _isFocusedOverride ?? _isFocused;
|
||||||
|
|
||||||
public void ClearBuffer() => _pendingMessage = string.Empty;
|
public void ClearBuffer() => _pendingMessage = string.Empty;
|
||||||
|
|
||||||
@@ -163,6 +180,7 @@ internal sealed class InputBar
|
|||||||
{
|
{
|
||||||
TrySend(activeTab);
|
TrySend(activeTab);
|
||||||
}
|
}
|
||||||
|
_isFocused = ImGui.IsItemFocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TrySend(Tab? activeTab)
|
private void TrySend(Tab? activeTab)
|
||||||
@@ -212,10 +230,7 @@ internal sealed class InputBar
|
|||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (ImGui.Button(FontAwesomeIcon.Cog.ToIconString()))
|
if (ImGui.Button(FontAwesomeIcon.Cog.ToIconString()))
|
||||||
{
|
{
|
||||||
// Settings toggle wires up when the plugin window registers
|
_onOpenSettings();
|
||||||
// its open handler; no-op until then so the button is
|
|
||||||
// visible without dragging a half-finished settings call
|
|
||||||
// into the component.
|
|
||||||
}
|
}
|
||||||
if (ImGui.IsItemHovered())
|
if (ImGui.IsItemHovered())
|
||||||
{
|
{
|
||||||
@@ -235,4 +250,11 @@ internal sealed class InputBar
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test-only hook; do not call from production code.
|
||||||
|
internal void TestSetPendingMessageForSelfTest(string value) => _pendingMessage = value;
|
||||||
|
|
||||||
|
// Test-only hook; do not call from production code. Pass null to release the
|
||||||
|
// override and let Draw()'s ImGui.IsItemFocused() result take over again.
|
||||||
|
internal void TestSetFocusedForSelfTest(bool? value) => _isFocusedOverride = value;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user