Checkpoint current interactive fiction state
This commit is contained in:
+127
-14
@@ -45,7 +45,8 @@ class OptionsUIModule extends BaseModule {
|
||||
'setupInitialState',
|
||||
'dispatchApiChangeEvent',
|
||||
'getPreference',
|
||||
'updatePreference'
|
||||
'updatePreference',
|
||||
'renderProviderStatuses'
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -183,20 +184,21 @@ class OptionsUIModule extends BaseModule {
|
||||
const speedValue = document.createElement('span');
|
||||
speedValue.className = 'slider-value';
|
||||
speedValue.textContent = '100%';
|
||||
this.elements.ttsSpeedValue = speedValue;
|
||||
speedContainer.appendChild(speedValue);
|
||||
|
||||
this.elements.ttsSpeed = createUIElement('input', {
|
||||
type: 'range',
|
||||
min: 50,
|
||||
max: 200,
|
||||
max: 150,
|
||||
value: 100,
|
||||
'data-pref-bind': 'app.speed',
|
||||
'data-pref-transform': 'range:0.5,2.0'
|
||||
'data-pref-bind': 'tts.speed',
|
||||
'data-pref-transform': 'centered-speed'
|
||||
}, null, speedContainer);
|
||||
|
||||
// Update displayed value when slider changes
|
||||
this.elements.ttsSpeed.addEventListener('input', () => {
|
||||
speedValue.textContent = `${this.elements.ttsSpeed.value}%`;
|
||||
this.updateSpeedDisplay();
|
||||
});
|
||||
|
||||
appSettingsSection.appendChild(speedContainer);
|
||||
@@ -239,6 +241,11 @@ class OptionsUIModule extends BaseModule {
|
||||
}, null, ttsSystemContainer);
|
||||
|
||||
ttsSection.appendChild(ttsSystemContainer);
|
||||
|
||||
const providerStatusContainer = document.createElement('div');
|
||||
providerStatusContainer.className = 'provider-status-list';
|
||||
this.elements.providerStatus = providerStatusContainer;
|
||||
ttsSection.appendChild(providerStatusContainer);
|
||||
|
||||
// TTS Voice
|
||||
const ttsVoiceContainer = document.createElement('div');
|
||||
@@ -510,7 +517,12 @@ class OptionsUIModule extends BaseModule {
|
||||
if (this.elements.ttsSystem) {
|
||||
this.elements.ttsSystem.addEventListener('change', async (event) => {
|
||||
this.updateApiSettingsVisibility(event.target.value);
|
||||
const ttsFactory = this.getModule('tts-factory');
|
||||
if (ttsFactory) {
|
||||
await ttsFactory.refreshHandlerStatus(event.target.value);
|
||||
}
|
||||
await this.populateVoices();
|
||||
this.renderProviderStatuses();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -595,6 +607,7 @@ class OptionsUIModule extends BaseModule {
|
||||
|
||||
// Update API settings visibility
|
||||
this.updateApiSettingsVisibility(this.elements.ttsSystem.value);
|
||||
this.renderProviderStatuses();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -604,8 +617,10 @@ class OptionsUIModule extends BaseModule {
|
||||
const ttsFactory = this.getModule('tts-factory');
|
||||
if (!ttsFactory || !this.elements.ttsVoice) return;
|
||||
|
||||
// Get voices for current TTS system
|
||||
const voices = await ttsFactory.getVoices() || [];
|
||||
const selectedHandler = this.elements.ttsSystem?.value || this.getPreference('tts', 'preferred_handler', 'none');
|
||||
const voices = typeof ttsFactory.getVoicesForHandler === 'function'
|
||||
? await ttsFactory.getVoicesForHandler(selectedHandler) || []
|
||||
: await ttsFactory.getVoices() || [];
|
||||
console.log('Options UI: TTS voices:', voices);
|
||||
|
||||
// Populate dropdown
|
||||
@@ -614,9 +629,35 @@ class OptionsUIModule extends BaseModule {
|
||||
voices,
|
||||
'id',
|
||||
'name',
|
||||
this.getPreference('tts', 'voice', '')
|
||||
this.getPreference('tts', `${selectedHandler}_voice`, this.getPreference('tts', 'voice', ''))
|
||||
);
|
||||
}
|
||||
|
||||
renderProviderStatuses() {
|
||||
const container = this.elements.providerStatus;
|
||||
const ttsFactory = this.getModule('tts-factory');
|
||||
if (!container || !ttsFactory || typeof ttsFactory.getHandlerStatuses !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = '';
|
||||
const statuses = ttsFactory.getHandlerStatuses();
|
||||
statuses.forEach(status => {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'provider-status-row';
|
||||
|
||||
const name = document.createElement('span');
|
||||
name.textContent = status.name;
|
||||
row.appendChild(name);
|
||||
|
||||
const value = document.createElement('span');
|
||||
value.className = 'provider-status-value';
|
||||
value.textContent = `${status.ready ? 'ready' : 'not ready'} - ${status.message}`;
|
||||
row.appendChild(value);
|
||||
|
||||
container.appendChild(row);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the languages dropdown
|
||||
@@ -737,6 +778,7 @@ class OptionsUIModule extends BaseModule {
|
||||
document.addEventListener('tts:voices:updated', () => {
|
||||
console.log('Options UI: Received tts:voices:updated event, updating voice dropdown');
|
||||
this.populateVoices();
|
||||
this.renderProviderStatuses();
|
||||
});
|
||||
|
||||
// Set up language change listener
|
||||
@@ -750,6 +792,36 @@ class OptionsUIModule extends BaseModule {
|
||||
console.log('Options UI: Received TTS engine change event:', event.detail);
|
||||
await this.populateVoices();
|
||||
this.updateApiSettingsVisibility(this.elements.ttsSystem.value);
|
||||
this.renderProviderStatuses();
|
||||
});
|
||||
|
||||
document.addEventListener('tts:status:updated', () => {
|
||||
this.renderProviderStatuses();
|
||||
});
|
||||
|
||||
document.addEventListener('tts:enabled:change', async (event) => {
|
||||
if (!event.detail || typeof event.detail.enabled !== 'boolean') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.elements.ttsEnabled) {
|
||||
this.elements.ttsEnabled.checked = event.detail.enabled;
|
||||
}
|
||||
|
||||
const ttsFactory = this.getModule('tts-factory');
|
||||
if (!ttsFactory) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.detail.enabled) {
|
||||
const preferredHandler = this.getPreference('tts', 'preferred_handler', 'none');
|
||||
if (preferredHandler !== 'none') {
|
||||
await ttsFactory.setActiveHandler(preferredHandler);
|
||||
}
|
||||
} else {
|
||||
await ttsFactory.disableAfterCurrentPlayback();
|
||||
}
|
||||
this.renderProviderStatuses();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -766,6 +838,7 @@ class OptionsUIModule extends BaseModule {
|
||||
// Setup all bindings in the modal
|
||||
this.bindings = persistenceManager.setupBindings('#options-modal');
|
||||
console.log('Options UI: Preference bindings set up', this.bindings.length);
|
||||
this.updateSpeedDisplay();
|
||||
|
||||
// Add event listeners for side effects when preferences change
|
||||
document.addEventListener('preference-updated', (event) => {
|
||||
@@ -793,16 +866,46 @@ class OptionsUIModule extends BaseModule {
|
||||
if (!ttsFactory) return;
|
||||
|
||||
if (key === 'preferred_handler') {
|
||||
this.populateVoices();
|
||||
const enabled = this.getPreference('tts', 'enabled', false);
|
||||
const activation = enabled && value !== 'none'
|
||||
? ttsFactory.setActiveHandler(value)
|
||||
: Promise.resolve(ttsFactory.disableAfterCurrentPlayback());
|
||||
activation.then(() => {
|
||||
this.populateVoices();
|
||||
this.renderProviderStatuses();
|
||||
});
|
||||
this.updateApiSettingsVisibility(value);
|
||||
} else if (key === 'voice') {
|
||||
ttsFactory.configure({ voice: value });
|
||||
} else if (key === 'speed') {
|
||||
ttsFactory.configure({ speed: value });
|
||||
} else if (key === 'language') {
|
||||
ttsFactory.configure({ language: value });
|
||||
} else if (key === 'enabled') {
|
||||
ttsFactory.configure({ enabled: value });
|
||||
}
|
||||
if (!value) {
|
||||
ttsFactory.disableAfterCurrentPlayback();
|
||||
} else {
|
||||
const preferredHandler = this.getPreference('tts', 'preferred_handler', 'none');
|
||||
if (preferredHandler !== 'none') {
|
||||
ttsFactory.setActiveHandler(preferredHandler);
|
||||
}
|
||||
}
|
||||
document.dispatchEvent(new CustomEvent('tts:enabled:change', {
|
||||
detail: { enabled: value }
|
||||
}));
|
||||
} else if (key.endsWith('_api_key')) {
|
||||
const provider = key.replace('_api_key', '');
|
||||
this.dispatchApiChangeEvent('api:keyChanged', provider, 'key', value);
|
||||
ttsFactory.refreshHandlerStatus(provider).then(() => this.renderProviderStatuses());
|
||||
} else if (key.endsWith('_api_url')) {
|
||||
const provider = key.replace('_api_url', '');
|
||||
this.dispatchApiChangeEvent('api:urlChanged', provider, 'url', value);
|
||||
ttsFactory.refreshHandlerStatus(provider).then(() => this.renderProviderStatuses());
|
||||
}
|
||||
if (key === 'speed' && this.elements.ttsSpeed) {
|
||||
this.updateSpeedDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
// Handle locale changes
|
||||
if (category === 'app' && key === 'locale') {
|
||||
@@ -810,16 +913,26 @@ class OptionsUIModule extends BaseModule {
|
||||
if (localization) {
|
||||
localization.setLocale(value);
|
||||
}
|
||||
const ttsFactory = this.getModule('tts-factory');
|
||||
if (ttsFactory) {
|
||||
ttsFactory.configure({ language: value });
|
||||
}
|
||||
this.updatePreference('tts', 'language', value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateSpeedDisplay() {
|
||||
if (!this.elements.ttsSpeed || !this.elements.ttsSpeedValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.elements.ttsSpeedValue.textContent = `${this.elements.ttsSpeed.value}%`;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the singleton instance
|
||||
const OptionsUI = new OptionsUIModule();
|
||||
|
||||
// Register with the module registry
|
||||
moduleRegistry.register(OptionsUI);
|
||||
|
||||
// Export the module
|
||||
export { OptionsUI };
|
||||
|
||||
Reference in New Issue
Block a user