Skip to content

Commit 0fb3c77

Browse files
committed
fix(voice): 收敛语音设置弹窗生命周期
1 parent a303038 commit 0fb3c77

2 files changed

Lines changed: 379 additions & 8 deletions

File tree

static/app/app-audio-capture.js

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,6 +1584,7 @@
15841584
var micPermissionGranted = false;
15851585
var cachedMicDevices = null;
15861586
var disposeVoiceRecognitionPopover = null;
1587+
var voiceRecognitionPopoverRenderGeneration = 0;
15871588

15881589
/** 请求麦克风权限并缓存设备列表 */
15891590
async function ensureMicrophonePermission() {
@@ -1632,9 +1633,11 @@
16321633
window.renderFloatingMicList = async function (popupArg) {
16331634
var micPopup = popupArg || document.getElementById('live2d-popup-mic') || document.getElementById('vrm-popup-mic') || document.getElementById('mmd-popup-mic');
16341635
if (!micPopup) return false;
1636+
var renderGeneration = ++voiceRecognitionPopoverRenderGeneration;
16351637
if (disposeVoiceRecognitionPopover) {
1636-
disposeVoiceRecognitionPopover();
1638+
var previousDispose = disposeVoiceRecognitionPopover;
16371639
disposeVoiceRecognitionPopover = null;
1640+
previousDispose();
16381641
}
16391642
var popupId = micPopup.id;
16401643
var isPopupAvailable = function () {
@@ -1646,7 +1649,10 @@
16461649

16471650
try {
16481651
var audioInputs = await ensureMicrophonePermission();
1649-
if (!isPopupAvailable()) return false;
1652+
if (
1653+
renderGeneration !== voiceRecognitionPopoverRenderGeneration
1654+
|| !isPopupAvailable()
1655+
) return false;
16501656
micPopup.innerHTML = '';
16511657

16521658
var hasMicrophoneDevices = audioInputs.length > 0;
@@ -1931,12 +1937,17 @@
19311937
};
19321938
}
19331939

1934-
var voiceSettingsPending = false;
1940+
var voiceSettingsPendingUntilEpoch = null;
1941+
function markVoiceSettingsPending() {
1942+
voiceSettingsPendingUntilEpoch = (
1943+
Number(S.voiceSessionStartEpoch) || 0
1944+
) + 1;
1945+
}
19351946
var asrToggle = createVoiceSettingToggle(
19361947
S.independentAsrEnabled === true,
19371948
function (enabled) {
19381949
S.independentAsrEnabled = enabled;
1939-
voiceSettingsPending = true;
1950+
markVoiceSettingsPending();
19401951
updateVoiceRecognitionUi();
19411952
if (window.appSettings && typeof window.appSettings.saveSettings === 'function') {
19421953
window.appSettings.saveSettings();
@@ -2004,7 +2015,7 @@
20042015
S.voiceInputResourceOptimizationEnabled !== false,
20052016
function (enabled) {
20062017
S.voiceInputResourceOptimizationEnabled = enabled;
2007-
voiceSettingsPending = true;
2018+
markVoiceSettingsPending();
20082019
updateVoiceRecognitionUi();
20092020
if (window.appSettings && typeof window.appSettings.saveSettings === 'function') {
20102021
window.appSettings.saveSettings();
@@ -2045,7 +2056,7 @@
20452056
: 'microphone.independentAsrSummaryGeneric', { provider: provider })
20462057
: ('独立 ASR' + (provider ? ' · ' + provider : '')))
20472058
: (window.t ? window.t('microphone.voiceRecognitionDisabled') : '当前使用 Omni 原生语音识别');
2048-
if (voiceSettingsPending) {
2059+
if (voiceSettingsPendingUntilEpoch !== null) {
20492060
voiceStatus.textContent = window.t
20502061
? window.t('microphone.voiceRecognitionSettingsPending')
20512062
: '◐ 设置将在下次语音会话生效';
@@ -2184,26 +2195,45 @@
21842195
}
21852196
}
21862197
function onVoiceLifecycleChanged() { updateVoiceRecognitionUi(); }
2198+
function onVoiceSessionStarted() {
2199+
if (
2200+
voiceSettingsPendingUntilEpoch === null
2201+
|| (Number(S.voiceSessionStartEpoch) || 0)
2202+
< voiceSettingsPendingUntilEpoch
2203+
) return;
2204+
voiceSettingsPendingUntilEpoch = null;
2205+
updateVoiceRecognitionUi();
2206+
}
21872207
document.addEventListener('pointerdown', onVoiceDocumentPointerDown, true);
21882208
document.addEventListener('keydown', onVoiceDocumentKeyDown, true);
21892209
window.addEventListener('resize', positionVoicePanel);
21902210
window.addEventListener('scroll', positionVoicePanel, true);
21912211
window.addEventListener('voice-input-lifecycle-changed', onVoiceLifecycleChanged);
2212+
window.addEventListener('neko:voice-session-started', onVoiceSessionStarted);
21922213
var voicePopupObserver = new MutationObserver(function () {
21932214
if (!isPopupAvailable()) closeVoicePanel(true);
21942215
});
21952216
voicePopupObserver.observe(micPopup, { attributes: true, attributeFilter: ['style', 'class'] });
2196-
disposeVoiceRecognitionPopover = function () {
2217+
var voicePopoverDisposed = false;
2218+
function disposeCurrentVoiceRecognitionPopover() {
2219+
if (voicePopoverDisposed) return;
2220+
voicePopoverDisposed = true;
21972221
clearVoiceTimers();
21982222
voicePopupObserver.disconnect();
21992223
document.removeEventListener('pointerdown', onVoiceDocumentPointerDown, true);
22002224
document.removeEventListener('keydown', onVoiceDocumentKeyDown, true);
22012225
window.removeEventListener('resize', positionVoicePanel);
22022226
window.removeEventListener('scroll', positionVoicePanel, true);
22032227
window.removeEventListener('voice-input-lifecycle-changed', onVoiceLifecycleChanged);
2228+
window.removeEventListener('neko:voice-session-started', onVoiceSessionStarted);
22042229
voicePanel.remove();
22052230
voiceBridge.remove();
2206-
};
2231+
if (
2232+
disposeVoiceRecognitionPopover
2233+
=== disposeCurrentVoiceRecognitionPopover
2234+
) disposeVoiceRecognitionPopover = null;
2235+
}
2236+
disposeVoiceRecognitionPopover = disposeCurrentVoiceRecognitionPopover;
22072237

22082238
var sep1b = document.createElement('div');
22092239
Object.assign(sep1b.style, { height: '1px', backgroundColor: 'var(--neko-popup-separator)', margin: '8px 0' });

0 commit comments

Comments
 (0)