feat(ui): Chat tab — channel filters + display prefs + font slider
Phase L.0 (cont.) — fourth tab on the Settings shell. Mixes retail's CharacterOptions2 chat-channel filter bits (Hear*Chat / TimeStamp / FilterLanguage / AppearOffline) with a font-size slider that has no retail bitfield equivalent. ChatSettings record (9 fields): · 5 channel filters: HearGeneralChat, HearTradeChat, HearLFGChat, HearRoleplayChat, HearSocietyChat · 3 display flags: ShowTimestamps, FilterProfanity, AppearOffline · 1 visual: FontSize (10..20 pt) Local-only this phase per the brainstorm — Hear*Chat flags affect client-side display filtering only; the server still streams every channel. Server-sync arrives later when the protocol round-trip is in place. SettingsStore grows LoadChat / SaveChat using the existing generic SaveSection helper. All four non-keybind sections (display, audio, gameplay, chat) now coexist non-destructively in settings.json. SettingsVM grows the parallel chat state machine. HasUnsavedChanges, Save, Cancel, ResetAllToDefaults all cover chat. Constructor signature adds two more params; existing call sites updated. SettingsPanel.RenderChatTab replaces the L.0-shell placeholder — 8 Checkbox calls grouped under "Channel filters" + "Display" headers, plus a font-size SliderFloat. The "Coming soon" placeholder test was retargeted from "Chat" to "Character" since Chat is no longer a placeholder. GameWindow wires SettingsStore.LoadChat / SaveChat + a TODO comment for the future ChatPanel filter integration (read SettingsVM.ChatDraft when filtering inbound chat lines). 13 new tests: · ChatSettings record (3) — defaults pinned, value equality, with- expressions · SettingsStore chat (3) — missing-file → defaults, round-trip, all four sections coexist · SettingsVM chat (5) — initial draft, SetChat marks dirty, Save invokes callback, Cancel reverts, ResetAllToDefaults covers · SettingsPanel chat tab (2) — checkboxes + slider render only when active dotnet build green (0 warnings); dotnet test 1,289 / 1,289 green (243 Core.Net + 373 UI.Abstractions + 673 Core). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b7165e5b17
commit
356b5f219e
9 changed files with 440 additions and 42 deletions
|
|
@ -33,7 +33,8 @@ public sealed class SettingsPanelTests
|
|||
persisted, dispatcher, _ => { },
|
||||
DisplaySettings.Default, _ => { },
|
||||
AudioSettings.Default, _ => { },
|
||||
GameplaySettings.Default, _ => { });
|
||||
GameplaySettings.Default, _ => { },
|
||||
ChatSettings.Default, _ => { });
|
||||
var panel = new SettingsPanel(vm);
|
||||
return (panel, vm, kb, dispatcher);
|
||||
}
|
||||
|
|
@ -228,17 +229,17 @@ public sealed class SettingsPanelTests
|
|||
[Fact]
|
||||
public void Placeholder_tabs_render_coming_soon_text_when_active()
|
||||
{
|
||||
// Chat is still a placeholder (next in build order). Display,
|
||||
// Audio, and Gameplay have shipped — they have real widgets,
|
||||
// not "coming soon" text.
|
||||
// Character is still a placeholder (last on the build order).
|
||||
// Display / Audio / Gameplay / Chat have shipped — they have
|
||||
// real widgets, not "coming soon" text.
|
||||
var (panel, _, _, _) = Build();
|
||||
var r = new FakePanelRenderer { ActiveTabLabel = "Chat" };
|
||||
var r = new FakePanelRenderer { ActiveTabLabel = "Character" };
|
||||
|
||||
panel.Render(new PanelContext(0.016f, new NullBus()), r);
|
||||
|
||||
var wrapped = r.Calls.Where(c => c.Method == "TextWrapped")
|
||||
.Select(c => (string)c.Args[0]!).ToList();
|
||||
Assert.Contains(wrapped, t => t.Contains("Chat settings coming soon"));
|
||||
Assert.Contains(wrapped, t => t.Contains("Character settings coming soon"));
|
||||
}
|
||||
|
||||
// -- Display tab content ---------------------------------------------
|
||||
|
|
@ -359,6 +360,48 @@ public sealed class SettingsPanelTests
|
|||
Assert.DoesNotContain("Lock UI (disable panel drag/resize)", checks);
|
||||
}
|
||||
|
||||
// -- Chat tab content ------------------------------------------------
|
||||
|
||||
[Fact]
|
||||
public void Chat_tab_when_active_renders_channel_filter_checkboxes_and_font_slider()
|
||||
{
|
||||
var (panel, _, _, _) = Build();
|
||||
var r = new FakePanelRenderer { ActiveTabLabel = "Chat" };
|
||||
|
||||
panel.Render(new PanelContext(0.016f, new NullBus()), r);
|
||||
|
||||
var checks = r.Calls.Where(c => c.Method == "Checkbox")
|
||||
.Select(c => (string)c.Args[0]!).ToList();
|
||||
Assert.Contains("General", checks);
|
||||
Assert.Contains("Trade", checks);
|
||||
Assert.Contains("LFG (looking for group)", checks);
|
||||
Assert.Contains("Roleplay", checks);
|
||||
Assert.Contains("Society (CD / EW / RB)", checks);
|
||||
Assert.Contains("Show timestamps", checks);
|
||||
Assert.Contains("Filter profanity", checks);
|
||||
Assert.Contains("Appear offline (hide from /who)", checks);
|
||||
|
||||
var sliders = r.Calls.Where(c => c.Method == "SliderFloat")
|
||||
.Select(c => (string)c.Args[0]!).ToList();
|
||||
Assert.Contains("Font size (pt)", sliders);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Chat_tab_does_not_render_when_a_different_tab_is_active()
|
||||
{
|
||||
var (panel, _, _, _) = Build();
|
||||
var r = new FakePanelRenderer { ActiveTabLabel = "Display" };
|
||||
|
||||
panel.Render(new PanelContext(0.016f, new NullBus()), r);
|
||||
|
||||
var checks = r.Calls.Where(c => c.Method == "Checkbox")
|
||||
.Select(c => (string)c.Args[0]!).ToList();
|
||||
// The tab labels "General", "Trade" etc only appear inside the
|
||||
// Chat tab. Confirm none of them rendered.
|
||||
Assert.DoesNotContain("General", checks);
|
||||
Assert.DoesNotContain("Trade", checks);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Audio_sliders_are_clamped_to_zero_one_range()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue