From 6bbde5c1cfa6d563086044e90c13ee1a6a2ef255 Mon Sep 17 00:00:00 2001 From: LeRatierBretonnier Date: Mon, 25 May 2026 15:57:58 +0200 Subject: [PATCH] Add settings panel with strip reopen button and AV disabled notification Features: - Added ScryingPoolSettings application with reopen/close strip buttons - Registered settings menu in module settings (GM only) - Added template for settings panel with styled buttons - Added translations for settings UI - Added info notification when AV is not available Files: - src/ui/gm/ScryingPoolSettings.js: New settings application - templates/settings.hbs: Settings panel template - lang/en.json: Added translations - module.js: Registered settings menu and AV notification Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe --- lang/en.json | 10 ++++- module.js | 21 ++++++++++ src/ui/gm/ScryingPoolSettings.js | 69 ++++++++++++++++++++++++++++++++ templates/settings.hbs | 53 ++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 src/ui/gm/ScryingPoolSettings.js create mode 100644 templates/settings.hbs diff --git a/lang/en.json b/lang/en.json index 6265460..8d04f44 100644 --- a/lang/en.json +++ b/lang/en.json @@ -27,7 +27,8 @@ "gmShowed": "GM showed {name}'s camera", "personalHidden": "GM has hidden your camera. Your portrait is shown to other Participants.", "personalShowed": "Your camera is now visible to the table.", - "avConfigGMOnly": "A/V settings are managed by the GM." + "avConfigGMOnly": "A/V settings are managed by the GM.", + "AVDisabled": "Audio/Video is not available in this FoundryVTT instance. Scrying Pool camera control features are disabled." }, "settings": { "showGMSelfFeed": { @@ -205,7 +206,12 @@ "PlayerPrivacyPanelHint": "Opt in or out of Reaction Cam and other automation features", "GMPlayerPrivacySelector": "View Player Privacy Settings", "GMPlayerPrivacySelectorLabel": "View and manage player privacy consent settings", - "GMPlayerPrivacySelectorHint": "Select a player to view their automation opt-in preferences (read-only)" + "GMPlayerPrivacySelectorHint": "Select a player to view their automation opt-in preferences (read-only)", + "Title": "Scrying Pool Settings", + "Hint": "Configure Scrying Pool module behavior", + "StripStatus": "Strip Status", + "ReopenStrip": "Open Strip", + "CloseStrip": "Close Strip" } } } diff --git a/module.js b/module.js index 17e7573..9b6ce43 100644 --- a/module.js +++ b/module.js @@ -35,6 +35,12 @@ import { ConfirmationBar } from './src/ui/gm/ConfirmationBar.js'; import { PlayerPrivacyPanelMenu, initPlayerPrivacyPanelMenu } from './src/ui/player/PlayerPrivacyPanelMenu.js'; import { initGMPlayerPrivacySelector } from './src/ui/gm/GMPlayerPrivacySelector.js'; import { ScryingPoolCameraViews, initScryingPoolCameraViews } from './src/ui/shared/ScryingPoolCameraViews.js'; +import { ScryingPoolSettings } from './src/ui/gm/ScryingPoolSettings.js'; + +// Factory function to create ScryingPoolSettings with roleRenderer dependency +function initScryingPoolSettings(roleRendererRef) { + return () => new ScryingPoolSettings(roleRendererRef); +} import { SOCKET_EVENTS } from './src/contracts/socket-message.js'; // Module-level references — constructed in init hook, used across hooks @@ -262,6 +268,10 @@ Hooks.once("ready", () => { } else if (outcome === 'unsupported') { adapter.webrtc = null; console.log('[ScryingPool] WebRTC not available - AV features disabled'); + // Show info message to GM about AV being disabled + if (game.user?.isGM) { + ui.notifications?.info(game.i18n.localize('SCRYING_POOL.Notifications.AVDisabled')); + } } else { // Legacy: track-disable or css-fallback (deprecated) adapter.webrtc = FoundryAdapter.buildWebRTCSurface(game.webrtc); @@ -403,6 +413,17 @@ Hooks.once("ready", () => { type: PlayerPrivacyPanelMenu, restricted: false, }); + + // Story 5.3: Register ScryingPoolSettings in module settings + // Provides button to reopen the strip + game.settings.registerMenu('scrying-pool', 'stripSettings', { + name: 'SCRYING_POOL.Settings.Title', + label: 'SCRYING_POOL.Settings.Title', + hint: 'SCRYING_POOL.Settings.Hint', + icon: 'fa-solid fa-cog', + type: initScryingPoolSettings(roleRenderer), + restricted: true, // GM only + }); } catch (err) { console.error('[ScryingPool] Module initialization failed:', err); throw err; // Re-throw to prevent module from loading in broken state diff --git a/src/ui/gm/ScryingPoolSettings.js b/src/ui/gm/ScryingPoolSettings.js new file mode 100644 index 0000000..1475402 --- /dev/null +++ b/src/ui/gm/ScryingPoolSettings.js @@ -0,0 +1,69 @@ +// @ts-nocheck +/** + * Scrying Pool Settings Application + * Provides a settings panel with a button to reopen the strip + */ +export class ScryingPoolSettings extends foundry.applications.api.ApplicationV2 { + static DEFAULT_OPTIONS = { + id: 'scrying-pool-settings', + classes: ['scrying-pool-settings'], + window: { title: 'Scrying Pool Settings', resizable: true }, + position: { width: 400, height: 200 }, + }; + + static PARTS = { + form: { + template: 'modules/scrying-pool/templates/settings.hbs', + }, + }; + + /** + * @param {object} options - Application options + * @param {object} roleRenderer - The role renderer instance to access openStrip/closeStrip + */ + constructor(roleRenderer, options = {}) { + super(options); + this._roleRenderer = roleRenderer; + } + + /** @inheritdoc */ + async _prepareContext(options) { + return { + hasStrip: this._roleRenderer?._strip?.rendered ?? false, + }; + } + + /** @inheritdoc */ + async _onRender(context, options) { + super._onRender(context, options); + + // Add click handler for reopen button + const reopenBtn = this.element.querySelector('[data-action="reopen-strip"]'); + if (reopenBtn) { + reopenBtn.addEventListener('click', () => { + this._roleRenderer?.openStrip(); + this.close(); + }); + } + + // Add click handler for close button + const closeBtn = this.element.querySelector('[data-action="close-strip"]'); + if (closeBtn) { + closeBtn.addEventListener('click', () => { + this._roleRenderer?.closeStrip(); + this.close(); + }); + } + } + + /** + * Toggle the strip open/closed + */ + _toggleStrip() { + if (this._roleRenderer?._strip?.rendered) { + this._roleRenderer.closeStrip(); + } else { + this._roleRenderer?.openStrip(); + } + } +} diff --git a/templates/settings.hbs b/templates/settings.hbs new file mode 100644 index 0000000..6858196 --- /dev/null +++ b/templates/settings.hbs @@ -0,0 +1,53 @@ +
+
+

{{localize "SCRYING_POOL.Settings.Title"}}

+

{{localize "SCRYING_POOL.Settings.Hint"}}

+
+ +
+ + {{#if hasStrip}} + + {{else}} + + {{/if}} +
+ + +