v1.0.13 - botao de reset funcional para limpar as salas
This commit is contained in:
1 parent
611aec9ba1
commit
c8323d56cf
9 files changed
+1593
-532
No files matched your search
+192
-29
@@ -3,7 +3,7 @@
|
||||
// -------------------relómm------------------------------------------------------
|
||||
// IMPORTS & STATE
|
||||
// -----------------------------------------------------------------------------
|
||||
import { appState, resetProjectState } from "./state.js";
|
||||
import { appState, saveStateToSession } from "./state.js";
|
||||
import {
|
||||
addTrackToState,
|
||||
removeLastTrackFromState,
|
||||
@@ -33,7 +33,12 @@ import {
|
||||
restartAudioEditorIfPlaying, // 👈 Adicionado
|
||||
} from "./audio/audio_audio.js";
|
||||
|
||||
import { parseMmpContent } from "./file.js";
|
||||
import {
|
||||
parseMmpContent,
|
||||
handleLocalProjectReset,
|
||||
syncPatternStateToServer,
|
||||
BLANK_PROJECT_XML,
|
||||
} from "./file.js";
|
||||
import { renderAll, showToast } from "./ui.js"; // showToast()
|
||||
import { updateStepUI, renderPatternEditor } from "./pattern/pattern_ui.js";
|
||||
import { PORT_SOCK } from "./config.js";
|
||||
@@ -167,12 +172,14 @@ socket.on("connect_error", (err) => {
|
||||
|
||||
socket.on("system_update", (data) => {
|
||||
if (data.type === "RELOAD_SAMPLES") {
|
||||
console.log(`[System Update] Recebida ordem para recarregar samples: ${data.message}`);
|
||||
|
||||
console.log(
|
||||
`[System Update] Recebida ordem para recarregar samples: ${data.message}`
|
||||
);
|
||||
|
||||
// Certifique-se de que esta função existe e faz o que é esperado:
|
||||
// 1. Fetch dos novos manifestos (metadata/samples-manifest.json etc.)
|
||||
// 2. Renderiza a interface do navegador de samples
|
||||
loadAndRenderSampleBrowser();
|
||||
loadAndRenderSampleBrowser();
|
||||
}
|
||||
// Se houver outras notificações, adicione-as aqui (ex: RELOAD_PROJECTS)
|
||||
});
|
||||
@@ -186,14 +193,40 @@ socket.on("load_project_state", async (projectXml) => {
|
||||
if (isLoadingProject) return;
|
||||
isLoadingProject = true;
|
||||
try {
|
||||
await parseMmpContent(projectXml);
|
||||
await parseMmpContent(projectXml); //
|
||||
renderAll();
|
||||
showToast("🎵 Projeto carregado com sucesso", "success");
|
||||
|
||||
// --- INÍCIO DA CORREÇÃO ---
|
||||
// Mova a lógica de snapshot para AQUI.
|
||||
// Só peça um snapshot DEPOIS que o XML foi carregado
|
||||
// e SE o XML (appState) não tiver áudio.
|
||||
const hasAudio =
|
||||
(appState.audio?.clips?.length || 0) > 0 ||
|
||||
(appState.audio?.tracks?.length || 0) > 0;
|
||||
if (!hasAudio && currentRoom) {
|
||||
console.log(
|
||||
"Projeto XML carregado, sem áudio. Pedindo snapshot de áudio..."
|
||||
);
|
||||
// O 'sendAction' agora é chamado daqui, não do joinRoom.
|
||||
sendAction({ type: "AUDIO_SNAPSHOT_REQUEST" });
|
||||
}
|
||||
// --- FIM DA CORREÇÃO ---
|
||||
} catch (e) {
|
||||
console.error("Erro ao carregar projeto:", e);
|
||||
showToast("❌ Erro ao carregar projeto", "error");
|
||||
}
|
||||
isLoadingProject = false;
|
||||
// Desativa a flag de reset após um delay.
|
||||
// Isso dá tempo para a "condição de corrida" (o snapshot sujo)
|
||||
// ser recebida e ignorada.
|
||||
setTimeout(() => {
|
||||
if (appState.global.justReset) {
|
||||
console.log("Socket: Limpando flag 'justReset'.");
|
||||
appState.global.justReset = false;
|
||||
}
|
||||
}, 250); // 2.5 segundos de "janela de proteção"
|
||||
// --- FIM DA CORREÇÃO ---
|
||||
});
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -206,16 +239,6 @@ export function joinRoom() {
|
||||
console.log(`Entrando na sala: ${currentRoom} como ${USER_NAME}`);
|
||||
showToast(`🚪 Entrando na sala ${currentRoom}`, "info");
|
||||
socket.emit("join_room", { roomName: currentRoom, userName: USER_NAME });
|
||||
setTimeout(() => {
|
||||
try {
|
||||
const hasAudio =
|
||||
(appState.audio?.clips?.length || 0) > 0 ||
|
||||
(appState.audio?.tracks?.length || 0) > 0;
|
||||
if (!hasAudio && currentRoom) {
|
||||
sendAction({ type: "AUDIO_SNAPSHOT_REQUEST" });
|
||||
}
|
||||
} catch {}
|
||||
}, 800);
|
||||
} else {
|
||||
console.warn("joinRoom() chamado, mas nenhuma sala encontrada na URL.");
|
||||
showToast("⚠️ Nenhuma sala encontrada na URL", "warning");
|
||||
@@ -498,6 +521,7 @@ async function handleActionBroadcast(action) {
|
||||
const seekTime = action.seekTime ?? appState.audio.audioEditorSeekTime;
|
||||
setTimeout(() => startAudioEditorPlayback(seekTime), delayMs);
|
||||
break;
|
||||
|
||||
case "STOP_AUDIO_PLAYBACK":
|
||||
setTimeout(
|
||||
() => stopAudioEditorPlayback(action.rewind || false),
|
||||
@@ -564,6 +588,8 @@ async function handleActionBroadcast(action) {
|
||||
const modeText = newMode === "global" ? "Global 🌐" : "Local 🏠";
|
||||
showToast(`${who} mudou modo para ${modeText}`, "info");
|
||||
}
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
// =================================================================
|
||||
@@ -571,28 +597,80 @@ async function handleActionBroadcast(action) {
|
||||
// =================================================================
|
||||
|
||||
// Estado Global
|
||||
case "LOAD_PROJECT":
|
||||
case "LOAD_PROJECT": //
|
||||
isLoadingProject = true;
|
||||
showToast("📂 Carregando...", "info");
|
||||
|
||||
// Esta parte está CORRETA. Sempre limpa o sessionStorage.
|
||||
if (window.ROOM_NAME) {
|
||||
try {
|
||||
sessionStorage.removeItem(`temp_state_${window.ROOM_NAME}`);
|
||||
console.log(
|
||||
"Socket: Estado da sessão local limpo para LOAD_PROJECT."
|
||||
);
|
||||
} catch (e) {
|
||||
console.error("Socket: Falha ao limpar estado da sessão:", e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await parseMmpContent(action.xml);
|
||||
await parseMmpContent(action.xml); //
|
||||
renderAll();
|
||||
showToast("🎶 Projeto sync", "success");
|
||||
|
||||
// --- INÍCIO DA CORREÇÃO ---
|
||||
// O problema é esta chamada. Ela cria um "eco" (SYNC_PATTERN_STATE)
|
||||
// que força um segundo 'parseMmpContent' e quebra o estado.
|
||||
|
||||
// REMOVA ou COMENTE este bloco:
|
||||
/*
|
||||
if (window.ROOM_NAME) {
|
||||
console.log(
|
||||
"LOAD_PROJECT: Sincronizando novo estado com o servidor..."
|
||||
);
|
||||
syncPatternStateToServer(); //
|
||||
}
|
||||
*/
|
||||
|
||||
// EM VEZ DISSO, apenas salve o estado na sessão local.
|
||||
// O `syncPatternStateToServer` agora é responsabilidade do servidor
|
||||
// (que já recebeu o LOAD_PROJECT) ou de outras ações.
|
||||
saveStateToSession();
|
||||
// --- FIM DA CORREÇÃO ---
|
||||
} catch (e) {
|
||||
console.error("Erro LOAD_PROJECT:", e);
|
||||
showToast("❌ Erro projeto", "error");
|
||||
}
|
||||
isLoadingProject = false;
|
||||
break;
|
||||
case "RESET_PROJECT":
|
||||
resetProjectState();
|
||||
document.getElementById("bpm-input").value = 140;
|
||||
document.getElementById("bars-input").value = 1;
|
||||
document.getElementById("compasso-a-input").value = 4;
|
||||
document.getElementById("compasso-b-input").value = 4;
|
||||
renderAll();
|
||||
|
||||
case "SYNC_PATTERN_STATE": //
|
||||
// Esta ação agora só será recebida de *outros* usuários,
|
||||
// ou quando o servidor enviar, não de você mesmo.
|
||||
try {
|
||||
await parseMmpContent(action.xml); //
|
||||
renderAll();
|
||||
saveStateToSession(); //
|
||||
console.log("Socket: Pattern state sincronizado.");
|
||||
} catch (e) {
|
||||
console.error("Erro SYNC_PATTERN_STATE:", e);
|
||||
showToast("❌ Erro sync pattern", "error");
|
||||
}
|
||||
break;
|
||||
|
||||
case "RESET_ROOM":
|
||||
console.log("Socket: Recebendo comando de RESET_ROOM do servidor."); //
|
||||
|
||||
// --- INÍCIO DA CORREÇÃO ---
|
||||
// Faltava esta linha para definir quem executou a ação
|
||||
const who = actorOf(action);
|
||||
showToast(`🧹 Reset por ${who}`, "warning");
|
||||
// --- FIM DA CORREÇÃO ---
|
||||
|
||||
handleLocalProjectReset(); //
|
||||
showToast(`🧹 Reset por ${who}`, "warning"); //
|
||||
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession(); //
|
||||
break;
|
||||
|
||||
// Configs
|
||||
@@ -601,24 +679,35 @@ async function handleActionBroadcast(action) {
|
||||
renderAll();
|
||||
const who = actorOf(action);
|
||||
showToast(`🕰 ${who} BPM ${action.value}`, "info");
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
case "SET_BARS": {
|
||||
document.getElementById("bars-input").value = action.value;
|
||||
renderAll();
|
||||
const who = actorOf(action);
|
||||
showToast(`🕰 ${who} Compasso add`, "info");
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
case "SET_TIMESIG_A":
|
||||
document.getElementById("compasso-a-input").value = action.value;
|
||||
renderAll();
|
||||
showToast("Compasso alt", "info");
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
|
||||
case "SET_TIMESIG_B":
|
||||
document.getElementById("compasso-b-input").value = action.value;
|
||||
renderAll();
|
||||
showToast("Compasso alt", "info");
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
|
||||
// Tracks
|
||||
@@ -627,15 +716,21 @@ async function handleActionBroadcast(action) {
|
||||
renderPatternEditor();
|
||||
const who = actorOf(action);
|
||||
showToast(`🥁 Faixa add por ${who}`, "info");
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
case "REMOVE_LAST_TRACK": {
|
||||
removeLastTrackFromState();
|
||||
renderPatternEditor();
|
||||
const who = actorOf(action);
|
||||
showToast(`❌ Faixa remov. por ${who}`, "warning");
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
case "ADD_AUDIO_LANE": {
|
||||
const id = action.trackId;
|
||||
if (!id) {
|
||||
@@ -654,14 +749,19 @@ async function handleActionBroadcast(action) {
|
||||
renderAll();
|
||||
const who = actorOf(action);
|
||||
showToast(`🎧 Pista add por ${who}`, "info");
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
case "REMOVE_AUDIO_CLIP":
|
||||
if (removeAudioClip(action.clipId)) {
|
||||
appState.global.selectedClipId = null;
|
||||
renderAll();
|
||||
const who = actorOf(action);
|
||||
showToast(`🎚️ Clip remov. por ${who}`, "info");
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -687,6 +787,8 @@ async function handleActionBroadcast(action) {
|
||||
const who = actorOf(action);
|
||||
const v = isActive ? "+" : "-";
|
||||
showToast(`🎯 ${who} ${v} nota ${ti + 1}.${pi + 1}.${si + 1}`, "info");
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -707,6 +809,35 @@ async function handleActionBroadcast(action) {
|
||||
showToast("❌ Erro sample", "error");
|
||||
}
|
||||
}
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
case "SET_ACTIVE_PATTERN": {
|
||||
// índice que veio do seletor global
|
||||
const { patternIndex } = action;
|
||||
|
||||
// O correto é iterar em TODAS as tracks e definir o
|
||||
// novo índice de pattern para CADA UMA delas.
|
||||
appState.pattern.tracks.forEach((track) => {
|
||||
track.activePatternIndex = patternIndex;
|
||||
});
|
||||
|
||||
// Mostra o toast (só uma vez)
|
||||
if (!isFromSelf) {
|
||||
const who = actorOf(action);
|
||||
showToast(`🔄 ${who} mudou para Pattern ${patternIndex + 1}`, "info");
|
||||
}
|
||||
|
||||
// O renderAll() vai redesenhar tudo.
|
||||
// O redrawSequencer() (que é chamado pelo renderAll)
|
||||
// vai ler o 'track.activePatternIndex' (agora atualizado)
|
||||
// para TODAS as tracks e desenhar o pattern correto.
|
||||
renderAll();
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -730,10 +861,17 @@ async function handleActionBroadcast(action) {
|
||||
} catch (e) {
|
||||
console.warn("Erro AUDIO_SNAPSHOT_REQUEST:", e);
|
||||
}
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
case "AUDIO_SNAPSHOT": {
|
||||
if (action.__target && action.__target !== socket.id) break;
|
||||
if (appState.global.justReset) {
|
||||
console.warn("Socket: Snapshot de áudio ignorado (justReset=true).");
|
||||
break; // Ignora o snapshot
|
||||
}
|
||||
const hasClips = (appState.audio?.clips?.length || 0) > 0;
|
||||
if (hasClips) break;
|
||||
try {
|
||||
@@ -745,13 +883,26 @@ async function handleActionBroadcast(action) {
|
||||
console.error("Erro AUDIO_SNAPSHOT:", e);
|
||||
showToast("❌ Erro sync áudio", "error");
|
||||
}
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
// Clip Sync
|
||||
case "ADD_AUDIO_CLIP": {
|
||||
try {
|
||||
const { filePath, trackId, startTimeInSeconds, clipId, name } = action;
|
||||
// --- INÍCIO DA MODIFICAÇÃO (Passo 2) ---
|
||||
// Agora extraímos o 'patternData' que o main.js enviou.
|
||||
const {
|
||||
filePath,
|
||||
trackId,
|
||||
startTimeInSeconds,
|
||||
clipId,
|
||||
name,
|
||||
patternData,
|
||||
} = action;
|
||||
// --- FIM DA MODIFICAÇÃO ---
|
||||
|
||||
if (
|
||||
appState.audio?.clips?.some((c) => String(c.id) === String(clipId))
|
||||
) {
|
||||
@@ -769,13 +920,20 @@ async function handleActionBroadcast(action) {
|
||||
name: `Pista ${appState.audio.tracks.length + 1}`,
|
||||
});
|
||||
}
|
||||
|
||||
// --- INÍCIO DA MODIFICAÇÃO (Passo 2) ---
|
||||
// Passamos o 'patternData' como o novo (sexto) argumento
|
||||
// para a função que armazena o clipe no estado.
|
||||
addAudioClipToTimeline(
|
||||
filePath,
|
||||
trackId,
|
||||
startTimeInSeconds,
|
||||
clipId,
|
||||
name
|
||||
name,
|
||||
patternData // <-- AQUI ESTÁ A "PARTITURA"
|
||||
);
|
||||
// --- FIM DA MODIFICAÇÃO ---
|
||||
|
||||
renderAll();
|
||||
const who = actorOf(action);
|
||||
const track = appState.audio?.tracks?.find((t) => t.id === trackId);
|
||||
@@ -790,8 +948,11 @@ async function handleActionBroadcast(action) {
|
||||
console.error("Erro ADD_AUDIO_CLIP:", e);
|
||||
showToast("❌ Erro add clip", "error");
|
||||
}
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
case "UPDATE_AUDIO_CLIP": {
|
||||
try {
|
||||
if (action.props?.__operation === "slice") {
|
||||
@@ -806,6 +967,8 @@ async function handleActionBroadcast(action) {
|
||||
console.error("Erro UPDATE_AUDIO_CLIP:", e);
|
||||
showToast("❌ Erro att clip", "error");
|
||||
}
|
||||
// Salva o estado localmente também!
|
||||
saveStateToSession();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -815,4 +978,4 @@ async function handleActionBroadcast(action) {
|
||||
}
|
||||
|
||||
// EXPORTS
|
||||
export { socket };
|
||||
export { socket };
|
||||
Reference in new issue
Block a user