Files
glchat/desktop/src-tauri/src/settings.rs
T

95 lines
5.0 KiB
Rust
Raw Normal View History

//! Настройки 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())
}