diff --git a/HellionChat/Plugin.cs b/HellionChat/Plugin.cs index 9e28c46..91c9397 100755 --- a/HellionChat/Plugin.cs +++ b/HellionChat/Plugin.cs @@ -118,6 +118,11 @@ public sealed class Plugin : IAsyncDalamudPlugin internal Commands Commands { get; private set; } = null!; internal GameFunctions.GameFunctions Functions { get; private set; } = null!; internal MessageManager MessageManager { get; private set; } = null!; + + // Reached by the gate-wiring self-test, which has to ask the live tab + // whether it sees a held gate. + internal Ui.Components.Settings.Tabs.DataPrivacyTab DataPrivacyTab { get; private set; } = + null!; internal AutoTellTabsService AutoTellTabsService { get; private set; } = null!; internal IpcManager Ipc { get; private set; } = null!; internal ExtraChat ExtraChat { get; private set; } = null!; @@ -163,10 +168,6 @@ public sealed class Plugin : IAsyncDalamudPlugin // Idempotency guard — Dalamud may fire DisposeAsync twice in a reload race. private int _disposeStarted; - // Set in the first DisposeAsync statement so async callbacks scheduled - // via Framework.RunOnTick (v1.4.8 B3 retention sweep) can early-bail - // before they touch state that has already been torn down. Volatile - // because the tick reads it from a different thread than the writer. // The three hide conditions v1.5.6 evaluated and cf4705e left without a // reader. Advanced once per draw, before any window is drawn. private Util.ChatHideReason _hideReason = Util.ChatHideReason.None; @@ -175,6 +176,10 @@ public sealed class Plugin : IAsyncDalamudPlugin // A cutscene the user dismissed stays dismissed until it ends. internal bool ChatActivationRequested; + // Set in the first DisposeAsync statement so async callbacks scheduled + // via Framework.RunOnTick (v1.4.8 B3 retention sweep) can early-bail + // before they touch state that has already been torn down. Volatile + // because the tick reads it from a different thread than the writer. private volatile bool _isDisposing; // Read by background workers that outlive a teardown -- the export thread @@ -414,6 +419,8 @@ public sealed class Plugin : IAsyncDalamudPlugin InputBar = _host.Services.GetRequiredService(); MainWindow = _host.Services.GetRequiredService(); SettingsWindow = _host.Services.GetRequiredService(); + DataPrivacyTab = + _host.Services.GetRequiredService(); DbViewer = _host.Services.GetRequiredService(); InputPreview = _host.Services.GetRequiredService(); CommandHelpWindow = _host.Services.GetRequiredService(); @@ -485,6 +492,7 @@ public sealed class Plugin : IAsyncDalamudPlugin new SelfTests.OnOpenMainUiRoutesMainWindowStep(this), new SelfTests.TypingIpcStateStep(this), new SelfTests.ConfigMigrationV25Step(this), + new SelfTests.DbGateWiringStep(this), new SelfTests.ChannelPopoutBindStep(this), new SelfTests.HoverStateFootprintStep(), new SelfTests.HonorificHeaderRenderStep(this), diff --git a/HellionChat/Privacy/ChannelGroups.cs b/HellionChat/Privacy/ChannelGroups.cs index 1adae18..8fabbb7 100644 --- a/HellionChat/Privacy/ChannelGroups.cs +++ b/HellionChat/Privacy/ChannelGroups.cs @@ -3,17 +3,15 @@ using HellionChat.Resources; namespace HellionChat.Privacy; -// The eight buckets the privacy surface sorts channels into. Sixty checkboxes in -// one flat list is not a choice anybody makes; eight named groups is. +// The eight buckets the privacy surface sorts channels into. Eighty-nine +// checkboxes in one flat list is not a choice anybody makes; eight named groups +// is. Shared by the export form and the persist grid so the two screens +// describe channels the same way. // // Headings are functions, not strings, so a language switch at runtime relabels // them on the next frame. A captured string would keep the language the window // happened to be opened in. // -// Lives here rather than in a tab because the retention and cleanup screens -// will need the same grouping, and three copies would drift the moment a patch -// adds a channel. Only the export uses it so far. -// // Game Master channels follow ChatTypeExt.Parent(), which already pairs each of // them with its player counterpart. Filing them all under system traffic reads // tidier but puts GmTell -- a private two-person conversation -- outside the diff --git a/HellionChat/Resources/HellionStrings.Designer.cs b/HellionChat/Resources/HellionStrings.Designer.cs index 6510312..887fb2f 100644 --- a/HellionChat/Resources/HellionStrings.Designer.cs +++ b/HellionChat/Resources/HellionStrings.Designer.cs @@ -364,9 +364,9 @@ internal class HellionStrings internal static string Settings_Theme_ResetUnavailable => Get(nameof(Settings_Theme_ResetUnavailable)); internal static string Settings_Theme_LockedTooltip => Get(nameof(Settings_Theme_LockedTooltip)); internal static string Settings_Theme_Custom => Get(nameof(Settings_Theme_Custom)); + internal static string Settings_Tabs_Duplicate => Get(nameof(Settings_Tabs_Duplicate)); internal static string Settings_Theme_ForkActive => Get(nameof(Settings_Theme_ForkActive)); internal static string Settings_Theme_ImportFile => Get(nameof(Settings_Theme_ImportFile)); - internal static string Settings_Theme_ExportActive => Get(nameof(Settings_Theme_ExportActive)); internal static string Settings_Theme_ImportPathHint => Get(nameof(Settings_Theme_ImportPathHint)); internal static string Settings_Theme_ExportDialogTitle => Get(nameof(Settings_Theme_ExportDialogTitle)); internal static string Settings_Theme_Category_Cool => Get(nameof(Settings_Theme_Category_Cool)); @@ -395,7 +395,6 @@ internal class HellionStrings internal static string Settings_Section_Integrations => Get(nameof(Settings_Section_Integrations)); internal static string Settings_Section_Credits => Get(nameof(Settings_Section_Credits)); internal static string Settings_Section_License => Get(nameof(Settings_Section_License)); - internal static string Settings_General_ReduceMotion_Description => Get(nameof(Settings_General_ReduceMotion_Description)); internal static string Settings_Keybinds_Hint => Get(nameof(Settings_Keybinds_Hint)); internal static string Settings_Keybinds_CycleNext => Get(nameof(Settings_Keybinds_CycleNext)); internal static string Settings_Keybinds_CyclePrevious => Get(nameof(Settings_Keybinds_CyclePrevious)); @@ -415,8 +414,6 @@ internal class HellionStrings internal static string Settings_Window_TabPlacement_Description => Get(nameof(Settings_Window_TabPlacement_Description)); internal static string Settings_Window_TitleBar_Name => Get(nameof(Settings_Window_TitleBar_Name)); internal static string Settings_Window_PopoutTitleBar_Name => Get(nameof(Settings_Window_PopoutTitleBar_Name)); - internal static string Settings_Window_InactiveOpacity_Name => Get(nameof(Settings_Window_InactiveOpacity_Name)); - internal static string Settings_Window_InactiveOpacity_Description => Get(nameof(Settings_Window_InactiveOpacity_Description)); internal static string Settings_Window_AllowMove_Name => Get(nameof(Settings_Window_AllowMove_Name)); internal static string Settings_Window_AllowResize_Name => Get(nameof(Settings_Window_AllowResize_Name)); internal static string Settings_Window_SidebarThreshold_Name => Get(nameof(Settings_Window_SidebarThreshold_Name)); @@ -427,8 +424,6 @@ internal class HellionStrings internal static string Settings_About_CustomRepo => Get(nameof(Settings_About_CustomRepo)); internal static string Settings_Section_AutoTranslate => Get(nameof(Settings_Section_AutoTranslate)); internal static string Settings_Emotes_Block => Get(nameof(Settings_Emotes_Block)); - internal static string Settings_NotifyFailedTell_Name => Get(nameof(Settings_NotifyFailedTell_Name)); - internal static string Settings_NotifyFailedTell_Description => Get(nameof(Settings_NotifyFailedTell_Description)); internal static string Settings_Telemetry_None => Get(nameof(Settings_Telemetry_None)); internal static string Settings_Section_Database => Get(nameof(Settings_Section_Database)); diff --git a/HellionChat/Resources/HellionStrings.ca.resx b/HellionChat/Resources/HellionStrings.ca.resx index 18dba14..7354097 100644 --- a/HellionChat/Resources/HellionStrings.ca.resx +++ b/HellionChat/Resources/HellionStrings.ca.resx @@ -1094,12 +1094,6 @@ Bloqueja - - Avisa quan un tell no arriba - - - El joc només informa d'un tell fallit al registre. Això mostra una notificació, perquè un missatge a algú desconnectat o en un altre món no passi desapercebut. - Vés al missatge més recent @@ -1163,9 +1157,6 @@ Llicència - - Desactiva els fosos del tema, els efectes en passar el cursor i les partícules. - Fes clic a un botó i després prem la combinació de tecles. Esc esborra. @@ -1223,12 +1214,6 @@ Barra de títol als pop-outs - - Opacitat inactiva - - - S'aplica mentre una altra finestra té el focus. - Permet moure @@ -1307,9 +1292,6 @@ Importa un fitxer de tema… - - Exporta el tema actiu… - Ruta al fitxer JSON (o arrossega'l a la carpeta) @@ -1343,4 +1325,7 @@ Escriu un missatge... + + Duplica + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.cs.resx b/HellionChat/Resources/HellionStrings.cs.resx index d2943ec..aaaa3fa 100644 --- a/HellionChat/Resources/HellionStrings.cs.resx +++ b/HellionChat/Resources/HellionStrings.cs.resx @@ -1093,12 +1093,6 @@ Zablokovat - - Upozornit, když tell nedorazí - - - Hra hlásí neúspěšný tell jen v logu. Toto místo toho zobrazí upozornění, aby zpráva někomu offline nebo na jiném světě nezůstala bez povšimnutí. - Přejít na nejnovější zprávu @@ -1162,9 +1156,6 @@ Licence - - Vypne prolínání motivů, přechody při najetí myší a poletující částice. - Klikni na tlačítko a poté stiskni kombinaci kláves. Esc smaže. @@ -1222,12 +1213,6 @@ Záhlaví u pop-out oken - - Neprůhlednost při neaktivitě - - - Platí, když má fokus jiné okno. - Povolit přesouvání @@ -1306,9 +1291,6 @@ Importovat soubor motivu… - - Exportovat aktivní motiv… - Cesta k souboru JSON (nebo přetáhni do složky) @@ -1342,4 +1324,7 @@ Napiš zprávu... + + Duplikovat + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.da.resx b/HellionChat/Resources/HellionStrings.da.resx index 67f9078..d13777b 100644 --- a/HellionChat/Resources/HellionStrings.da.resx +++ b/HellionChat/Resources/HellionStrings.da.resx @@ -1093,12 +1093,6 @@ Bloker - - Advar når en tell ikke når frem - - - Spillet melder kun en mislykket tell i loggen. Dette giver en notifikation i stedet, så en besked til nogen offline eller på en anden verden ikke overses. - Hop til den seneste besked @@ -1162,9 +1156,6 @@ Licens - - Slår temaovergange, hover-fade og de svævende partikler fra. - Klik på en knap, og tryk derefter tastekombinationen. Esc rydder. @@ -1222,12 +1213,6 @@ Vis titellinje for pop-out-vinduer - - Uigennemsigtighed når inaktiv - - - Gælder, mens et andet vindue har fokus. - Tillad flytning @@ -1306,9 +1291,6 @@ Importér temafil… - - Eksportér aktivt tema… - Sti til JSON-fil (eller træk-og-slip i mappen) @@ -1342,4 +1324,7 @@ Skriv en besked... + + Duplikér + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.de.resx b/HellionChat/Resources/HellionStrings.de.resx index d59e4fc..e2760fa 100644 --- a/HellionChat/Resources/HellionStrings.de.resx +++ b/HellionChat/Resources/HellionStrings.de.resx @@ -1088,12 +1088,6 @@ Sperren - - Warnen, wenn ein Flüstern nicht ankommt - - - Das Spiel meldet einen fehlgeschlagenen Flüstern nur im Protokoll. Das hier zeigt stattdessen eine Benachrichtigung, damit eine Nachricht an jemanden offline oder auf einer anderen Welt nicht untergeht. - Zur neuesten Nachricht springen @@ -1157,9 +1151,6 @@ Lizenz - - Schaltet Theme-Überblendungen, Hover-Überblendungen und die schwebenden Partikel ab. - Auf einen Knopf klicken, dann die Tastenkombination drücken. Esc löscht. @@ -1217,12 +1208,6 @@ Titelleiste für Pop-Outs - - Deckkraft im Hintergrund - - - Gilt, solange ein anderes Fenster den Fokus hat. - Verschieben erlauben @@ -1301,9 +1286,6 @@ Theme-Datei importieren… - - Aktives Theme exportieren… - Pfad zur JSON-Datei (oder in den Ordner ziehen) @@ -1337,4 +1319,7 @@ Nachricht schreiben... + + Duplizieren + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.el.resx b/HellionChat/Resources/HellionStrings.el.resx index 8241688..f35e762 100644 --- a/HellionChat/Resources/HellionStrings.el.resx +++ b/HellionChat/Resources/HellionStrings.el.resx @@ -1093,12 +1093,6 @@ Αποκλεισμός - - Προειδοποίηση όταν ένα tell δεν φτάνει - - - Το παιχνίδι αναφέρει ένα αποτυχημένο tell μόνο στο αρχείο καταγραφής. Αυτό εμφανίζει ειδοποίηση, ώστε ένα μήνυμα σε κάποιον εκτός σύνδεσης ή σε άλλον κόσμο να μην περάσει απαρατήρητο. - Μετάβαση στο πιο πρόσφατο μήνυμα @@ -1162,9 +1156,6 @@ Άδεια - - Απενεργοποιεί τις μεταβάσεις θέματος, τα εφέ αιώρησης και τα σωματίδια. - Κάντε κλικ σε ένα κουμπί και μετά πατήστε τον συνδυασμό πλήκτρων. Το Esc καθαρίζει. @@ -1222,12 +1213,6 @@ Εμφάνιση γραμμής τίτλου στα αποσπώμενα παράθυρα - - Αδιαφάνεια όταν ανενεργό - - - Ισχύει όσο ένα άλλο παράθυρο έχει την εστίαση. - Να επιτρέπεται η μετακίνηση @@ -1306,9 +1291,6 @@ Εισαγωγή αρχείου θέματος… - - Εξαγωγή ενεργού θέματος… - Διαδρομή προς αρχείο JSON (ή σύρετε στον φάκελο) @@ -1342,4 +1324,7 @@ Γράψτε ένα μήνυμα... + + Αντιγραφή + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.es.resx b/HellionChat/Resources/HellionStrings.es.resx index b057d75..105a5c7 100644 --- a/HellionChat/Resources/HellionStrings.es.resx +++ b/HellionChat/Resources/HellionStrings.es.resx @@ -1094,12 +1094,6 @@ Bloquear - - Avisar cuando un tell no llega - - - El juego solo informa de un tell fallido en el registro. Esto muestra una notificación, para que un mensaje a alguien desconectado o en otro mundo no pase desapercibido. - Ir al mensaje más reciente @@ -1163,9 +1157,6 @@ Licencia - - Desactiva las transiciones del tema, los efectos al pasar el cursor y las partículas. - Haz clic en un botón y luego pulsa la combinación de teclas. Esc borra. @@ -1223,12 +1214,6 @@ Barra de título en pop-outs - - Opacidad inactiva - - - Se aplica mientras otra ventana tiene el foco. - Permitir mover @@ -1307,9 +1292,6 @@ Importar archivo de tema… - - Exportar el tema activo… - Ruta al archivo JSON (o arrástralo a la carpeta) @@ -1343,4 +1325,7 @@ Escribe un mensaje... + + Duplicar + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.fi.resx b/HellionChat/Resources/HellionStrings.fi.resx index c770bf9..0c02e98 100644 --- a/HellionChat/Resources/HellionStrings.fi.resx +++ b/HellionChat/Resources/HellionStrings.fi.resx @@ -1093,12 +1093,6 @@ Estä - - Varoita, kun tell ei mene perille - - - Peli ilmoittaa epäonnistuneesta tellistä vain lokissa. Tämä näyttää sen sijaan ilmoituksen, jottei viesti offline-tilassa tai toisessa maailmassa olevalle jää huomaamatta. - Siirry uusimpaan viestiin @@ -1162,9 +1156,6 @@ Lisenssi - - Poistaa teemaristihäivytykset, osoitinhäivytykset ja leijuvat hiukkaset käytöstä. - Napsauta painiketta ja paina sitten näppäinyhdistelmää. Esc tyhjentää. @@ -1222,12 +1213,6 @@ Näytä otsikkopalkki irrotetuissa ikkunoissa - - Läpinäkymättömyys epäaktiivisena - - - Koskee, kun toinen ikkuna on kohdistettuna. - Salli siirtäminen @@ -1306,9 +1291,6 @@ Tuo teematiedosto… - - Vie aktiivinen teema… - JSON-tiedoston polku (tai vedä kansioon) @@ -1342,4 +1324,7 @@ Kirjoita viesti... + + Kahdenna + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.fr.resx b/HellionChat/Resources/HellionStrings.fr.resx index 361a5c2..93aeb61 100644 --- a/HellionChat/Resources/HellionStrings.fr.resx +++ b/HellionChat/Resources/HellionStrings.fr.resx @@ -1094,12 +1094,6 @@ Bloquer - - Avertir quand un message privé n'arrive pas - - - Le jeu ne signale un message privé échoué que dans le journal. Ceci affiche une notification à la place, pour qu'un message à quelqu'un hors ligne ou sur un autre monde ne passe pas inaperçu. - Aller au message le plus récent @@ -1163,9 +1157,6 @@ Licence - - Désactive les fondus de thème, les effets de survol et les particules flottantes. - Cliquez sur un bouton, puis appuyez sur la combinaison de touches. Échap efface. @@ -1223,12 +1214,6 @@ Afficher la barre de titre des fenêtres détachées - - Opacité inactive - - - S'applique quand une autre fenêtre a le focus. - Autoriser le déplacement @@ -1307,9 +1292,6 @@ Importer un fichier de thème… - - Exporter le thème actif… - Chemin du fichier JSON (ou glissez-déposez dans le dossier) @@ -1343,4 +1325,7 @@ Écrivez un message... + + Dupliquer + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.hu.resx b/HellionChat/Resources/HellionStrings.hu.resx index d94f370..ed40eb9 100644 --- a/HellionChat/Resources/HellionStrings.hu.resx +++ b/HellionChat/Resources/HellionStrings.hu.resx @@ -1093,12 +1093,6 @@ Letiltás - - Figyelmeztetés, ha egy tell nem érkezik meg - - - A játék csak a naplóban jelzi a sikertelen tellt. Ez helyette értesítést jelenít meg, hogy egy offline vagy másik világon lévő játékosnak küldött üzenet ne maradjon észrevétlen. - Ugrás a legutóbbi üzenetre @@ -1162,9 +1156,6 @@ Licenc - - Kikapcsolja a témaátmeneteket, a rámutatási elhalványulást és a lebegő részecskéket. - Kattints egy gombra, majd nyomd le a billentyűkombinációt. Az Esc törli. @@ -1222,12 +1213,6 @@ Címsor a pop-out ablakoknál - - Átlátszatlanság inaktívan - - - Akkor érvényes, ha másik ablak van fókuszban. - Mozgatás engedélyezése @@ -1306,9 +1291,6 @@ Témafájl importálása… - - Aktív téma exportálása… - A JSON-fájl útvonala (vagy húzd a mappába) @@ -1342,4 +1324,7 @@ Írj egy üzenetet... + + Másolat + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.it.resx b/HellionChat/Resources/HellionStrings.it.resx index a08b665..98a745c 100644 --- a/HellionChat/Resources/HellionStrings.it.resx +++ b/HellionChat/Resources/HellionStrings.it.resx @@ -1094,12 +1094,6 @@ Blocca - - Avvisa quando un tell non arriva - - - Il gioco segnala un tell fallito solo nel registro. Questo mostra invece una notifica, così un messaggio a qualcuno offline o in un altro mondo non passa inosservato. - Vai al messaggio più recente @@ -1163,9 +1157,6 @@ Licenza - - Disattiva le dissolvenze del tema, gli effetti al passaggio del mouse e le particelle. - Fai clic su un pulsante, poi premi la combinazione di tasti. Esc cancella. @@ -1223,12 +1214,6 @@ Barra del titolo nei pop-out - - Opacità finestra inattiva - - - Si applica mentre un'altra finestra ha il focus. - Consenti lo spostamento @@ -1307,9 +1292,6 @@ Importa file tema… - - Esporta il tema attivo… - Percorso del file JSON (o trascinalo nella cartella) @@ -1343,4 +1325,7 @@ Scrivi un messaggio... + + Duplica + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.ja.resx b/HellionChat/Resources/HellionStrings.ja.resx index 3716ff0..9b23c70 100644 --- a/HellionChat/Resources/HellionStrings.ja.resx +++ b/HellionChat/Resources/HellionStrings.ja.resx @@ -1094,12 +1094,6 @@ ブロック - - テルが届かなかったときに警告する - - - ゲームはテルの失敗をログにしか表示しません。この設定では代わりに通知を出すので、オフラインや別ワールドの相手へのメッセージを見落としません。 - 最新のメッセージへ移動 @@ -1163,9 +1157,6 @@ ライセンス - - テーマのクロスフェード、ホバー時のフェード、漂う粒子を無効にします。 - ボタンをクリックしてからキーの組み合わせを押してください。Esc で解除します。 @@ -1223,12 +1214,6 @@ ポップアウトのタイトルバーを表示 - - 非アクティブ時の不透明度 - - - 別のウィンドウがフォーカスされている間に適用されます。 - 移動を許可 @@ -1307,9 +1292,6 @@ テーマファイルをインポート… - - 現在のテーマをエクスポート… - JSONファイルのパス(またはフォルダーにドラッグ&ドロップ) @@ -1343,4 +1325,7 @@ メッセージを入力... + + 複製 + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.ko.resx b/HellionChat/Resources/HellionStrings.ko.resx index 6f68f84..47cc108 100644 --- a/HellionChat/Resources/HellionStrings.ko.resx +++ b/HellionChat/Resources/HellionStrings.ko.resx @@ -1094,12 +1094,6 @@ 차단 - - 귓속말이 전달되지 않으면 알림 - - - 게임은 귓속말 실패를 로그에만 표시합니다. 이 설정은 대신 알림을 띄워, 오프라인이거나 다른 월드에 있는 상대에게 보낸 메시지를 놓치지 않게 합니다. - 최신 메시지로 이동 @@ -1163,9 +1157,6 @@ 라이선스 - - 테마 전환 효과, 마우스 오버 페이드, 떠다니는 입자를 끕니다. - 버튼을 클릭한 뒤 키 조합을 누르세요. Esc로 지웁니다. @@ -1223,12 +1214,6 @@ 팝아웃 창의 제목 표시줄 보이기 - - 비활성 상태 불투명도 - - - 다른 창이 포커스를 가진 동안 적용됩니다. - 이동 허용 @@ -1307,9 +1292,6 @@ 테마 파일 가져오기… - - 현재 테마 내보내기… - JSON 파일 경로 (또는 폴더로 끌어다 놓기) @@ -1343,4 +1325,7 @@ 메시지를 입력하세요... + + 복제 + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.nb.resx b/HellionChat/Resources/HellionStrings.nb.resx index 815fe59..f3824e9 100644 --- a/HellionChat/Resources/HellionStrings.nb.resx +++ b/HellionChat/Resources/HellionStrings.nb.resx @@ -1093,12 +1093,6 @@ Blokker - - Varsle når en tell ikke kommer frem - - - Spillet melder en mislykket tell bare i loggen. Dette gir et varsel i stedet, så en melding til noen offline eller på en annen verden ikke blir oversett. - Hopp til den nyeste meldingen @@ -1162,9 +1156,6 @@ Lisens - - Slår av temaovergang, hover-toning og de drivende partiklene. - Klikk på en knapp, og trykk deretter tastekombinasjonen. Esc tømmer. @@ -1222,12 +1213,6 @@ Tittellinje for pop-out-vinduer - - Dekkevne når inaktiv - - - Gjelder mens et annet vindu har fokus. - Tillat flytting @@ -1306,9 +1291,6 @@ Importer temafil… - - Eksporter aktivt tema… - Sti til JSON-fil (eller dra og slipp i mappen) @@ -1342,4 +1324,7 @@ Skriv en melding... + + Dupliser + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.nl.resx b/HellionChat/Resources/HellionStrings.nl.resx index 1773a17..8e5fed6 100644 --- a/HellionChat/Resources/HellionStrings.nl.resx +++ b/HellionChat/Resources/HellionStrings.nl.resx @@ -1094,12 +1094,6 @@ Blokkeren - - Waarschuwen als een tell niet aankomt - - - Het spel meldt een mislukte tell alleen in het log. Dit toont in plaats daarvan een melding, zodat een bericht aan iemand offline of op een andere wereld niet onopgemerkt blijft. - Ga naar het nieuwste bericht @@ -1163,9 +1157,6 @@ Licentie - - Schakelt themaovergangen, hover-fades en de zwevende deeltjes uit. - Klik op een knop en druk daarna de toetsencombinatie. Esc wist. @@ -1223,12 +1214,6 @@ Titelbalk voor pop-outvensters - - Dekking bij inactiviteit - - - Geldt terwijl een ander venster de focus heeft. - Verplaatsen toestaan @@ -1307,9 +1292,6 @@ Themabestand importeren… - - Actief thema exporteren… - Pad naar JSON-bestand (of sleep het naar de map) @@ -1343,4 +1325,7 @@ Typ een bericht... + + Dupliceren + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.pl.resx b/HellionChat/Resources/HellionStrings.pl.resx index 6cea3dc..8164f55 100644 --- a/HellionChat/Resources/HellionStrings.pl.resx +++ b/HellionChat/Resources/HellionStrings.pl.resx @@ -1093,12 +1093,6 @@ Zablokuj - - Ostrzegaj, gdy tell nie dotrze - - - Gra zgłasza nieudany tell tylko w dzienniku. To zamiast tego wyświetla powiadomienie, żeby wiadomość do kogoś offline lub na innym świecie nie umknęła. - Przejdź do najnowszej wiadomości @@ -1162,9 +1156,6 @@ Licencja - - Wyłącza przenikanie motywów, wygaszanie przy najechaniu i unoszące się cząstki. - Kliknij przycisk, a następnie naciśnij kombinację klawiszy. Esc czyści. @@ -1222,12 +1213,6 @@ Pokaż pasek tytułu w oknach odłączonych - - Nieprzezroczystość, gdy nieaktywne - - - Obowiązuje, gdy inne okno ma fokus. - Zezwól na przesuwanie @@ -1306,9 +1291,6 @@ Importuj plik motywu… - - Eksportuj aktywny motyw… - Ścieżka do pliku JSON (lub przeciągnij do folderu) @@ -1342,4 +1324,7 @@ Napisz wiadomość... + + Duplikuj + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.pt-BR.resx b/HellionChat/Resources/HellionStrings.pt-BR.resx index c185c79..4c418ea 100644 --- a/HellionChat/Resources/HellionStrings.pt-BR.resx +++ b/HellionChat/Resources/HellionStrings.pt-BR.resx @@ -1094,12 +1094,6 @@ Bloquear - - Avisar quando um tell não chega - - - O jogo relata um tell que falhou apenas no registro. Isto mostra uma notificação, para que uma mensagem a alguém offline ou em outro mundo não passe despercebida. - Ir para a mensagem mais recente @@ -1163,9 +1157,6 @@ Licença - - Desativa as transições de tema, os efeitos ao passar o cursor e as partículas. - Clique em um botão e depois pressione a combinação de teclas. Esc limpa. @@ -1223,12 +1214,6 @@ Mostrar barra de título nas janelas destacadas - - Opacidade inativa - - - Aplica-se enquanto outra janela está em foco. - Permitir mover @@ -1307,9 +1292,6 @@ Importar arquivo de tema… - - Exportar o tema ativo… - Caminho do arquivo JSON (ou arraste para a pasta) @@ -1343,4 +1325,7 @@ Digite uma mensagem... + + Duplicar + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.pt-PT.resx b/HellionChat/Resources/HellionStrings.pt-PT.resx index 925e834..361a83f 100644 --- a/HellionChat/Resources/HellionStrings.pt-PT.resx +++ b/HellionChat/Resources/HellionStrings.pt-PT.resx @@ -1093,12 +1093,6 @@ Bloquear - - Avisar quando um tell não chega - - - O jogo comunica um tell falhado apenas no registo. Isto mostra uma notificação, para que uma mensagem a alguém offline ou noutro mundo não passe despercebida. - Ir para a mensagem mais recente @@ -1162,9 +1156,6 @@ Licença - - Desativa as transições de tema, os efeitos ao passar o cursor e as partículas. - Clique num botão e depois prima a combinação de teclas. Esc limpa. @@ -1222,12 +1213,6 @@ Mostrar barra de título nas janelas destacadas - - Opacidade inativa - - - Aplica-se enquanto outra janela está em foco. - Permitir mover @@ -1306,9 +1291,6 @@ Importar ficheiro de tema… - - Exportar o tema ativo… - Caminho do ficheiro JSON (ou arraste para a pasta) @@ -1342,4 +1324,7 @@ Escreva uma mensagem... + + Duplicar + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.resx b/HellionChat/Resources/HellionStrings.resx index b93a3de..087d394 100644 --- a/HellionChat/Resources/HellionStrings.resx +++ b/HellionChat/Resources/HellionStrings.resx @@ -1114,12 +1114,6 @@ Block - - Warn when a tell does not arrive - - - The game reports a failed tell in the log only. This raises a notification instead, so a message to someone offline or on another world does not go unnoticed. - off @@ -1174,9 +1168,6 @@ License - - Turns off theme crossfades, hover fades and the drifting motes. - Click a button, then press the key combination. Esc clears. @@ -1234,12 +1225,6 @@ Show title bar for pop-outs - - Inactive opacity - - - Applies while another window has focus. - Allow movement @@ -1318,9 +1303,6 @@ Import theme file… - - Export active theme… - Path to JSON file (or drag-and-drop into the folder) @@ -1354,4 +1336,7 @@ Type a message... + + Duplicate + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.ro.resx b/HellionChat/Resources/HellionStrings.ro.resx index a7753e9..cc06371 100644 --- a/HellionChat/Resources/HellionStrings.ro.resx +++ b/HellionChat/Resources/HellionStrings.ro.resx @@ -1094,12 +1094,6 @@ Blochează - - Avertizează când un tell nu ajunge - - - Jocul raportează un tell eșuat doar în jurnal. Aceasta afișează în schimb o notificare, ca un mesaj către cineva offline sau aflat pe altă lume să nu treacă neobservat. - Salt la cel mai recent mesaj @@ -1163,9 +1157,6 @@ Licență - - Dezactivează tranzițiile temei, efectele la trecerea cursorului și particulele. - Fă clic pe un buton, apoi apasă combinația de taste. Esc șterge. @@ -1223,12 +1214,6 @@ Afișează bara de titlu la ferestrele desprinse - - Opacitate când e inactiv - - - Se aplică cât timp altă fereastră are focusul. - Permite mutarea @@ -1307,9 +1292,6 @@ Importă fișier de temă… - - Exportă tema activă… - Calea către fișierul JSON (sau trage-l în folder) @@ -1343,4 +1325,7 @@ Scrie un mesaj... + + Duplică + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.ru.resx b/HellionChat/Resources/HellionStrings.ru.resx index bf7c5b0..de4d70d 100644 --- a/HellionChat/Resources/HellionStrings.ru.resx +++ b/HellionChat/Resources/HellionStrings.ru.resx @@ -1094,12 +1094,6 @@ Заблокировать - - Предупреждать, когда tell не доходит - - - Игра сообщает о недоставленном tell только в журнале. Здесь вместо этого показывается уведомление, чтобы сообщение офлайн-игроку или игроку с другого мира не осталось незамеченным. - Перейти к последнему сообщению @@ -1163,9 +1157,6 @@ Лицензия - - Отключает переходы темы, затухание при наведении и плавающие частицы. - Нажмите кнопку, затем нажмите сочетание клавиш. Esc очищает. @@ -1223,12 +1214,6 @@ Показывать заголовок в отдельных окнах - - Непрозрачность в неактивном состоянии - - - Действует, пока фокус на другом окне. - Разрешить перемещение @@ -1307,9 +1292,6 @@ Импортировать файл темы… - - Экспортировать активную тему… - Путь к файлу JSON (или перетащите его в папку) @@ -1343,4 +1325,7 @@ Введите сообщение... + + Дублировать + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.sv.resx b/HellionChat/Resources/HellionStrings.sv.resx index 8ecf1a6..c77e20a 100644 --- a/HellionChat/Resources/HellionStrings.sv.resx +++ b/HellionChat/Resources/HellionStrings.sv.resx @@ -1094,12 +1094,6 @@ Blockera - - Varna när en tell inte kommer fram - - - Spelet rapporterar en misslyckad tell bara i loggen. Det här visar en avisering i stället, så att ett meddelande till någon offline eller på en annan värld inte missas. - Hoppa till det senaste meddelandet @@ -1163,9 +1157,6 @@ Licens - - Stänger av temaövertoningar, hovertoningar och de svävande partiklarna. - Klicka på en knapp och tryck sedan tangentkombinationen. Esc rensar. @@ -1223,12 +1214,6 @@ Namnlist för pop-out-fönster - - Opacitet vid inaktivitet - - - Gäller medan ett annat fönster har fokus. - Tillåt flytt @@ -1307,9 +1292,6 @@ Importera temafil… - - Exportera aktivt tema… - Sökväg till JSON-fil (eller dra och släpp i mappen) @@ -1343,4 +1325,7 @@ Skriv ett meddelande... + + Duplicera + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.tr.resx b/HellionChat/Resources/HellionStrings.tr.resx index fef7005..7d95d2c 100644 --- a/HellionChat/Resources/HellionStrings.tr.resx +++ b/HellionChat/Resources/HellionStrings.tr.resx @@ -1093,12 +1093,6 @@ Engelle - - Bir tell ulaşmadığında uyar - - - Oyun başarısız bir tell'i yalnızca kayıtta bildirir. Bu ayar bunun yerine bir bildirim gösterir, böylece çevrimdışı ya da başka bir dünyadaki birine gönderilen ileti gözden kaçmaz. - En son iletiye git @@ -1162,9 +1156,6 @@ Lisans - - Tema geçişlerini, üzerine gelme solmalarını ve süzülen parçacıkları kapatır. - Bir düğmeye tıklayın, ardından tuş kombinasyonuna basın. Esc temizler. @@ -1222,12 +1213,6 @@ Ayrık pencereler için başlık çubuğunu göster - - Etkin değilken opaklık - - - Başka bir pencere odaktayken geçerlidir. - Taşımaya izin ver @@ -1306,9 +1291,6 @@ Tema dosyası içe aktar… - - Etkin temayı dışa aktar… - JSON dosyasının yolu (veya klasöre sürükleyip bırakın) @@ -1342,4 +1324,7 @@ Bir ileti yazın... + + Çoğalt + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.uk.resx b/HellionChat/Resources/HellionStrings.uk.resx index 8c337e5..403ad43 100644 --- a/HellionChat/Resources/HellionStrings.uk.resx +++ b/HellionChat/Resources/HellionStrings.uk.resx @@ -1093,12 +1093,6 @@ Заблокувати - - Попереджати, коли tell не доходить - - - Гра повідомляє про недоставлений tell лише в журналі. Це натомість показує сповіщення, щоб повідомлення офлайн-гравцю або гравцю з іншого світу не залишилося непоміченим. - Перейти до останнього повідомлення @@ -1162,9 +1156,6 @@ Ліцензія - - Вимикає переходи теми, згасання при наведенні та плаваючі частинки. - Натисніть кнопку, потім натисніть комбінацію клавіш. Esc очищає. @@ -1222,12 +1213,6 @@ Показувати рядок заголовка у відокремлених вікнах - - Непрозорість у неактивному стані - - - Діє, поки фокус на іншому вікні. - Дозволити переміщення @@ -1306,9 +1291,6 @@ Імпортувати файл теми… - - Експортувати активну тему… - Шлях до файлу JSON (або перетягніть у теку) @@ -1342,4 +1324,7 @@ Введіть повідомлення... + + Дублювати + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.zh-Hans.resx b/HellionChat/Resources/HellionStrings.zh-Hans.resx index cb8c456..a21a232 100644 --- a/HellionChat/Resources/HellionStrings.zh-Hans.resx +++ b/HellionChat/Resources/HellionStrings.zh-Hans.resx @@ -1094,12 +1094,6 @@ 屏蔽 - - 密语未送达时提醒 - - - 游戏只在日志里提示密语发送失败。此设置改为弹出通知,让发给离线或其他世界玩家的消息不会被忽略。 - 跳到最新消息 @@ -1163,9 +1157,6 @@ 许可证 - - 关闭主题淡入淡出、悬停渐变和漂浮粒子。 - 点击按钮后按下组合键。Esc 清除。 @@ -1223,12 +1214,6 @@ 显示弹出窗口的标题栏 - - 非活动时的不透明度 - - - 当另一个窗口获得焦点时生效。 - 允许移动 @@ -1307,9 +1292,6 @@ 导入主题文件… - - 导出当前主题… - JSON 文件路径(或拖放到文件夹) @@ -1343,4 +1325,7 @@ 输入消息... + + 复制 + \ No newline at end of file diff --git a/HellionChat/Resources/HellionStrings.zh-Hant.resx b/HellionChat/Resources/HellionStrings.zh-Hant.resx index 8290ce9..f4026a6 100644 --- a/HellionChat/Resources/HellionStrings.zh-Hant.resx +++ b/HellionChat/Resources/HellionStrings.zh-Hant.resx @@ -1094,12 +1094,6 @@ 封鎖 - - 悄悄話未送達時提醒 - - - 遊戲只在日誌裡提示悄悄話傳送失敗。此設定改為彈出通知,讓發給離線或其他世界玩家的訊息不會被忽略。 - 跳到最新訊息 @@ -1163,9 +1157,6 @@ 授權 - - 關閉主題淡入淡出、滑過漸變和漂浮粒子。 - 點擊按鈕後按下組合鍵。Esc 清除。 @@ -1223,12 +1214,6 @@ 顯示彈出視窗的標題列 - - 非作用中的不透明度 - - - 當另一個視窗取得焦點時生效。 - 允許移動 @@ -1307,9 +1292,6 @@ 匯入主題檔案… - - 匯出目前主題… - JSON 檔案路徑(或拖放到資料夾) @@ -1343,4 +1325,7 @@ 輸入訊息... + + 複製 + \ No newline at end of file diff --git a/HellionChat/SelfTests/DbGateWiringStep.cs b/HellionChat/SelfTests/DbGateWiringStep.cs new file mode 100644 index 0000000..573d199 --- /dev/null +++ b/HellionChat/SelfTests/DbGateWiringStep.cs @@ -0,0 +1,131 @@ +using Dalamud.Bindings.ImGui; +using Dalamud.Plugin.SelfTest; +using HellionChat.Ui.Components.Settings; +using HellionChat.Util; + +namespace HellionChat.SelfTests; + +// The gate has fourteen unit tests. None of them prove that the workers are +// wired to it, and that is where the mistake actually happened: the metadata +// refresh reached the store without taking the gate at all, and its flag was +// missing from the tab's shared busy state, so a wipe could start while it held +// the read lock. +// +// A unit test cannot see that. It needs the real singleton, the real flags and +// the real settings tab, so it lives here. +internal sealed class DbGateWiringStep : ISelfTestStep +{ + private readonly Plugin _plugin; + + public DbGateWiringStep(Plugin plugin) => _plugin = plugin; + + public string Name => "Hellion Chat - DB gate wiring"; + + public SelfTestStepResult RunStep() + { + var failures = new List(); + + // Nothing may be running when the probe starts, or the assertions below + // measure somebody else's operation. + if (_plugin.DbOperations.IsBusy) + failures.Add($"gate already held by {_plugin.DbOperations.Current} before the probe"); + + CheckEveryOperationRoundTrips(failures); + CheckRefusalLeavesTheOwnerAlone(failures); + CheckRevisionTracksMutations(failures); + CheckTabSeesTheGate(failures); + + foreach (var f in failures) + ImGui.Text(f); + + SelfTestReport.Append(Name, failures.Count == 0 ? "PASS" : "FAIL", failures); + return failures.Count == 0 ? SelfTestStepResult.Pass : SelfTestStepResult.Fail; + } + + private void CheckEveryOperationRoundTrips(List failures) + { + foreach (var op in EnumValues.All) + { + if (op == DbOperation.None) + continue; + + if (!_plugin.DbOperations.TryBegin(op)) + { + failures.Add($"{op}: TryBegin refused on a free gate"); + continue; + } + + if (_plugin.DbOperations.Current != op) + failures.Add($"{op}: gate reports {_plugin.DbOperations.Current} after TryBegin"); + + if (_plugin.DbOperations.TryBegin(op)) + failures.Add($"{op}: a second TryBegin succeeded while it was held"); + + _plugin.DbOperations.End(op); + + if (_plugin.DbOperations.IsBusy) + failures.Add($"{op}: still busy after End"); + } + } + + private void CheckRefusalLeavesTheOwnerAlone(List failures) + { + if (!_plugin.DbOperations.TryBegin(DbOperation.Export)) + { + failures.Add("could not take the gate for the refusal check"); + return; + } + + // A worker whose TryBegin was refused still runs its finally. Releasing + // there must not hand away somebody else's lock. + _plugin.DbOperations.End(DbOperation.Clear); + + if (_plugin.DbOperations.Current != DbOperation.Export) + failures.Add("a foreign End released the gate"); + + _plugin.DbOperations.End(DbOperation.Export); + } + + private void CheckRevisionTracksMutations(List failures) + { + var before = _plugin.DbOperations.Revision; + + _plugin.DbOperations.TryBegin(DbOperation.Export); + _plugin.DbOperations.End(DbOperation.Export); + if (_plugin.DbOperations.Revision != before) + failures.Add("export moved the revision; it cannot change a row"); + + _plugin.DbOperations.TryBegin(DbOperation.Cleanup); + _plugin.DbOperations.End(DbOperation.Cleanup); + if (_plugin.DbOperations.Revision == before) + failures.Add( + "cleanup did not move the revision; a stale preview would pass as current" + ); + } + + // The settings tab decides whether the destructive buttons are live. If it + // cannot see a held gate, two of them are clickable at once. + private void CheckTabSeesTheGate(List failures) + { + if (!_plugin.DbOperations.TryBegin(DbOperation.Clear)) + { + failures.Add("could not take the gate for the tab check"); + return; + } + + try + { + if (!_plugin.DataPrivacyTab.AnythingRunningForSelfTest) + failures.Add("the data and privacy tab does not see a held gate"); + } + finally + { + _plugin.DbOperations.End(DbOperation.Clear); + } + + if (_plugin.DataPrivacyTab.AnythingRunningForSelfTest) + failures.Add("the tab still reports busy after the gate was released"); + } + + public void CleanUp() { } +} diff --git a/HellionChat/Ui/Components/Settings/TabEditor.cs b/HellionChat/Ui/Components/Settings/TabEditor.cs index 739ed1a..524d297 100644 --- a/HellionChat/Ui/Components/Settings/TabEditor.cs +++ b/HellionChat/Ui/Components/Settings/TabEditor.cs @@ -171,7 +171,12 @@ internal sealed class TabEditor // already has its sixty channels picked, and Tab.Clone has been ready // for it since v1.8.0. ImGui.SameLine(); - if (ImGuiUtil.IconButton(FontAwesomeIcon.Copy, tooltip: Language.Options_Tabs_Add)) + if ( + ImGuiUtil.IconButton( + FontAwesomeIcon.Copy, + tooltip: HellionStrings.Settings_Tabs_Duplicate + ) + ) { var copy = tab.Clone(); copy.Identifier = Guid.NewGuid(); @@ -191,7 +196,6 @@ internal sealed class TabEditor if (_editing == tab.Identifier) ClearWorking(); - _ = TabLifecycleHelpers.SelectionAfterDelete(tabs, index); _plugin.SaveConfig(); RequestRefilter(); } diff --git a/HellionChat/Ui/Components/Settings/Tabs/DataPrivacyTab.cs b/HellionChat/Ui/Components/Settings/Tabs/DataPrivacyTab.cs index 1841ce3..e7ea970 100644 --- a/HellionChat/Ui/Components/Settings/Tabs/DataPrivacyTab.cs +++ b/HellionChat/Ui/Components/Settings/Tabs/DataPrivacyTab.cs @@ -69,6 +69,11 @@ internal sealed class DataPrivacyTab // refusal the user has to trigger to discover is not an answer. private DbOperation CurrentOperation => _plugin.DbOperations.Current; + // The gate-wiring self-test asserts that this sees a held gate. It is the + // one thing about this state that a unit test cannot reach: the flags are + // instance state on a DI singleton and the gate is another. + internal bool AnythingRunningForSelfTest => AnythingRunning; + private bool AnythingRunning => _exportRunning || _exportDialogOpen @@ -76,6 +81,7 @@ internal sealed class DataPrivacyTab || _cleanupRunning || _clearRunning || _maintenanceRunning + || _dbRefreshRunning || _plugin.RetentionSweepRunning || CurrentOperation != DbOperation.None; @@ -380,21 +386,27 @@ internal sealed class DataPrivacyTab ImGuiUtil.Tooltip(Language.Options_Database_Metadata_CopyConfigPath); } - ImGuiUtil.HelpText( - string.Format( - Language.Options_Database_Metadata_Size, - StringUtil.BytesToString(_dbSize) - ) - ); - ImGuiUtil.HelpText( - string.Format( - Language.Options_Database_Metadata_LogSize, - StringUtil.BytesToString(_dbLogSize) - ) - ); - ImGuiUtil.HelpText( - string.Format(Language.Options_Database_Metadata_MessageCount, _dbMessageCount) - ); + // Same reason the clear hint below waits: the fields start at zero, and + // "0 B / 0 messages" reads as an empty database rather than as a number + // that has not been fetched yet. + if (_dbEverRefreshed) + { + ImGuiUtil.HelpText( + string.Format( + Language.Options_Database_Metadata_Size, + StringUtil.BytesToString(_dbSize) + ) + ); + ImGuiUtil.HelpText( + string.Format( + Language.Options_Database_Metadata_LogSize, + StringUtil.BytesToString(_dbLogSize) + ) + ); + ImGuiUtil.HelpText( + string.Format(Language.Options_Database_Metadata_MessageCount, _dbMessageCount) + ); + } ImGui.Spacing(); @@ -458,11 +470,25 @@ internal sealed class DataPrivacyTab { try { - _dbSize = _plugin.MessageManager.Store.DatabaseSize(); - _dbLogSize = _plugin.MessageManager.Store.DatabaseLogSize(); - _dbMessageCount = _plugin.MessageManager.Store.MessageCount(); - _dbRefreshedAt = Environment.TickCount64; - _dbEverRefreshed = true; + // Takes the gate like every other reader of the store. + // MessageCount holds _readLock, and a VACUUM starting under it + // is exactly the collision this gate was written for -- being a + // read rather than a write does not exempt it. + if (!_plugin.DbOperations.TryBegin(DbOperation.Cleanup)) + return; + + try + { + _dbSize = _plugin.MessageManager.Store.DatabaseSize(); + _dbLogSize = _plugin.MessageManager.Store.DatabaseLogSize(); + _dbMessageCount = _plugin.MessageManager.Store.MessageCount(); + _dbRefreshedAt = Environment.TickCount64; + _dbEverRefreshed = true; + } + finally + { + _plugin.DbOperations.End(DbOperation.Cleanup); + } } catch (Exception e) { @@ -561,6 +587,11 @@ internal sealed class DataPrivacyTab { _clearRunning = false; _logger.LogError(e, "Could not start the clear thread"); + + // The most destructive button in the plugin. Silence here means the + // user pressed it and nothing happened, with no way to tell that + // from a wipe that worked. + Notify(HellionStrings.Settings_Database_ClearError, NotificationType.Error); } } @@ -682,6 +713,11 @@ internal sealed class DataPrivacyTab catch (Exception e) { _logger.LogError(e, "Manual maintenance failed"); + + // The comment above promises refusals are said out loud. A + // failure that is not is the same silence wearing a different + // hat. + Notify(HellionStrings.Settings_Database_ClearError, NotificationType.Error); } finally { @@ -1047,7 +1083,7 @@ internal sealed class DataPrivacyTab { _cleanupRunning = false; _logger.LogError(e, "Could not start the cleanup thread"); - WrapperUtil.AddNotification(HellionStrings.Cleanup_Error, NotificationType.Error); + Notify(HellionStrings.Cleanup_Error, NotificationType.Error); } } @@ -1106,9 +1142,9 @@ internal sealed class DataPrivacyTab ); } - // Whole groups rather than sixty individual channels. Nobody makes a - // sixty-way choice, and the eight groups are the same ones the privacy - // wizard already uses, so the two screens describe the world the same way. + // Whole groups rather than eighty-nine individual channels. Nobody makes an + // eighty-nine-way choice, and the same eight groups carry the persist grid + // below, so the two screens describe channels the same way. private void DrawExportChannels() { ImGui.Spacing(); @@ -1334,7 +1370,7 @@ internal sealed class DataPrivacyTab // The thread never ran, so nothing will clear the flag for us. _exportRunning = false; _logger.LogError(e, "Could not start the export thread"); - WrapperUtil.AddNotification(HellionStrings.Export_Error, NotificationType.Error); + Notify(HellionStrings.Export_Error, NotificationType.Error); } } diff --git a/HellionChat/Ui/Components/Settings/Tabs/GeneralTab.cs b/HellionChat/Ui/Components/Settings/Tabs/GeneralTab.cs index f7e0c31..fb8328c 100644 --- a/HellionChat/Ui/Components/Settings/Tabs/GeneralTab.cs +++ b/HellionChat/Ui/Components/Settings/Tabs/GeneralTab.cs @@ -44,7 +44,7 @@ internal sealed class GeneralTab _w.ToggleRow( ImGui.GetID("general.behaviour.reducemotion"u8), HellionStrings.Settings_ThemeAndLayout_ReduceMotion_Name, - HellionStrings.Settings_General_ReduceMotion_Description, + HellionStrings.Settings_ThemeAndLayout_ReduceMotion_Description, () => Plugin.Config.ReduceMotion, v => Plugin.Config.ReduceMotion = v ); @@ -80,8 +80,8 @@ internal sealed class GeneralTab // is typing does not see it. On by default and never reachable. _w.ToggleRow( ImGui.GetID("general.notifications.failedtell"u8), - HellionStrings.Settings_NotifyFailedTell_Name, - HellionStrings.Settings_NotifyFailedTell_Description, + HellionStrings.Settings_Chat_NotifyFailedTell_Name, + HellionStrings.Settings_Chat_NotifyFailedTell_Description, () => Plugin.Config.NotifyFailedTell, v => Plugin.Config.NotifyFailedTell = v ); diff --git a/HellionChat/Ui/Components/Settings/Tabs/WindowTab.cs b/HellionChat/Ui/Components/Settings/Tabs/WindowTab.cs index dd45dc6..885b6df 100644 --- a/HellionChat/Ui/Components/Settings/Tabs/WindowTab.cs +++ b/HellionChat/Ui/Components/Settings/Tabs/WindowTab.cs @@ -93,8 +93,8 @@ internal sealed class WindowTab ); _w.SliderFloatRow( ImGui.GetID("window.opacity.inactive"u8), - HellionStrings.Settings_Window_InactiveOpacity_Name, - HellionStrings.Settings_Window_InactiveOpacity_Description, + HellionStrings.Settings_ThemeAndLayout_WindowOpacityInactive_Name, + HellionStrings.Settings_ThemeAndLayout_WindowOpacityInactive_Description, () => Plugin.Config.WindowOpacityInactive, v => Plugin.Config.WindowOpacityInactive = v, 0.1f, diff --git a/HellionChat/Ui/Components/Settings/ThemeImportExportRow.cs b/HellionChat/Ui/Components/Settings/ThemeImportExportRow.cs index 1656a08..2801923 100644 --- a/HellionChat/Ui/Components/Settings/ThemeImportExportRow.cs +++ b/HellionChat/Ui/Components/Settings/ThemeImportExportRow.cs @@ -39,7 +39,7 @@ internal sealed class ThemeImportExportRow } ImGui.SameLine(); - if (ImGui.Button(HellionStrings.Settings_Theme_ExportActive)) + if (ImGui.Button(HellionStrings.Settings_Themes_ExportActive)) { ExportActive(); } diff --git a/HellionChat/Util/TabLifecycleHelpers.cs b/HellionChat/Util/TabLifecycleHelpers.cs index f08aaa6..5c9887f 100644 --- a/HellionChat/Util/TabLifecycleHelpers.cs +++ b/HellionChat/Util/TabLifecycleHelpers.cs @@ -52,24 +52,6 @@ internal static class TabLifecycleHelpers return index; } - // Which tab the editor should select after deleting the one at index. - // - // The next editable tab below, else the one above, else nothing. Returning - // the index the caller should select *after* the removal, so it is already - // shifted. - public static int SelectionAfterDelete(IReadOnlyList tabs, int deletedIndex) - { - for (var i = deletedIndex + 1; i < tabs.Count; i++) - if (IsEditable(tabs[i])) - return i - 1; - - for (var i = deletedIndex - 1; i >= 0; i--) - if (IsEditable(tabs[i])) - return i; - - return -1; - } - // Deleting the last editable tab leaves a window with nothing to draw, and // the message list has no empty state. The editor offers templates instead // of a delete in that situation. diff --git a/PRIVACY.md b/PRIVACY.md index 1918b8f..a6fedca 100644 --- a/PRIVACY.md +++ b/PRIVACY.md @@ -22,8 +22,8 @@ Last reviewed: 2026-08-18 (HellionChat v1.12.0). no remote update check beyond what Dalamud itself does. - One outbound network call exists by design: the BetterTTV emote service (for chat emotes). It is documented in detail below and can be reasoned about per request. -- You can export every message the plugin has stored, in Markdown, JSON or CSV. You can delete it - by channel, by age, or all of it at once. +- You can export every message the plugin has stored, in Markdown, JSON or CSV. You can delete it by + channel, by age, or all of it at once. --- @@ -96,8 +96,9 @@ font is bundled instead. incoming chat message contains a token matching one of the cached IDs. These are cached locally (`EmoteCacheV1/`) and reused across sessions. - **Cached:** Yes, in `EmoteCacheV1/`. A given emote is downloaded once per machine and reused. -- **How to opt out:** Turn off the **Show emotes** option in Settings → Chat → Display modes. With it disabled, the - emote cache does not load and no requests to BetterTTV are made for the rest of the session. +- **How to opt out:** Turn off the **Show emotes** option in Settings → Chat → Display modes. With + it disabled, the emote cache does not load and no requests to BetterTTV are made for the rest of + the session. - **BetterTTV's privacy policy:** Source: `HellionChat/EmoteCache.cs`. @@ -119,10 +120,10 @@ Cached `FFXIV_Lodestone_SSF.ttf` files left over from earlier versions remain in ### Links you click yourself (no automatic traffic) The About tab contains buttons that open external pages in your browser when you click them: the -Hellion Forge Discord invite, the HellionChat Gitea repository, its custom-repo manifest, and -- when -the Honorific integration row is shown -- that plugin's GitHub repository and its author's profile. -Nothing happens until you click. They are documented here for completeness, not because they -generate background traffic. +Hellion Forge Discord invite, the HellionChat Gitea repository, its custom-repo manifest, and -- +when the Honorific integration row is shown -- that plugin's GitHub repository and its author's +profile. Nothing happens until you click. They are documented here for completeness, not because +they generate background traffic. --- @@ -150,8 +151,8 @@ locally, those rights translate directly into plugin features: ### Right to access (Art. 15) -Settings → Data & Privacy → Export. You can export to **Markdown**, **JSON** or **CSV**, narrowed -by channel group, by age in days, or by a substring of the sender's name. The export goes through a +Settings → Data & Privacy → Export. You can export to **Markdown**, **JSON** or **CSV**, narrowed by +channel group, by age in days, or by a substring of the sender's name. The export goes through a Dalamud file dialog and writes wherever you point it, on your machine. It reads the database on its own connection and writes to a temporary file first, so a run that is interrupted leaves the previous export in place rather than a file that looks complete and is not. @@ -183,6 +184,7 @@ Two options: channel is stored and nothing contradicts your settings; with no channel selected, a cleanup would delete everything, and that is what the clear button is for. Both cases say so instead of offering a button that does not do what it looks like. + 2. **Full deletion.** Close the game and delete the `pluginConfigs/HellionChat/` directory. The next plugin start will produce a fresh, empty configuration. diff --git a/docs/THEME-AUTHORING.md b/docs/THEME-AUTHORING.md index 6556268..924f3c7 100644 --- a/docs/THEME-AUTHORING.md +++ b/docs/THEME-AUTHORING.md @@ -183,8 +183,8 @@ Check `/xllog` after a plugin reload to see what loaded and what didn't. 4. Watch every plugin window (chat, settings, pop-out) and pick something to fix. 5. Tweak. Reload. Repeat. -Tip: the **Settings → Appearance** picker shows a mini-mockup per theme — your colors are visible before -you switch. +Tip: the **Settings → Appearance** picker shows a mini-mockup per theme — your colors are visible +before you switch. ## Sharing themes