enhance lesson generation and focus mode functionality

This commit is contained in:
ImBenji
2026-04-28 01:37:42 +01:00
parent 507bc15dcc
commit 5a4caaf1d0
2 changed files with 47 additions and 6 deletions
+34 -5
View File
@@ -529,6 +529,7 @@ const focusMode = ref(false);
const currentChunk = ref<{ text: string; start: number; end: number } | null>(null);
const karaokeAudioEl = ref<HTMLAudioElement | null>(null);
const questionPlaying = ref(false);
const focusEverActivated = ref(false);
if (import.meta.client) {
const stored = localStorage.getItem("revisione-focus-mode");
@@ -543,8 +544,10 @@ const hasAudio = computed(() => {
const showKaraoke = computed(() => {
if (!focusMode.value) return false;
const ds = displayStep.value;
return (lessonState.mode === "main" || lessonState.mode === "branch") &&
(ds?.type === "concept" || ds?.type === "example");
if (!((lessonState.mode === "main" || lessonState.mode === "branch") &&
(ds?.type === "concept" || ds?.type === "example"))) return false;
// dont show overlay if this step has no audio — avoids perma-"..." with missing TTS
return !!(ds?.audioPath && ds?.audioChunks && (ds.audioChunks as any[]).length > 0);
});
const showQuestionOverlay = computed(() =>
@@ -554,10 +557,24 @@ const showQuestionOverlay = computed(() =>
questionPlaying.value
);
function toggleFocusMode() {
async function toggleFocusMode() {
focusMode.value = !focusMode.value;
if (import.meta.client) localStorage.setItem("revisione-focus-mode", String(focusMode.value));
if (focusMode.value) {
// on first activation, re-fetch lesson so we have the latest audio paths from the DB
if (!focusEverActivated.value) {
focusEverActivated.value = true;
try {
const fresh = await $fetch<any>(`/api/topics/${topicId}/lesson`);
lesson.value = fresh;
const s0 = fresh?.content?.steps?.[0];
console.log("[focus] step 0 audioPath:", s0?.audioPath, "| chunks:", s0?.audioChunks?.length ?? "none");
} catch (e) {
console.warn("[focus] re-fetch failed, using cached lesson data", e);
}
}
nextTick(() => startStepAudio());
} else {
stopAllAudio();
@@ -686,7 +703,16 @@ function startStepAudio() {
if (!s) return;
if (s.type === "concept" || s.type === "example" || s.type === "summary") {
if (!s.audioPath || !s.audioChunks) return;
if (!s.audioPath || !s.audioChunks || (s.audioChunks as any[]).length === 0) {
// no usable audio for this step — skip it automatically so focus mode stays alive
if (!isLastMainStep.value) {
lessonState.stepIndex++;
nextTick(() => startStepAudio());
} else {
completeLesson();
}
return;
}
const audio = karaokeAudioEl.value;
if (!audio) return;
audio.src = s.audioPath;
@@ -705,7 +731,10 @@ function startStepAudio() {
}
} else if (lessonState.mode === "branch") {
const bs = currentBranchStep.value;
if (!bs?.audioPath || !bs.audioChunks) return;
if (!bs?.audioPath || !bs.audioChunks || (bs.audioChunks as any[]).length === 0) {
advanceBranchStep();
return;
}
const audio = karaokeAudioEl.value;
if (!audio) return;
audio.src = bs.audioPath;