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 и сессии) из параллельной волны: файл коммитится целиком по договорённости с координатором.
95 lines
5.0 KiB
Rust
95 lines
5.0 KiB
Rust
//! Настройки desktop-обёртки.
|
|
//!
|
|
//! Лежат в `tauri-plugin-store` (`settings.json` в каталоге конфигурации
|
|
//! приложения). Обёртка хранит только то, что относится к платформе: адрес
|
|
//! инстанса и переключатели поведения. Сессия целиком живёт в cookie webview
|
|
//! (docs/client-tauri.md §2): токенов и паролей здесь нет.
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
use tauri::{AppHandle, Runtime};
|
|
use tauri_plugin_store::StoreExt;
|
|
|
|
/// Файл хранилища в каталоге конфигурации приложения.
|
|
const STORE_FILE: &str = "settings.json";
|
|
/// Ключ, под которым лежит объект настроек.
|
|
const STORE_KEY: &str = "settings";
|
|
|
|
/// Адрес стенда по умолчанию: тот же клиент, что открывается в браузере.
|
|
pub const DEFAULT_INSTANCE: &str = "https://gl.mhspx.su";
|
|
|
|
/// Комбинация push-to-talk по умолчанию.
|
|
///
|
|
/// Голых клавиш (как `V` в браузерном PTT) в глобальном шорткате быть не может:
|
|
/// системный перехват занял бы клавишу у всех приложений, поэтому по умолчанию
|
|
/// комбинация с модификаторами, а пустая строка означает «выключено».
|
|
pub const DEFAULT_PTT_SHORTCUT: &str = "CommandOrControl+Shift+Space";
|
|
|
|
/// Комбинация «выключить/включить микрофон» по умолчанию.
|
|
pub const DEFAULT_MUTE_SHORTCUT: &str = "CommandOrControl+Shift+M";
|
|
|
|
/// Комбинация «не слышу» (deafen) по умолчанию.
|
|
pub const DEFAULT_DEAFEN_SHORTCUT: &str = "CommandOrControl+Shift+D";
|
|
|
|
/// Настройки обёртки. Поля в camelCase — их читает и пишет страница настроек.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(default, rename_all = "camelCase")]
|
|
pub struct Settings {
|
|
/// Адрес инстанса, который загружается в главное окно.
|
|
pub instance_url: String,
|
|
/// Закрытие окна сворачивает приложение в трей.
|
|
pub close_to_tray: bool,
|
|
/// Запускать приложение при входе в систему (свёрнутым в трей).
|
|
pub autostart: bool,
|
|
/// Пользователю уже задавали вопрос про автозапуск при первом запуске.
|
|
pub autostart_prompted: bool,
|
|
/// Глобальный push-to-talk (пустая строка — выключен).
|
|
pub ptt_shortcut: String,
|
|
/// Глобальное переключение микрофона (пустая строка — выключено).
|
|
pub mute_shortcut: String,
|
|
/// Глобальное переключение «не слышу» (пустая строка — выключено).
|
|
pub deafen_shortcut: String,
|
|
/// Показывать нативные уведомления об упоминаниях и личных сообщениях.
|
|
pub notifications: bool,
|
|
}
|
|
|
|
impl Default for Settings {
|
|
fn default() -> Self {
|
|
Self {
|
|
instance_url: DEFAULT_INSTANCE.to_string(),
|
|
close_to_tray: true,
|
|
autostart: false,
|
|
autostart_prompted: false,
|
|
ptt_shortcut: DEFAULT_PTT_SHORTCUT.to_string(),
|
|
mute_shortcut: DEFAULT_MUTE_SHORTCUT.to_string(),
|
|
deafen_shortcut: DEFAULT_DEAFEN_SHORTCUT.to_string(),
|
|
notifications: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Читает настройки из хранилища; при отсутствии или порче — значения по умолчанию.
|
|
pub fn load<R: Runtime>(app: &AppHandle<R>) -> Settings {
|
|
let Ok(store) = app.store(STORE_FILE) else {
|
|
log::warn!("не удалось открыть хранилище настроек, используются значения по умолчанию");
|
|
return Settings::default();
|
|
};
|
|
let Some(value) = store.get(STORE_KEY) else {
|
|
return Settings::default();
|
|
};
|
|
match serde_json::from_value::<Settings>(value) {
|
|
Ok(settings) => settings,
|
|
Err(error) => {
|
|
log::warn!("настройки в хранилище повреждены ({error}), берём значения по умолчанию");
|
|
Settings::default()
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Сохраняет настройки в хранилище.
|
|
pub fn save<R: Runtime>(app: &AppHandle<R>, settings: &Settings) -> Result<(), String> {
|
|
let store = app.store(STORE_FILE).map_err(|error| error.to_string())?;
|
|
let value = serde_json::to_value(settings).map_err(|error| error.to_string())?;
|
|
store.set(STORE_KEY, value);
|
|
store.save().map_err(|error| error.to_string())
|
|
}
|