Commit Graph
10 Commits
Author SHA1 Message Date
JonKazama-Hellion 57780351d4 feat(settings): convert the remaining four standard tabs
Chat, Channels, General and Data & Privacy now draw the same way Window does. A
half-converted window is worse than an unconverted one: before, all seven tabs
were consistently dated; after the pilot, one looked current and six looked
abandoned, and switching between them made the seam obvious.

Descriptions move out of the help markers and onto the rows. Those strings were
written to be read, and a (?) the user has to hover is where an explanation goes
to be ignored. Several were translated into 25 languages and had never appeared
on screen at all.

Two settings that could not use the standard helpers -- the language picker,
which rebuilds the font atlas, and the keybind mode, whose description depends
on the selected value -- go through a plain Row that hands the caller the control
column and leaves the save logic alone.

Privacy filter labels now come from the resources that already existed for them,
same defect as the channels tab last round: strings present, translated, and
reachable from no line of code.

Four more constructors take a TokenResolver, so this wants the DI smoke pass.
Only the appearance tab still draws stock collapsing headers; its four
components are their own block.
2026-08-18 18:23:34 +02:00
JonKazama-Hellion 588b886537 fix(settings): remove the switches that do nothing
Six settings had a control, a saved value, translated labels, and no reader
anywhere in the plugin. Flipping them changed a byte on disk and nothing else.

Three sat next to each other in the Chat tab under timestamps, so the section
read as four related options where only one -- the 24-hour clock -- works.
FormatTimestamp consults nothing else.

The first-run wizard offered one of them too, on its visual step, and listed it
back in the summary as if it had been applied. That is the first screen a new
user sees, so it goes as well.

Their own strings show how long this has been drifting: the wizard called
PrettierTimestamps "relative time", the settings tab called the same field
"modern layout". Two different features, one boolean, neither implemented. That
is also why these are removed rather than wired up -- there is no single
behaviour to restore, and inventing one belongs in a cycle that plans it.

Config fields stay, with a comment. A stored value should survive until the
rendering it describes exists, and dropping them would silently reset anyone who
set them.

Found by an audit that turned up considerably more of this: 433 of 824
translated resource keys reach no code at all, and the export, cleanup, tab
editor and pin paths are complete but unreachable. That is its own cycle; this
commit only clears what actively lies to the user in the window we are working
on.
2026-08-18 14:41:07 +02:00
JonKazama-Hellion f999036e50 refactor(settings): merge the duplicated tab helpers
Six tabs carried a byte-identical DrawToggle, four a byte-identical slider, and
five hand-rolled the same enum combo loop. 281 lines out, 82 in.

The combos were not only duplicated, they were wasteful: each one called
Enum.GetValues inside Draw, so every open settings window allocated five arrays
per frame for sets that cannot change at runtime. EnumValues<T> reads them once
per closed generic, and the label array is one buffer shared by all of them.

Two behaviours are now uniform rather than accidental. The range check on the
selected index existed in exactly one of the five and is now in all of them,
and the tell auto-open combo lost its inline literal array in favour of a Name
extension like its seven peers -- still English, but at least in the place the
localisation pass will look.

SettingsWidgets is constructed by each tab rather than injected. The tabs are DI
singletons and a seventh constructor signature change buys nothing here.

One visible difference: the tell auto-open combo was 220px wide against 200 for
every other combo in the window. It is 200 now.
2026-08-18 13:42:21 +02:00
JonKazama-Hellion 5b51f7dcfd fix(settings): use the existing translations and unfreeze the window title
Review of block A found three things a German user sees straight away.

Two of the three new controls hard-coded English labels although translated
resources already existed for exactly them: Options_PlaySounds_Name and
Options_KeybindMode_Name are in all 25 files. So "Sprache" sat directly above
"Play sounds". The help marker now uses Options_PlaySounds_Description too.

The settings window title was baked in at construction, so it kept whatever
language the plugin started in. Every other string re-reads per draw; this was
the one frozen one. A PreDraw override refreshes it.

Three smaller items from the same review:

The comment on the language order was wrong in both halves. None never reaches
the sort -- it is filtered out and pinned to the front -- so the "list would
jump" hazard it described cannot happen, and the count was 25 endonyms, not 24.
Left as-is it invited someone to swap Where and OrderBy, which would make the
order depend on the culture the game started in.

The rebuild comment claimed thread affinity made it safe. It does not: the
rebuild disposes the very font handle that Plugin.Draw has pushed for the
frame. It works because Dalamud holds the ImFont under a per-frame lock, and
that is now what the comment says. The help marker also warns that switching
rebuilds the atlas and where to clear accumulated glyph ranges.

ApplyLanguage gets an equality guard. Combo only reports real changes, but a
font atlas rebuild is expensive enough that no future caller should be able to
trigger a no-op one.

ChatTab lost its last ChatType reference with the deleted grid, so the using
went too.
2026-08-18 11:33:42 +02:00
JonKazama-Hellion 81b68a1681 fix(settings): stop drawing the same privacy options in two tabs
Three settings were rendered in two places at once, and the third is the one
that matters: the entire 89-entry channel grid existed twice. ChatTab's
"Channel filter" section and DataPrivacyTab's "Privacy filter" section wrote
the same HashSet through near-identical code, differing only in the ImGui id
suffix. Whichever one the user found first, the other silently showed the same
state.

ChatTab's section is gone entirely. DataPrivacyTab is a proper superset of it
-- it additionally carries PrivacyPersistUnknownChannels -- so nothing is lost.
PrintChangelog keeps only its General entry, where it belongs: it is start-up
behaviour, not privacy.

The lock-ordering comment moved before the deletion. DataPrivacyTab's version
was "see ChatTab for the ordering", a cross-reference to the file being
removed; the actual reasoning only existed in ChatTab.
2026-08-18 11:19:32 +02:00
JonKazama-Hellion eaed0b13e0 fix(config): guard the shared config maps, restore lost fields in Tab.Clone
TabsListLock never covered ChatColours, PrivacyPersistChannels or
RetentionPerChannelDays, yet the settings UI mutates them from the draw thread
while the retention thread can be serializing the same config. Adding a new key
to a dictionary or a new element to a set invalidates a running enumeration, so
this could throw from inside JsonConvert.SerializeObject.

Not a corner case: the colour picker lists 66 channels but only 25 ship with a
default, so the first edit of any of the remaining ones inserts a new key -- and
the reset button removes a key, which makes the next edit a fresh insert again.

The readers matter as much as the writers. IsAllowedForStorage runs per message
on the worker thread and asks PrivacyPersistChannels whether a channel may be
stored; a Contains racing an Add that resizes buckets can answer wrong, and that
answer decides whether a message is written to disk. The retention sweep
enumerates RetentionPerChannelDays on the framework thread while the wizard can
clear it -- Clear does not throw there, it just cuts the enumeration short, so
the sweep would run on half a policy.

New ConfigMapsLock covers all of it. It sits inside TabsListLock (that edge is
real, AutoTellTabsService calls SaveConfig while holding the tabs lock), never
the other way round -- so every call site closes the lock before saving.

Tab.Clone silently dropped Icon and ChatCodes, both serialized. A reflection
test now walks the serialized fields so a future one cannot slip past.

Also: CurrentTab read Count and [0] as two separate accesses.
2026-08-17 07:27:48 +02:00
JonKazama-Hellion b397591ba4 feat(window): restore the title-bar, hide-button, and 24-hour-clock toggles
Re-wires four 1.5.6 settings that survived the v1.6.0 rewrite as dormant config
fields but lost their UI + consumers:
- ShowTitleBar / ShowPopOutTitleBar: gate ImGuiWindowFlags.NoTitleBar on the main
  window (ResolveFlags) and pop-out windows (new PreDraw). Inverted logic matches
  1.5.6 (flag set only when the toggle is off).
- ShowHideButton: gate the input-bar hide button on the toggle.
- Use24HourClock: add the toggle (MessageList already consumes the field).
New 'Window style' section in WindowTab; Use24HourClock in ChatTab display modes.
MainWindowFlagsStep extended with the NoTitleBar fresh-base contract.
2026-06-15 20:19:59 +02:00
JonKazama-Hellion b0bee25770 feat(input): warn and hold before sending plugin-only symbols 2026-05-31 00:45:31 +02:00
JonKazama-Hellion 92f1736ea9 feat(settings): add world suffix and name format combos to the chat tab 2026-05-31 00:36:09 +02:00
JonKazama-Hellion 2507ed5197 feat(settings): add Chat tab including command help side 2026-05-26 19:12:01 +02:00