Initial
This commit is contained in:
207
resources/app/client/apps/av/av-config.js
Normal file
207
resources/app/client/apps/av/av-config.js
Normal file
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* Audio/Video Conferencing Configuration Sheet
|
||||
* @extends {FormApplication}
|
||||
*
|
||||
* @param {AVMaster} object The {@link AVMaster} instance being configured.
|
||||
* @param {FormApplicationOptions} [options] Application configuration options.
|
||||
*/
|
||||
class AVConfig extends FormApplication {
|
||||
constructor(object, options) {
|
||||
super(object || game.webrtc, options);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
title: game.i18n.localize("WEBRTC.Title"),
|
||||
id: "av-config",
|
||||
template: "templates/sidebar/apps/av-config.html",
|
||||
popOut: true,
|
||||
width: 480,
|
||||
height: "auto",
|
||||
tabs: [{navSelector: ".tabs", contentSelector: "form", initial: "general"}]
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
async getData(options={}) {
|
||||
const settings = this.object.settings;
|
||||
const videoSources = await this.object.client.getVideoSources();
|
||||
const audioSources = await this.object.client.getAudioSources();
|
||||
const audioSinks = await this.object.client.getAudioSinks();
|
||||
|
||||
// If the currently chosen device is unavailable, display a separate option for 'unavailable device (use default)'
|
||||
const { videoSrc, audioSrc, audioSink } = settings.client;
|
||||
const videoSrcUnavailable = this._isSourceUnavailable(videoSources, videoSrc);
|
||||
const audioSrcUnavailable = this._isSourceUnavailable(audioSources, audioSrc);
|
||||
const audioSinkUnavailable = this._isSourceUnavailable(audioSinks, audioSink);
|
||||
const isSSL = window.location.protocol === "https:";
|
||||
|
||||
// Audio/Video modes
|
||||
const modes = {
|
||||
[AVSettings.AV_MODES.DISABLED]: "WEBRTC.ModeDisabled",
|
||||
[AVSettings.AV_MODES.AUDIO]: "WEBRTC.ModeAudioOnly",
|
||||
[AVSettings.AV_MODES.VIDEO]: "WEBRTC.ModeVideoOnly",
|
||||
[AVSettings.AV_MODES.AUDIO_VIDEO]: "WEBRTC.ModeAudioVideo"
|
||||
};
|
||||
|
||||
// Voice Broadcast modes
|
||||
const voiceModes = Object.values(AVSettings.VOICE_MODES).reduce((obj, m) => {
|
||||
obj[m] = game.i18n.localize(`WEBRTC.VoiceMode${m.titleCase()}`);
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
// Nameplate settings.
|
||||
const nameplates = {
|
||||
[AVSettings.NAMEPLATE_MODES.OFF]: "WEBRTC.NameplatesOff",
|
||||
[AVSettings.NAMEPLATE_MODES.PLAYER_ONLY]: "WEBRTC.NameplatesPlayer",
|
||||
[AVSettings.NAMEPLATE_MODES.CHAR_ONLY]: "WEBRTC.NameplatesCharacter",
|
||||
[AVSettings.NAMEPLATE_MODES.BOTH]: "WEBRTC.NameplatesBoth"
|
||||
};
|
||||
|
||||
const dockPositions = Object.fromEntries(Object.values(AVSettings.DOCK_POSITIONS).map(p => {
|
||||
return [p, game.i18n.localize(`WEBRTC.DockPosition${p.titleCase()}`)];
|
||||
}));
|
||||
|
||||
// Return data to the template
|
||||
return {
|
||||
user: game.user,
|
||||
modes,
|
||||
voiceModes,
|
||||
serverTypes: {FVTT: "WEBRTC.FVTTSignalingServer", custom: "WEBRTC.CustomSignalingServer"},
|
||||
turnTypes: {server: "WEBRTC.TURNServerProvisioned", custom: "WEBRTC.CustomTURNServer"},
|
||||
settings,
|
||||
canSelectMode: game.user.isGM && isSSL,
|
||||
noSSL: !isSSL,
|
||||
videoSources,
|
||||
audioSources,
|
||||
audioSinks: foundry.utils.isEmpty(audioSinks) ? false : audioSinks,
|
||||
videoSrcUnavailable,
|
||||
audioSrcUnavailable,
|
||||
audioSinkUnavailable,
|
||||
audioDisabled: audioSrc === "disabled",
|
||||
videoDisabled: videoSrc === "disabled",
|
||||
nameplates,
|
||||
nameplateSetting: settings.client.nameplates ?? AVSettings.NAMEPLATE_MODES.BOTH,
|
||||
dockPositions,
|
||||
audioSourceOptions: this.#getDevices(audioSources, audioSrcUnavailable, "WEBRTC.DisableAudioSource"),
|
||||
audioSinkOptions: this.#getDevices(audioSinks, audioSinkUnavailable),
|
||||
videoSourceOptions: this.#getDevices(videoSources, videoSrcUnavailable, "WEBRTC.DisableVideoSource")
|
||||
};
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get an array of available devices which can be chosen.
|
||||
* @param {Record<string, string>} devices
|
||||
* @param {string} unavailableDevice
|
||||
* @param {string} disabledLabel
|
||||
* @returns {FormSelectOption[]}
|
||||
*/
|
||||
#getDevices(devices, unavailableDevice, disabledLabel) {
|
||||
const options = [];
|
||||
let hasDefault = false;
|
||||
for ( const [k, v] of Object.entries(devices) ) {
|
||||
if ( k === "default" ) hasDefault = true;
|
||||
options.push({value: k, label: v});
|
||||
}
|
||||
if ( !hasDefault ) {
|
||||
options.unshift({value: "default", label: game.i18n.localize("WEBRTC.DefaultSource")});
|
||||
}
|
||||
if ( disabledLabel ) {
|
||||
options.unshift({value: "disabled", label: game.i18n.localize(disabledLabel)});
|
||||
}
|
||||
if ( unavailableDevice ) {
|
||||
options.push({value: unavailableDevice, label: game.i18n.localize("WEBRTC.UnavailableDevice")});
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
/* Event Listeners and Handlers */
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
|
||||
// Options below are GM only
|
||||
if ( !game.user.isGM ) return;
|
||||
html.find('select[name="world.turn.type"]').change(this._onTurnTypeChanged.bind(this));
|
||||
|
||||
// Activate or de-activate the custom server and turn configuration sections based on current settings
|
||||
const settings = this.object.settings;
|
||||
this._setConfigSectionEnabled(".webrtc-custom-turn-config", settings.world.turn.type === "custom");
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Set a section's input to enabled or disabled
|
||||
* @param {string} selector Selector for the section to enable or disable
|
||||
* @param {boolean} enabled Whether to enable or disable this section
|
||||
* @private
|
||||
*/
|
||||
_setConfigSectionEnabled(selector, enabled = true) {
|
||||
let section = this.element.find(selector);
|
||||
if (section) {
|
||||
section.css("opacity", enabled ? 1.0 : 0.5);
|
||||
section.find("input").prop("disabled", !enabled);
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Determine whether a given video or audio source, or audio sink has become
|
||||
* unavailable since the last time it was set.
|
||||
* @param {object} sources The available devices
|
||||
* @param {string} source The selected device
|
||||
* @private
|
||||
*/
|
||||
_isSourceUnavailable(sources, source) {
|
||||
const specialValues = ["default", "disabled"];
|
||||
return source && (!specialValues.includes(source)) && !Object.keys(sources).includes(source);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Callback when the turn server type changes
|
||||
* Will enable or disable the turn section based on whether the user selected a custom turn or not
|
||||
* @param {Event} event The event that triggered the turn server type change
|
||||
* @private
|
||||
*/
|
||||
_onTurnTypeChanged(event) {
|
||||
event.preventDefault();
|
||||
const choice = event.currentTarget.value;
|
||||
this._setConfigSectionEnabled(".webrtc-custom-turn-config", choice === "custom")
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
|
||||
/** @override */
|
||||
async _updateObject(event, formData) {
|
||||
const settings = game.webrtc.settings;
|
||||
settings.client.videoSrc = settings.client.videoSrc || null;
|
||||
settings.client.audioSrc = settings.client.audioSrc || null;
|
||||
|
||||
const update = foundry.utils.expandObject(formData);
|
||||
|
||||
// Update world settings
|
||||
if ( game.user.isGM ) {
|
||||
if ( settings.world.mode !== update.world.mode ) SettingsConfig.reloadConfirm({world: true});
|
||||
const world = foundry.utils.mergeObject(settings.world, update.world);
|
||||
await game.settings.set("core", "rtcWorldSettings", world);
|
||||
}
|
||||
|
||||
// Update client settings
|
||||
const client = foundry.utils.mergeObject(settings.client, update.client);
|
||||
await game.settings.set("core", "rtcClientSettings", client);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user