Commit Graph

168 Commits

Author SHA1 Message Date
JonKazama-Hellion 395a0d7c98 refactor(settings): polish database tab section structure
Drop the redundant inner Advanced TreeNode in the Maintenance section,
flatten the duplicated indent in the Overview section, and rename the
section headings so they reflect their content (Overview shows
metadata, Maintenance hosts the shift-gated tooling).
2026-05-02 17:33:51 +02:00
JonKazama-Hellion b76bfb3cfc refactor(settings-refactor): regroup Database tab into storage, viewer, stats tree nodes 2026-05-02 17:22:26 +02:00
JonKazama-Hellion 0512e4729c refactor(settings-refactor): remove theme settings from Privacy tab and tighten tree structure 2026-05-02 17:14:40 +02:00
JonKazama-Hellion 654f24c609 docs(settings-refactor): add Chat tab header explaining emote block migration 2026-05-02 17:09:50 +02:00
JonKazama-Hellion 0e2a14197c feat(settings-refactor): populate Chat tab with auto-tell-tabs, behaviour, preview, emotes 2026-05-02 17:04:25 +02:00
JonKazama-Hellion e086afe2a8 feat(settings-refactor): populate Window tab with hide, inactivity, frame, tooltips 2026-05-02 16:54:23 +02:00
JonKazama-Hellion c97ce7543b feat(settings-refactor): populate Appearance tab with theme, fonts, colours, timestamps 2026-05-02 16:44:50 +02:00
JonKazama-Hellion cca4571470 feat(settings-refactor): populate General tab with input, audio, performance, language sections 2026-05-02 16:36:52 +02:00
JonKazama-Hellion 444d7f8e2e style(settings-refactor): use property-style for Plugin reference in tab stubs 2026-05-02 16:31:42 +02:00
JonKazama-Hellion 71ae95d79c feat(settings-refactor): wire new 8-tab structure with stubs 2026-05-02 16:26:22 +02:00
JonKazama-Hellion 39cd7ab801 feat(auto-tell-tabs): make greeted toggle button opt-in (default off, greeter-specific) 2026-05-02 14:26:13 +02:00
JonKazama-Hellion 757370dd53 feat(auto-tell-tabs): add settings sections in chat and privacy tabs with help-marker pattern 2026-05-02 14:19:35 +02:00
JonKazama-Hellion 6b44310e04 Fix the About tab so the translator list is reachable
The translator section sat inside a child window whose height was
computed as "whatever is left in the content region minus a line".
Once the About copy grew with the new mission and rewritten built-on
sections, that remaining space dropped close to zero on smaller
settings windows, so the tree node was rendered but its content was
either invisible or unscrollable from the parent.

Drop the fixed-height child entirely. The settings window already
provides a scroll container around each tab, so rendering the tree
node and the translator list directly into it lets the parent
handle the scroll. The translators get a manual indent push to keep
the visual nesting that the child-frame used to suggest.
2026-05-02 03:54:34 +02:00
JonKazama-Hellion 59332ce9ea Move About-tab copy to HellionStrings and rephrase neutrally
The About tab copy was hand-written in English directly in About.cs,
which left the German users on the upstream Chat 2 wording for the
Hellion-specific blocks. The copy itself also leaned on em-dashes
mid-sentence and on a tone that could read as accusing Chat 2 of
GDPR violations, which was never the intent. This commit moves the
six About-tab sections (Maintainer, Why this fork exists, Built on
Chat 2, License, FFXIV disclaimer, Localization) into HellionStrings
and tightens the wording in both languages.

Tone change is the substantive part. Chat 2's full-history default
is now described as "the right one for most users" rather than a
problem the fork is fixing, and the webinterface removal is framed
as a focus mismatch — Chat 2's webinterface targets remote chat
access from a second device, this fork targets a smaller default
footprint, neither approach is wrong. The personal trigger for the
fork (two million logged messages over two years, mostly /say and
/yell from strangers) stays as it is honest context rather than
criticism.

The same neutralised wording is mirrored in three more places that
described the webinterface removal: the README "Was gegenüber
Chat 2 fehlt" block, the HellionChat.yaml description and changelog,
and the matching repo.json fields. The 0.2.0 changelog no longer
recites the upstream auth-flow internals; "different use case,
substantial rebuild, removed" is enough for users.

Em-dashes were also removed from two body strings that previously
used them as comma replacements (Privacy filter storage-only help
and the retention default description). Heading-level dashes
("Hellion Chat — Welcome", "Export (GDPR Art. 15 — right of
access)") stay because dashes are appropriate as separators in
titles.

The Theme description was already inaccurate — it still talked
about slate-violet tabs and amber highlights even though the brand
sweep moved everything onto Arctic Cyan plus Ember Orange. Updated
to describe the current palette honestly.
2026-05-02 03:50:08 +02:00
JonKazama-Hellion 462530dec5 Add a mission statement to the About tab
The About tab already credits Chat 2 and the maintainers, but it
never said why this fork exists in the first place. New users
discovering Hellion Chat through the Dalamud plugin list could
reasonably read it as a replacement attempt rather than what it is:
a niche alternative for users who care about chat persistence and
data minimisation.

The new "Why this fork exists" block sits between the Maintainer
and the Built-on-Chat-2 sections so the reading order goes from
"who" to "why" to "from what". It states three things plainly:

  - Hellion Chat is not trying to replace Chat 2
  - The trigger was the maintainer's own database (two years,
    two million messages, mostly public-chat from strangers)
  - Source is open under the same EUPL-1.2 licence; the upstream
    authors are welcome to look, take ideas, ask, or ignore

The tone matches the rest of the About tab — direct, no marketing
voice — and stays in English with the other legal-ish copy so a
single source covers every locale.
2026-05-02 03:40:57 +02:00
JonKazama-Hellion de0d2c80cd Serialise retention sweeps so the auto and manual paths cannot overlap
Audit findings M-3 and M-4. The 24h auto-sweep launched from
Plugin's constructor and the manual button in the Privacy tab were
both starting a background thread that called DeleteByRetentionPolicy
on the shared MessageStore connection without coordinating. With
unfortunate timing — manual click moments after a fresh plugin load
— two sweeps would race for the same connection and the second
would just re-do work the first one already did, while still
overwriting RetentionLastRunAt.

Move the running flag and a lock object to Plugin so both paths see
the same gate. Each entry point takes the lock long enough to check
and set the flag, then runs the actual delete on its background
thread without holding the lock (other DB operations already happen
without locking; spreading the lock further would suggest a
guarantee we do not actually provide). The Privacy tab keeps a
read-only property that surfaces the shared flag for its UI disable
state — ImGui is single-threaded and bool reads are atomic, so the
lock-free read is fine.
2026-05-02 02:52:34 +02:00
JonKazama-Hellion a857714064 Clarify the privacy filter only governs storage, not the live chat log
Audit finding M-5. The master switch description told users what the
filter does to the database, but nothing in the UI ruled out the
common misreading "if I disable a channel, it will also disappear
from the chat log". A help-text line under the toggle now states
explicitly that the filter is storage-only and points at the
in-game chat tab filters for hiding channels visually. EN and DE
strings added together.
2026-05-02 02:49:45 +02:00
JonKazama-Hellion bf5d03c7ea Update README, About tab and project doc for the webinterface removal
README's Stability section gains a "what is missing compared to Chat 2"
block that names the five concrete reasons the upstream webinterface
could not stay (System.Random auth code, bind on all interfaces,
unflagged cookies, SSE stream that bypassed the privacy filter, and
the cumulative hardening cost). The project status list reflects
0.2.0 with Phase 1.5 marked done and the remaining audit follow-ups
queued under Phase 2.

The About tab gets a single-line acknowledgement that the upstream
webinterface is intentionally absent, so users coming from Chat 2 do
not look for it under settings or assume it broke.

The Obsidian project note is updated separately under
Vault/Ideen/Hellion Chat Plugin (ChatTwo Fork).md to record the audit
decision and the six-commit cleanup.
2026-05-02 02:28:36 +02:00
JonKazama-Hellion 7bacd1aaba Remove webinterface settings tab and configuration fields
Webinterface adds a third-party HTTP surface that contradicts the
DSGVO-by-default promise: it broadcasts every chat message including
filtered ChatTypes (privacy filter only covers DB writes), ships a
five-digit numeric auth code seeded from System.Random, binds on all
interfaces by default and sets cookies without security flags.

Hardening it for our threat model would land 500+ lines of code and
permanent maintenance for a feature very few users actually use. The
forks audience wants less surface, not more, so the entire feature is
being removed in a focused commit cluster. This first commit drops
the user-facing surface: settings tab class, tab registration and
the Configuration fields plus their UpdateFrom mirror.
2026-05-02 02:18:43 +02:00
JonKazama-Hellion 96fa05dc9b Clarify translator credits in the About tab
The inherited Translators tree node was rendered under the
upstream `Options_About_Translators` label and could be misread
as "people who translated Hellion Chat". The list is in fact the
Chat 2 community Crowdin contributors and covers the inherited
upstream strings only — the Hellion-specific strings live in
HellionStrings.<lang>.resx and are maintained by the Hellion
Online Media maintainer (currently EN + DE; other locales are
not yet covered).

Add a Localization block right above the tree node that spells
this out, and rename the tree node label to "Chat 2 community
translators (upstream)" so the attribution is unambiguous.
2026-05-02 00:07:50 +02:00
JonKazama-Hellion d891ec5e50 Rebrand the About tab around the Hellion fork
The inherited About tab still pointed at Infi's Discord handle,
the Chat 2 community Discord thread, the Infiziert90/ChatTwo
issue tracker and the chattwo Crowdin project — all upstream
references that don't apply to this fork. Replace them with:

  - Discord handle: @j.j_kazama
  - GitHub Issues: JonKazama-Hellion/HellionChat
  - The Chat 2 community Discord thread is dropped (no equivalent
    Hellion community channel yet)
  - The chattwo Crowdin link is dropped (we have no separate
    Crowdin project; Hellion-specific strings live in the bundled
    HellionStrings.<lang>.resx files maintained by hand)

Adds four Hellion-specific blocks below the version line:

  Maintainer  → Hellion Online Media (Florian Wathling), with the
                hellion-media.de website as the contact channel for
                any licensing or legal inquiries.

  Built on    → makes it explicit that Hellion Chat is a fork of
  Chat 2        Chat 2 by Infi and Anna; every chat-replacement
                feature, IPC integration, rendering and storage
                code comes from upstream. Links to the upstream
                Infiziert90/ChatTwo repository.

  License     → EUPL-1.2 with the dual copyright statement
                covering the upstream Chat 2 authors and the
                Hellion Chat additions.

  FFXIV       → standard SQUARE ENIX disclaimer naming the plugin
  disclaimer    as unofficial and fan-made, so anyone reading the
                tab knows up front that this is not endorsed by SE.

The original ChatTwo translator credits stay intact below — the
upstream contributors deserve to remain visible in the fork.
2026-05-02 00:02:13 +02:00
JonKazama-Hellion 984b00ac0d Bundle the Hellion icon and Exo 2 font
Replace the inherited Chat 2 icon with the 1024×1024 Hellion logo
from the Hellion Online Media brand assets so the plugin shows
its real identity in Dalamud's plugin list. Bundle Exo 2 Variable
(SIL Open Font License 1.1) as an embedded resource together with
the OFL license text — keeps the license travelling with the font
inside the assembly as the OFL requires.

A new Configuration.UseHellionFont (default true) plus a checkbox
in the Privacy tab Appearance section route FontManager's regular
font handle through tk.AddFontFromMemory using the embedded TTF
bytes when the toggle is on; flipping it off falls back to the
existing AddFontWithFallback path so users who picked their own
system font under Settings → Fonts keep that choice.

Settings.cs now treats UseHellionFont as a font-changing setting
so toggling it triggers FontManager.BuildFonts on save without
needing a plugin reload.
2026-05-01 22:45:43 +02:00
JonKazama-Hellion 7fdbc81c22 Add window opacity slider to the Hellion theme
True per-window focus-aware transparency would require touching
ChatLogWindow and SettingsWindow individually (both upstream code,
both prone to cherry-pick churn). Instead expose a single opacity
slider that mixes a configured alpha into the WindowBg color in
PushGlobal — applies to every Hellion-rendered pane uniformly,
the game shines through, and form fields / dialogs / popups stay
opaque on top so input remains readable.

Default 92%, range clamped to 0.5–1.0 in the UI and 0x55–0xFF in
the alpha conversion so users can't accidentally make the panes
disappear entirely. Slider sits inside the Appearance section
right under the master Hellion-theme checkbox and is greyed out
when the theme is disabled.
2026-05-01 21:22:55 +02:00
JonKazama-Hellion 07470f527e Apply Hellion theme plugin-wide with multi-accent palette
Move from a local color stack inside Hellion-only surfaces to a
single push wrapping Plugin.Draw, so chat log, settings,
viewers, the file dialog and the wizard all render under the same
palette. The local Push() helper stays for explicit use, but the
two existing call sites (Privacy tab, FirstRunWizard) now drop
their local pushes — the global stack already covers them and
double-pushing would shift colors on every frame.

Palette grew from a single cyan accent into a three-tone HUD set:

  Primary cyan-teal (#00B8D4)  → buttons, checkboxes, slider grabs,
                                 separator hover/active.
  Secondary industrial amber   → scrollbar grab and resize-grip
  (#FFB300)                      hover/active highlights.
  Tertiary slate violet         → active title bars and active tabs
  (#7B61FF)                      so identity beats out the cyan
                                 accent without competing with it on
                                 action controls.

Surfaces are deep slate (#0E1A20 windows, #102027 children, #162831
frames) with steel borders (#37474F). Style variables flatten the
default Dalamud rounding into something more geometric: 4 px window
rounding, 2 px frame/grab/tab/scrollbar, 1 px borders.

A new Configuration.HellionThemeEnabled (default true) and a
matching Appearance section at the top of the Privacy tab let users
turn the whole thing off and fall back to the Dalamud default look.
The flag is checked once per frame in Plugin.Draw — `using
IDisposable? _ = ... ? PushGlobal() : null` — so disabling has zero
overhead beyond a bool check.
2026-05-01 21:13:58 +02:00
JonKazama-Hellion c285dcb0a0 Polish: README, AI disclosure, scoped Hellion ImGui style
Replace the inherited upstream README with a Hellion-specific one
that lists the privacy/retention/cleanup/export features, links to
upstream and the relevant unanswered filtering issues, documents
the EUPL-1.2 license relationship, and acknowledges Infi & Anna for
the Chat 2 engine that everything builds on.

Add AI_DISCLOSURE.md with the goatcorp Pair classification, an
explicit list of what AI is and is not used for in this fork
(translations, visual assets and license-sensitive boundaries are
handled by the maintainer), and the tooling list. Drops in before
v0.1 so it's already in place when the repo goes public.

HellionStyle.Push() returns a disposable bundle of ImGui color
pushes (cyan-teal accents on a deep-slate frame with steel
borders) and pops them in reverse on Dispose. Privacy tab and the
first-run wizard wrap their Draw with `using var _style =
HellionStyle.Push()` so only Hellion-owned surfaces get the
HUD-flavored palette while upstream Chat 2 tabs render in their
original style — important so cherry-picks from upstream don't
fight with our color overrides.
2026-05-01 21:00:07 +02:00
JonKazama-Hellion 68a6910c53 Add message export for GDPR Art. 15 right of access
The privacy story is incomplete without a way to actually hand the
data over. New Export section in the Privacy tab streams matching
messages to a Markdown, JSON or CSV file using Dalamud's file
dialog and a background thread, so the settings UI stays
responsive even when the export crawls a 150k-message archive.

MessageStore.StreamForExport returns a MessageEnumerator over
non-deleted rows filtered by ChatType list and date range, sorted
ascending. MessageExporter.ExportToFile takes that enumerator,
optionally narrows by SenderSource.TextValue substring (case-
insensitive), and writes one of three formats:

  Markdown — human-readable, day headers, [HH:mm] ChatType Sender:
  prefix per line, trailing total.

  JSON — single object with metadata (filter snapshot, exported_at,
  plugin name) and a messages array carrying id, ISO-8601 date,
  numeric and named ChatType, source/target kinds, receiver,
  content_id, sender plaintext, content plaintext.

  CSV — header line plus quoted-when-needed rows for spreadsheet
  ingestion.

Sender plaintext, channel filter, date range and format are
exposed as form fields above the Export button. Empty channel
selection means "all stored channels", a 0-day range means "no
time limit". Result count and target path are reported via
WrapperUtil notifications.
2026-05-01 20:41:58 +02:00
JonKazama-Hellion 33cfc7effa Add first-run wizard with three privacy profiles
Fresh installs now open a setup window on first plugin load that
asks the user to pick one of three starting profiles. Existing
ChatTwo users keep skipping the wizard because the v6→v7 migration
sets Configuration.FirstRunCompleted = true on the same pass that
seeds the Privacy-First defaults — they already saw the migration
notification and can reopen the wizard from the Privacy tab if
they want to choose differently.

The three profiles map to concrete configuration sets:

  Privacy-First (recommended): own-conversation whitelist (30
  channels), retention enabled with the spec defaults (Tells 365
  days, own-conversation channels 90, fallback 30).

  Casual: Privacy-First plus public chat (Say/Shout/Yell, both
  emote types, Novice Network) with a 1-day retention window so
  RP players can scroll back the last scene without keeping
  third-party speech forever.

  Full History: filter off, retention off, GDPR warning shown
  inline. Behaves like upstream Chat 2.

The wizard window is non-modal but covers a wide layout (three
side-by-side cards) and closing it without picking anything is
treated as accepting whatever defaults are already in place. The
Privacy tab gains a "show wizard again" button at the top so the
choice is reversible.
2026-05-01 20:30:25 +02:00
JonKazama-Hellion 5b33a21d15 Localize the Hellion Chat surface area (EN + DE)
Add HellionStrings.resx as the English source and HellionStrings.de.resx
for German, with a hand-maintained Designer.cs that mirrors the layout
of Language.Designer.cs. Resource files live next to the upstream
Language.resx but are kept entirely separate so upstream cherry-picks
never collide with our translations and any future Hellion-only
translation tooling (Crowdin, manual contribution) can target this
file without touching the Chat 2 dictionary.

Plugin.LanguageChanged now updates HellionStrings.Culture alongside
Language.Culture so every UI string flips to the active locale at the
same moment. The Privacy tab title, master switch, channel groups
(now resolved per frame so the language can change without restart),
preset buttons, failsafe toggle, retention section, cleanup section,
status messages and notification bodies all read from HellionStrings.
The migration toast also takes its title and body from there.

Translations follow the project's German style: Du-Form, full
diacritics (ä, ö, ü), no em-dashes inside flowing prose, "Whitelist"
and "Linkshell" kept as-is because they are the established terms.
2026-05-01 20:03:18 +02:00
JonKazama-Hellion 353596fa43 Fall back to spec retention defaults before the global default
GetRetentionDays previously dropped straight from a missing user
override to RetentionDefaultDays, so every channel showed 30 days
in the UI even though the spec lists 365 for Tells and 90 for own-
conversation channels. Insert a middle layer: user override → spec
default → global default. The retention sweep now seeds its policy
from PrivacyDefaults.DefaultRetentionDays first and lets explicit
user overrides win on top, and the per-channel UI tags each row as
[override], [spec], or [global] so the source of the value is
visible without guessing.
2026-05-01 18:52:54 +02:00
JonKazama-Hellion 68c7185cea Add per-channel message retention with daily background sweep
Privacy filter trimmed history "by what" — this adds the time axis.
Each ChatType gets its own retention window in days; channels
without an explicit override fall back to a configurable global
default. The master switch defaults to OFF: the plugin never
deletes history without explicit user consent.

MessageStore.DeleteByRetentionPolicy builds an OR'd WHERE clause
over (ChatType = X AND Date < cutoff_X) plus a NOT IN catch-all
for the global default, hard-deletes matches, and only runs VACUUM
when something was actually removed.

Plugin.RunRetentionSweepIfDue runs at most once per 24 hours on a
background thread (off the load path) and persists the timestamp
so subsequent restarts skip the sweep until enough time has
passed. The Privacy tab gains a retention section with the master
switch, default-days input, per-channel override tree, reset
buttons, and a Ctrl+Shift "apply now" action that mirrors the
auto-sweep but on demand.

Spec defaults: Tells 365 days, own-conversation channels (Party,
Cross-Party, Alliance, PvP Team, FC, Linkshells 1-8, Cross-World
Linkshells 1-8, ExtraChat 1-8) 90 days, fallback 30 days.
2026-05-01 18:47:31 +02:00
JonKazama-Hellion 2401ea5864 Add retroactive cleanup for the existing database
The privacy filter only catches new messages. Two new MessageStore
methods support a one-shot retroactive sweep: GetMessageCountsByChatType
returns a (ChatType, count) snapshot so the UI can preview the impact,
and CleanupRetainOnly hard-deletes everything outside the supplied
allowlist and runs VACUUM to reclaim disk space.

The Privacy tab gains a new section with a refresh-preview button, a
keep/delete summary, a per-channel breakdown tree, and a Ctrl+Shift
confirm. The cleanup runs on a background thread so a 800+ MB VACUUM
does not block the settings UI; tabs are rebuilt via the framework
thread once the delete finishes. The cleanup deliberately uses the
saved Plugin.Config whitelist (not unsaved Mutable edits) so it stays
consistent with the prospective filter.
2026-05-01 18:34:28 +02:00
JonKazama-Hellion 1ad5cb3164 Add privacy filter with channel whitelist (GDPR Art. 25)
Introduce an opt-out channel whitelist so the database only persists
messages from channels the user explicitly wants to keep. Default
profile follows GDPR data minimization: own conversations only
(Tells, Party, FC, Linkshells, Cross-World Linkshells, Alliance,
ExtraChat). Public chat (Say/Shout/Yell), Novice Network, NPC
dialogue and system logs are dropped by default.

The filter sits inside MessageStore.UpsertMessage so any current or
future write path is covered uniformly. Configuration provides an
IsAllowedForStorage(ChatType) helper plus a "persist unknown
channels" failsafe (default off) for ChatTypes added by future
patches.

A new Privacy settings tab exposes the whitelist as grouped
checkboxes with three preset buttons (Privacy-First, Clear all,
Select all). Configuration version bumps from 6 to 7; existing
users are migrated to the Privacy-First defaults on first load
and notified once via the Dalamud notification manager.

Also includes a small .env.example and gitignore hygiene for local
development setup.
2026-05-01 18:20:09 +02:00
Infi dcf77e27f2 - Fix migration not running for new users
- Use PlayerState for character
2026-04-30 18:14:15 +02:00
Infi b4cb8b25ec - API 15
- Migrate config for API 15
- Migrate database for API 15
- Allow usage of new target source
- Implement first tell target option
2026-04-30 02:59:58 +02:00
Infi c424311b24 - Check auto translation for commands and execute them instead of sending
- Plugin commands trigger the command helper window now
- Fix auto translation with empty text appearing
- Switch up all dalamud payload usage to ROSS if possible
- Prepare 7.5 changes
- Cleanup
2026-04-08 21:15:28 +02:00
Infi 4f9a6cd5be - API 14 2025-12-19 06:49:18 +01:00
Infi 9b3e3f79e3 - Fix imgui asserts on table 2025-09-19 22:49:51 +02:00
Infi efddaf30ad - API 13 2025-08-06 22:24:45 +02:00
Simon Schürrle 0d075ca060 Merge pull request #150
* Hash message links so messages with different links aren't considered…

* Add option to toggle if links should be considered for the message ha…
2025-06-22 20:17:19 +02:00
Infi cb8abc9ed6 - Implement independent hide condition for popouts (closes #124) 2024-12-14 16:39:36 +01:00
Infi 92d4a75ec4 Small oops 2024-12-14 14:59:42 +01:00
Infi 97a8b96326 - Display name even if invalid channel is selected
- Add NoMove & NoResize to tabs
2024-12-14 14:54:20 +01:00
Infi d0a55e80ea - Switch SetTooltip to ImRaii based Tooltip
- Shorter date format for db viewer
2024-11-21 12:31:09 +01:00
Infi 1a1995759a - Handle NBSP payloads
- Use ingame version of axis font
2024-11-21 08:34:24 +01:00
Infi 45fdac0dd6 API 11 2024-11-13 04:13:18 +01:00
Infi 725fe449f8 - Support locked channels
- Implement render limit for webinterface [default 1000]
2024-09-02 12:46:09 +02:00
Infi 8d973ff966 Remove migration code 2024-08-30 23:53:34 +02:00
Infi db3d513f9e Loc the string 2024-08-29 19:06:49 +02:00
Infi cdf4f92ffa Allow users to collapse usage notice 2024-08-29 19:05:46 +02:00
Infi 6cb01aa2f4 Add button indicator for url link 2024-08-28 14:49:50 +02:00