mirror of
https://github.com/mssoftjp/obsidian-voice-input.git
synced 2026-07-22 06:44:48 +00:00
fix: guard voice input UI promises
This commit is contained in:
parent
7ddd851713
commit
5ff1787f6d
4 changed files with 48 additions and 19 deletions
|
|
@ -118,7 +118,9 @@ export default class VoiceInputPlugin extends Plugin {
|
|||
// Add ribbon icon
|
||||
this.addRibbonIcon('microphone', i18n.t('ui.titles.main'), () => {
|
||||
this.logger.debug('Ribbon icon clicked');
|
||||
void this.viewManager.activateVoiceInputView();
|
||||
void this.viewManager.activateVoiceInputView().catch((error) => {
|
||||
this.logger.error('Failed to activate Voice Input view from ribbon', error);
|
||||
});
|
||||
});
|
||||
this.logger.debug('Ribbon icon added');
|
||||
|
||||
|
|
@ -128,7 +130,9 @@ export default class VoiceInputPlugin extends Plugin {
|
|||
name: i18n.t('ui.commands.openView'),
|
||||
callback: () => {
|
||||
this.logger.debug('Command executed: open-view');
|
||||
void this.viewManager.activateVoiceInputView();
|
||||
void this.viewManager.activateVoiceInputView().catch((error) => {
|
||||
this.logger.error('Failed to activate Voice Input view from command', error);
|
||||
});
|
||||
}
|
||||
});
|
||||
this.logger.debug('Commands registered');
|
||||
|
|
@ -153,7 +157,13 @@ export default class VoiceInputPlugin extends Plugin {
|
|||
}
|
||||
|
||||
onunload(): void {
|
||||
void this.teardownPlugin();
|
||||
void this.teardownPlugin().catch((error) => {
|
||||
if (this.logger?.error) {
|
||||
this.logger.error('Voice Input Plugin unload failed', error);
|
||||
} else if (typeof console !== 'undefined' && console.error) {
|
||||
console.error('Voice Input Plugin unload failed', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async teardownPlugin(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,9 @@ export class VoiceInputView extends ItemView {
|
|||
}
|
||||
|
||||
onOpen(): void {
|
||||
void this.handleOpen();
|
||||
void this.handleOpen().catch((error) => {
|
||||
console.error('Failed to open Voice Input view', error);
|
||||
});
|
||||
}
|
||||
|
||||
private async handleOpen(): Promise<void> {
|
||||
|
|
@ -83,7 +85,9 @@ export class VoiceInputView extends ItemView {
|
|||
}
|
||||
|
||||
onClose(): void {
|
||||
void this.handleClose();
|
||||
void this.handleClose().catch((error) => {
|
||||
console.error('Failed to close Voice Input view', error);
|
||||
});
|
||||
}
|
||||
|
||||
private async handleClose(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ export class VoiceInputViewActions {
|
|||
: 'max-duration';
|
||||
this.pendingVadAutoStop = false;
|
||||
this.updateUIAfterStop();
|
||||
void this.processRecordedAudio(audioBlob, { type: reasonType });
|
||||
this.processRecordedAudio(audioBlob, { type: reasonType });
|
||||
};
|
||||
|
||||
const handleMicrophoneStatusChange = (status: 'initializing' | 'ready' | 'error') => {
|
||||
|
|
@ -303,7 +303,7 @@ export class VoiceInputViewActions {
|
|||
|
||||
// Process audio for manual stop
|
||||
if (audioBlob && audioBlob.size > 0) {
|
||||
await this.processRecordedAudio(audioBlob, stopReason);
|
||||
this.processRecordedAudio(audioBlob, stopReason);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
|
|
@ -378,7 +378,7 @@ export class VoiceInputViewActions {
|
|||
/**
|
||||
* Process recorded audio with proper notifications
|
||||
*/
|
||||
private async processRecordedAudio(audioBlob: Blob, stopReason: StopReason): Promise<void> {
|
||||
private processRecordedAudio(audioBlob: Blob, stopReason: StopReason): void {
|
||||
// Show appropriate status based on stop reason
|
||||
if (this.view.ui.statusEl) {
|
||||
switch (stopReason.type) {
|
||||
|
|
@ -406,7 +406,9 @@ export class VoiceInputViewActions {
|
|||
|
||||
// Process queue if not already processing
|
||||
if (!this.isProcessingAudio) {
|
||||
void this.processQueue();
|
||||
void this.processQueue().catch((error) => {
|
||||
this.logger.error('Failed to process audio queue', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -452,7 +454,9 @@ export class VoiceInputViewActions {
|
|||
if (this.recordingState.processingQueue.length > 0) {
|
||||
// Use setTimeout to avoid potential stack overflow
|
||||
setTimeout(() => {
|
||||
void this.processQueue();
|
||||
void this.processQueue().catch((error) => {
|
||||
this.logger.error('Failed to continue processing audio queue', error);
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ export class VoiceInputViewUI {
|
|||
});
|
||||
this.clipboardButton.setAttribute('aria-label', this.i18n.t('ui.tooltips.copy'));
|
||||
this.clipboardButton.addEventListener('click', () => {
|
||||
void this.view.actions.copyToClipboard();
|
||||
this.runAction(() => this.view.actions.copyToClipboard(), 'Failed to copy text to clipboard');
|
||||
});
|
||||
|
||||
// Clear button
|
||||
|
|
@ -150,7 +150,7 @@ export class VoiceInputViewUI {
|
|||
});
|
||||
this.insertAtCursorButton.setAttribute('aria-label', this.i18n.t('ui.tooltips.insertAtCursor'));
|
||||
this.insertAtCursorButton.addEventListener('click', () => {
|
||||
void this.view.actions.insertToNote();
|
||||
this.runAction(() => this.view.actions.insertToNote(), 'Failed to insert text at cursor');
|
||||
});
|
||||
|
||||
// Append button
|
||||
|
|
@ -163,7 +163,7 @@ export class VoiceInputViewUI {
|
|||
});
|
||||
this.appendButton.setAttribute('aria-label', this.i18n.t('ui.tooltips.append'));
|
||||
this.appendButton.addEventListener('click', () => {
|
||||
void this.view.actions.appendToNote();
|
||||
this.runAction(() => this.view.actions.appendToNote(), 'Failed to append text to note');
|
||||
});
|
||||
|
||||
// Keep the old insertButton for backward compatibility (set to hidden)
|
||||
|
|
@ -178,7 +178,7 @@ export class VoiceInputViewUI {
|
|||
cls: 'voice-input-cancel-button-full voice-input-hidden'
|
||||
});
|
||||
this.cancelButton.addEventListener('click', () => {
|
||||
void this.view.actions.cancelRecording();
|
||||
this.runAction(() => this.view.actions.cancelRecording(), 'Failed to cancel recording');
|
||||
});
|
||||
|
||||
// Second row - Record button container
|
||||
|
|
@ -267,7 +267,7 @@ export class VoiceInputViewUI {
|
|||
return;
|
||||
}
|
||||
|
||||
void this.view.actions.toggleRecording();
|
||||
this.runAction(() => this.view.actions.toggleRecording(), 'Failed to toggle recording');
|
||||
};
|
||||
|
||||
// Push-to-talk functionality with delayed start
|
||||
|
|
@ -386,13 +386,15 @@ export class VoiceInputViewUI {
|
|||
*/
|
||||
updateSettingsUI() {
|
||||
// Update correction toggle
|
||||
if (this.correctionToggle) {
|
||||
this.correctionToggle.setValue(this.plugin.settings.enableTranscriptionCorrection);
|
||||
const correctionToggle = this.correctionToggle;
|
||||
if (correctionToggle) {
|
||||
correctionToggle.setValue(this.plugin.settings.enableTranscriptionCorrection);
|
||||
}
|
||||
|
||||
// Update transcription model dropdown
|
||||
if (this.transcriptionModelDropdown) {
|
||||
this.transcriptionModelDropdown.setValue(this.plugin.settings.transcriptionModel);
|
||||
const transcriptionModelDropdown = this.transcriptionModelDropdown;
|
||||
if (transcriptionModelDropdown) {
|
||||
transcriptionModelDropdown.setValue(this.plugin.settings.transcriptionModel);
|
||||
}
|
||||
|
||||
// (no additional post-processing UI elements to update)
|
||||
|
|
@ -416,6 +418,15 @@ export class VoiceInputViewUI {
|
|||
this.textArea.addEventListener('cut', this.textChangeHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to safely run async view actions without unhandled rejections
|
||||
*/
|
||||
private runAction(task: () => Promise<void>, context: string): void {
|
||||
void task().catch((error) => {
|
||||
console.error(context, error);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up resources
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue