- 托盘菜单加 4 项:New messages: N(灰)/ Pause notifications(勾选态)/ Settings.../ Restart connection - 单实例:第二次启动通过 RegisterWindowMessageW 发激活请求,托盘 WndProc 收后调用 on_open(show+reset counter);main.rs AlreadyRunning 路径调用 activate_existing_instance - AppConfig 加 notifications_paused 字段(与 desktop_notifications 区分,tray 暂停持久化) - WS drain 通过 Rc<RefCell<Option<Arc<TrayState>>>> 与托盘共享 new_messages 计数器 - WndProc 在调用 on_open 前自己清零计数器,免去回调侧的 RefCell 捕获(保持 Send+Sync)
68 lines
2.4 KiB
Rust
68 lines
2.4 KiB
Rust
//! Active-config view used at runtime.
|
|
//!
|
|
//! Phase 5 C1: this is a thin wrapper over `storage::AppConfig`. It
|
|
//! surfaces the single selected server as `ServerConfig` so the rest
|
|
//! of the runtime (`gotify::GotifyApi`, `gotify::websocket`) doesn't
|
|
//! have to care about the multi-server storage layout. The placeholder
|
|
//! URL/token that lived here in Phase 3 C2 is gone — first-run users
|
|
//! will see "no server configured" until they fill in Settings
|
|
//! (Phase 6 hooks up the Settings → Connection form).
|
|
|
|
use crate::error::AppResult;
|
|
use crate::gotify::ServerConfig;
|
|
use crate::storage::AppConfig as PersistedConfig;
|
|
|
|
pub struct ActiveConfig {
|
|
pub server: Option<ServerConfig>,
|
|
pub appearance: String,
|
|
pub desktop_notifications: bool,
|
|
pub sound: bool,
|
|
pub notify_high: bool,
|
|
pub notify_max: bool,
|
|
pub notifications_paused: bool,
|
|
pub start_with_windows: bool,
|
|
pub start_minimized: bool,
|
|
pub close_to_tray: bool,
|
|
}
|
|
|
|
impl ActiveConfig {
|
|
/// Load from `%APPDATA%/WindowsGotify/config.json` (or defaults on
|
|
/// missing / malformed file). Returns `Ok(ActiveConfig)` even when
|
|
/// there's no server configured — the caller decides how to
|
|
/// surface that in the UI.
|
|
pub fn load() -> AppResult<Self> {
|
|
let persisted = crate::storage::load_config();
|
|
Ok(Self::from_persisted(persisted))
|
|
}
|
|
|
|
fn from_persisted(p: PersistedConfig) -> Self {
|
|
let server = p
|
|
.active_server()
|
|
.or_else(|| p.first_enabled_server())
|
|
.map(|entry| entry.config.clone());
|
|
Self {
|
|
server,
|
|
appearance: p.appearance,
|
|
desktop_notifications: p.desktop_notifications,
|
|
sound: p.sound,
|
|
notify_high: p.notify_high,
|
|
notify_max: p.notify_max,
|
|
notifications_paused: p.notifications_paused,
|
|
start_with_windows: p.start_with_windows,
|
|
start_minimized: p.start_minimized,
|
|
close_to_tray: p.close_to_tray,
|
|
}
|
|
}
|
|
|
|
/// Build an `ActiveConfig` from a fully-formed `PersistedConfig`
|
|
/// value (handy for tests and for the upcoming Settings → Save
|
|
/// path, which constructs the persisted config in memory and then
|
|
/// asks us to mirror it back).
|
|
pub fn from_persisted_value(p: PersistedConfig) -> Self {
|
|
Self::from_persisted(p)
|
|
}
|
|
|
|
pub fn placeholder() -> Self {
|
|
Self::from_persisted(PersistedConfig::default())
|
|
}
|
|
} |