feat(desktop): переход в комнату по уведомлению, выход без потери правок, Ctrl/Cmd+K
Три пункта спецификации клиента (docs/client-tauri.md §5), которые оставались открытыми в обёртке: - **Клик по уведомлению → переход в канал.** У `tauri-plugin-notification` на desktop нет колбэка действия, поэтому реализовано лучшее доступное поведение: уведомление, показанное при неактивном окне, запоминается, и когда приложение активируется в течение 10 секунд (окно получило фокус или macOS прислала `RunEvent::Reopen`), окно поднимается и открывается комната из уведомления — `glchat://guild/<id>/channel/<id>`, для личной беседы `glchat://dm/<id>`. Идентификаторы проверяются (только цифры), чтобы из текста уведомления нельзя было собрать произвольный deep link. Ограничение: ОС не сообщает, что активация вызвана именно кликом, поэтому переход сработает и при обычном возврате в приложение в эти 10 секунд — это описано в desktop/README.md; - **Выход при несохранённых изменениях.** Клиент сообщает о правках командой `desktop_set_dirty`; закрытие окна и пункт «Выход» в трее перехватываются (`window::request_close_confirmation`), окно best-effort покачивается (`Window::set_position`, на Wayland молча пропускается), а решение принимает пользователь в диалоге клиента «Сохранить / Выйти без сохранения»; закрывает приложение команда `desktop_close_window`. Раньше выход из трея терял правки молча; - **Ctrl/Cmd+K.** Комбинация регистрируется глобально (`shortcuts.rs`) и при неактивном окне поднимает окно и просит клиент открыть палитру команд (`WebMessage::OpenPalette`); повторы комбинаций с настраиваемыми шорткатами отсекаются по разобранной комбинации, иначе вторая регистрация падала бы. Заодно: `updates.rs` получил тест, который разбирает манифест релиза типом самого `tauri-plugin-updater` (`RemoteRelease`) — он ловит расхождение формата (например, дату не в RFC 3339), из-за которого обновление молча не приходило бы. Проверки: `make desktop-check` (fmt, clippy, 10 тестов).
This commit is contained in:
@@ -157,3 +157,64 @@ async fn prompt_install<R: Runtime>(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// Манифест ровно в том виде, в каком его раскладывает
|
||||
/// `scripts/desktop-release.sh` (проверяется вместе с серверной частью:
|
||||
/// internal/server/updates.go).
|
||||
const MANIFEST: &str = r#"{
|
||||
"version": "0.2.0",
|
||||
"notes": "Релиз glchat 0.2.0",
|
||||
"pub_date": "2026-09-22T12:00:00Z",
|
||||
"platforms": {
|
||||
"darwin-aarch64": {
|
||||
"signature": "dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZQo=",
|
||||
"url": "https://gl.mhspx.su/updates/darwin/aarch64/glchat.app.tar.gz"
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
|
||||
/// Разбор манифеста идёт тем же типом, что использует плагин обновлений:
|
||||
/// тест ловит расхождение формата (например, дату не в RFC 3339), из-за
|
||||
/// которого обновление молча не приходило бы.
|
||||
#[test]
|
||||
fn манифест_разбирается_плагином_обновлений() {
|
||||
let release: tauri_plugin_updater::RemoteRelease =
|
||||
serde_json::from_str(MANIFEST).expect("манифест должен разбираться плагином");
|
||||
assert_eq!(release.version.to_string(), "0.2.0");
|
||||
assert!(release.pub_date.is_some(), "дата публикации не разобрана");
|
||||
assert_eq!(
|
||||
release
|
||||
.download_url("darwin-aarch64")
|
||||
.expect("ссылка на артефакт")
|
||||
.as_str(),
|
||||
"https://gl.mhspx.su/updates/darwin/aarch64/glchat.app.tar.gz"
|
||||
);
|
||||
assert_eq!(
|
||||
release
|
||||
.signature("darwin-aarch64")
|
||||
.expect("подпись платформы"),
|
||||
"dW50cnVzdGVkIGNvbW1lbnQ6IHNpZ25hdHVyZQo="
|
||||
);
|
||||
// Другая платформа в манифесте отсутствует — плагин сообщит об этом.
|
||||
assert!(release.signature("windows-x86_64").is_err());
|
||||
}
|
||||
|
||||
/// Адрес манифеста собирается по адресу инстанса и не содержит двойных слэшей.
|
||||
#[test]
|
||||
fn адрес_манифеста_собирается_из_адреса_инстанса() {
|
||||
let url = instance::normalize("https://gl.mhspx.su/").expect("адрес инстанса");
|
||||
let endpoint = format!("{}{UPDATE_PATH}", instance::display(&url));
|
||||
assert_eq!(
|
||||
endpoint,
|
||||
"https://gl.mhspx.su/updates/{{target}}/{{arch}}/{{current_version}}"
|
||||
);
|
||||
assert!(
|
||||
!UPDATER_PUBKEY.is_empty(),
|
||||
"публичный ключ подписи должен быть вшит в сборку"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user