anc
Простой путь: записать → расшифровать → получить результат
- Главная: «Записать» (или аудиофайл перетаскиванием) и записи со статусом.
Боковая панель и «Новая заметка» убраны.
- Экран записи: шаги «Аудио → Расшифровка → Результат», на экране только
текущий шаг и одна главная кнопка.
- Результаты вкладками: «Расшифровка», «Конспект», «Задачи», «Ревью»,
«Свой запрос»; копировать, как текст, править, сделать заново, удалить.
Повтор команды заменяет раздел, а не дописывает второй.
- Задача #9: без ключа кнопки ведут к подключению ИИ; у расшифровки и
ответа ИИ — прогресс и «Отменить» (CancellationToken в ядре); идущая
запись видна меткой в шапке на любом экране.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
e75bd24
30 сентября 2026 г.
state.ts
// Общее состояние интерфейса: идёт ли запись, есть ли ключ, короткие сообщения.
import { api, errorText, files, type RecordingView } from "./api";
type Listener = () => void;
const listeners = new Set<Listener>();
export const state = {
recording: null as RecordingView | null,
};
/** Файл, выбранный или перетащенный в окно, — новая запись. */
export async function addAudio(path: string | null): Promise<void> {
if (!path) return;
if (!files.isAudio(path)) {
toast("Это не аудиофайл — подойдут mp3, m4a, wav, aiff, flac, ogg");
return;
}
toast("Читаю файл…", "ok");
try {
const m = await api.addAudio(path);
location.hash = `#/m/${encodeURIComponent(m.id)}`;
} catch (e) {
toast(e);
}
}
export async function startRecording(): Promise<void> {
try {
const m = await api.recorderStart();
await refreshRecording();
location.hash = `#/m/${encodeURIComponent(m.id)}`;
} catch (e) {
toast(e);
}
}
export function onChange(cb: Listener): () => void {
listeners.add(cb);
return () => listeners.delete(cb);
}
export function changed(): void {
listeners.forEach((cb) => cb());
}
export async function refreshRecording(): Promise<void> {
state.recording = await api.recorderStatus();
changed();
}
/** Сообщение внизу экрана: ошибка или «Скопировано». Исчезает само. */
export function toast(message: unknown, kind: "error" | "ok" = "error"): void {
const el = document.getElementById("toast");
if (!el) return;
el.textContent = kind === "error" ? errorText(message) : String(message);
el.className = `toast is-${kind}`;
el.hidden = false;
window.clearTimeout(Number(el.dataset.timer));
el.dataset.timer = String(window.setTimeout(() => (el.hidden = true), kind === "error" ? 8000 : 2000));
}
export async function copy(text: string, what = "Скопировано"): Promise<void> {
try {
await navigator.clipboard.writeText(text);
toast(what, "ok");
} catch (e) {
toast(e);
}
}