Add settings panel with strip reopen button and AV disabled notification
CI / ci (push) Successful in 46s
CI / ci (push) Successful in 46s
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 <vibe@mistral.ai>
This commit is contained in:
+8
-2
@@ -27,7 +27,8 @@
|
|||||||
"gmShowed": "GM showed {name}'s camera",
|
"gmShowed": "GM showed {name}'s camera",
|
||||||
"personalHidden": "GM has hidden your camera. Your portrait is shown to other Participants.",
|
"personalHidden": "GM has hidden your camera. Your portrait is shown to other Participants.",
|
||||||
"personalShowed": "Your camera is now visible to the table.",
|
"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": {
|
"settings": {
|
||||||
"showGMSelfFeed": {
|
"showGMSelfFeed": {
|
||||||
@@ -205,7 +206,12 @@
|
|||||||
"PlayerPrivacyPanelHint": "Opt in or out of Reaction Cam and other automation features",
|
"PlayerPrivacyPanelHint": "Opt in or out of Reaction Cam and other automation features",
|
||||||
"GMPlayerPrivacySelector": "View Player Privacy Settings",
|
"GMPlayerPrivacySelector": "View Player Privacy Settings",
|
||||||
"GMPlayerPrivacySelectorLabel": "View and manage player privacy consent 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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ import { ConfirmationBar } from './src/ui/gm/ConfirmationBar.js';
|
|||||||
import { PlayerPrivacyPanelMenu, initPlayerPrivacyPanelMenu } from './src/ui/player/PlayerPrivacyPanelMenu.js';
|
import { PlayerPrivacyPanelMenu, initPlayerPrivacyPanelMenu } from './src/ui/player/PlayerPrivacyPanelMenu.js';
|
||||||
import { initGMPlayerPrivacySelector } from './src/ui/gm/GMPlayerPrivacySelector.js';
|
import { initGMPlayerPrivacySelector } from './src/ui/gm/GMPlayerPrivacySelector.js';
|
||||||
import { ScryingPoolCameraViews, initScryingPoolCameraViews } from './src/ui/shared/ScryingPoolCameraViews.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';
|
import { SOCKET_EVENTS } from './src/contracts/socket-message.js';
|
||||||
|
|
||||||
// Module-level references — constructed in init hook, used across hooks
|
// Module-level references — constructed in init hook, used across hooks
|
||||||
@@ -262,6 +268,10 @@ Hooks.once("ready", () => {
|
|||||||
} else if (outcome === 'unsupported') {
|
} else if (outcome === 'unsupported') {
|
||||||
adapter.webrtc = null;
|
adapter.webrtc = null;
|
||||||
console.log('[ScryingPool] WebRTC not available - AV features disabled');
|
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 {
|
} else {
|
||||||
// Legacy: track-disable or css-fallback (deprecated)
|
// Legacy: track-disable or css-fallback (deprecated)
|
||||||
adapter.webrtc = FoundryAdapter.buildWebRTCSurface(game.webrtc);
|
adapter.webrtc = FoundryAdapter.buildWebRTCSurface(game.webrtc);
|
||||||
@@ -403,6 +413,17 @@ Hooks.once("ready", () => {
|
|||||||
type: PlayerPrivacyPanelMenu,
|
type: PlayerPrivacyPanelMenu,
|
||||||
restricted: false,
|
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) {
|
} catch (err) {
|
||||||
console.error('[ScryingPool] Module initialization failed:', err);
|
console.error('[ScryingPool] Module initialization failed:', err);
|
||||||
throw err; // Re-throw to prevent module from loading in broken state
|
throw err; // Re-throw to prevent module from loading in broken state
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<form class="scrying-pool-settings-form">
|
||||||
|
<div class="form-group">
|
||||||
|
<h2>{{localize "SCRYING_POOL.Settings.Title"}}</h2>
|
||||||
|
<p class="hint">{{localize "SCRYING_POOL.Settings.Hint"}}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "SCRYING_POOL.Settings.StripStatus"}}</label>
|
||||||
|
{{#if hasStrip}}
|
||||||
|
<button type="button" data-action="close-strip" class="scrying-pool-btn scrying-pool-btn-close">
|
||||||
|
<i class="fa-solid fa-eye-slash"></i> {{localize "SCRYING_POOL.Settings.CloseStrip"}}
|
||||||
|
</button>
|
||||||
|
{{else}}
|
||||||
|
<button type="button" data-action="reopen-strip" class="scrying-pool-btn scrying-pool-btn-reopen">
|
||||||
|
<i class="fa-solid fa-eye"></i> {{localize "SCRYING_POOL.Settings.ReopenStrip"}}
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.scrying-pool-settings-form {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
.scrying-pool-settings-form .form-group {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
.scrying-pool-settings-form .hint {
|
||||||
|
color: var(--text-muted);
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
.scrying-pool-btn {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.scrying-pool-btn-reopen {
|
||||||
|
background-color: var(--success);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.scrying-pool-btn-close {
|
||||||
|
background-color: var(--danger);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
.scrying-pool-btn:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</form>
|
||||||
Reference in New Issue
Block a user