cffcec72b8
Первый инкремент Фазы 6 (docs/client-tauri.md): окно с тем же веб-клиентом (по умолчанию https://gl.mhspx.su, адрес настраивается), трей с меню и индикатором непрочитанных, нативные уведомления, глобальный push-to-talk и переключение микрофона/deafen, автозапуск, single-instance, сохранение геометрии окна, deep links glchat://…, автообновление по подписанному манифесту. Связь страницы с обёрткой — через платформенный адаптер (web/src/lib/platform.ts) и минимальный типизированный набор команд; в веб-клиенте появились системные уведомления об упоминаниях и личных сообщениях и переключатель в настройках. В web/src/stores/gateway.ts вместе с вызовом уведомления лежат правки по дефектам realtime (READY и сессии) из параллельной волны: файл коммитится целиком по договорённости с координатором.
69 lines
3.3 KiB
Rust
69 lines
3.3 KiB
Rust
//! Мост «Rust → веб-клиент».
|
||
//!
|
||
//! Обратное направление (страница → обёртка) идёт через типизированные команды
|
||
//! (`commands.rs`), а события платформы передаются вызовом единственной функции
|
||
//! `window.__glchatDesktop.receive(...)` в самой странице. Отдельного канала
|
||
//! событий нет намеренно: сообщений мало, а типы у них общие с `web/src/lib/platform.ts`.
|
||
|
||
use serde::Serialize;
|
||
use tauri::{AppHandle, Manager, Runtime};
|
||
|
||
use crate::settings::Settings;
|
||
use crate::state::AppState;
|
||
|
||
/// Метка главного окна (единственное окно приложения).
|
||
pub const WEB_WINDOW: &str = "main";
|
||
|
||
/// Сообщение веб-клиенту: то, что платформа сообщает странице.
|
||
#[derive(Debug, Clone, Serialize)]
|
||
#[serde(tag = "type", rename_all = "camelCase")]
|
||
pub enum WebMessage {
|
||
/// Нажат или отпущен глобальный push-to-talk.
|
||
Ptt { active: bool },
|
||
/// Переключить микрофон (глобальный шорткат).
|
||
ToggleMic,
|
||
/// Переключить «не слышу» (глобальный шорткат).
|
||
ToggleDeafen,
|
||
/// Открыть deep link: приглашение или сервер с комнатой.
|
||
DeepLink { url: String },
|
||
/// Настройки обёртки изменились (обновлена страница настроек).
|
||
Settings { settings: Settings },
|
||
/// Доступно обновление — клиент показывает уведомление в интерфейсе.
|
||
UpdateAvailable { version: String },
|
||
}
|
||
|
||
/// Отправляет сообщение в веб-клиент.
|
||
///
|
||
/// Если клиент ещё не загрузился, deep link ставится в очередь и будет отдан
|
||
/// после `desktop_ready` (docs/client-tauri.md §5). Остальные сообщения в этот
|
||
/// момент терять не страшно: они относятся к активному взаимодействию.
|
||
pub fn send<R: Runtime>(app: &AppHandle<R>, message: &WebMessage) -> bool {
|
||
let state = app.state::<AppState>();
|
||
if !state.web_ready() {
|
||
if let WebMessage::DeepLink { url } = message {
|
||
state.push_deep_link(url.clone());
|
||
}
|
||
return false;
|
||
}
|
||
dispatch(app, message)
|
||
}
|
||
|
||
/// Немедленная доставка без проверки готовности клиента.
|
||
pub fn dispatch<R: Runtime>(app: &AppHandle<R>, message: &WebMessage) -> bool {
|
||
let Some(window) = app.get_webview_window(WEB_WINDOW) else {
|
||
return false;
|
||
};
|
||
let Ok(payload) = serde_json::to_string(message) else {
|
||
log::warn!("не удалось сериализовать сообщение веб-клиенту");
|
||
return false;
|
||
};
|
||
let script = format!("window.__glchatDesktop && window.__glchatDesktop.receive({payload});");
|
||
match window.eval(&script) {
|
||
Ok(()) => true,
|
||
Err(error) => {
|
||
log::debug!("веб-клиент не принял сообщение: {error}");
|
||
false
|
||
}
|
||
}
|
||
}
|