Merge fix/remember-window-size: persist + restore window size
This commit is contained in:
+32
-11
@@ -250,13 +250,15 @@ impl Default for AppState {
|
||||
let _ = UI_RX.set(Mutex::new(Some(ui_rx)));
|
||||
|
||||
let mut config = AppConfig::load();
|
||||
// A persisted divider size from a differently-sized window could be out of
|
||||
// range for the default window — clamp it before first render.
|
||||
// The window opens at the restored size (see `run_gui`); clamp the
|
||||
// persisted divider positions against THAT size, not a hardcoded default,
|
||||
// so they stay valid for the window we're actually about to show.
|
||||
let (ww, wh) = (config.window_width, config.window_height);
|
||||
config.participants_width =
|
||||
clamp_participants_width(config.participants_width, 900.0);
|
||||
config.chat_height = clamp_chat_height(config.chat_height, 760.0);
|
||||
config.controls_width = clamp_controls_width(config.controls_width, 900.0);
|
||||
config.chat_drawer_width = clamp_chat_drawer_width(config.chat_drawer_width, 900.0);
|
||||
clamp_participants_width(config.participants_width, ww);
|
||||
config.chat_height = clamp_chat_height(config.chat_height, wh);
|
||||
config.controls_width = clamp_controls_width(config.controls_width, ww);
|
||||
config.chat_drawer_width = clamp_chat_drawer_width(config.chat_drawer_width, ww);
|
||||
notify::set_enabled(config.notifications_enabled);
|
||||
let _ = controller.send(CoreCommand::SetNoiseGateThreshold(config.noise_gate_threshold));
|
||||
let _ = controller.send(CoreCommand::SetInputVolume(config.input_volume));
|
||||
@@ -300,7 +302,7 @@ impl Default for AppState {
|
||||
recording_started: None,
|
||||
chat_messages: Vec::new(),
|
||||
chat_input: String::new(),
|
||||
window_size: Size::new(900.0, 760.0),
|
||||
window_size: Size::new(ww, wh),
|
||||
layout_picker_open: false,
|
||||
drawer_chat_open: false,
|
||||
mic_level: 0.0,
|
||||
@@ -320,16 +322,22 @@ fn theme(_state: &AppState) -> Theme {
|
||||
}
|
||||
|
||||
pub fn run_gui() -> iced::Result {
|
||||
// Restore the last window size (saved on close). Position can't be restored on
|
||||
// Wayland — xdg-shell gives clients no way to set their own position — so we
|
||||
// only persist size and leave placement to the compositor.
|
||||
let saved = AppConfig::load();
|
||||
let init_size = iced::Size::new(saved.window_width, saved.window_height);
|
||||
iced::application(AppState::default, update, view)
|
||||
.title("PeerSpeak P2P Voice Chat")
|
||||
.theme(theme)
|
||||
.subscription(subscription)
|
||||
.window(iced::window::Settings {
|
||||
// Taller default so the bottom chat dock doesn't squeeze the controls
|
||||
// column. Layout is responsive (Fill), so resizing still works.
|
||||
size: iced::Size::new(900.0, 760.0),
|
||||
// Restored from config (defaults 900×760: taller so the bottom chat
|
||||
// dock doesn't squeeze the controls column). Layout is responsive.
|
||||
size: init_size,
|
||||
position: iced::window::Position::Centered,
|
||||
exit_on_close_request: true,
|
||||
// We save the final size ourselves on CloseRequested, then exit.
|
||||
exit_on_close_request: false,
|
||||
..Default::default()
|
||||
})
|
||||
.run()
|
||||
@@ -734,6 +742,12 @@ fn update(state: &mut AppState, message: AppMessage) -> Task<AppMessage> {
|
||||
}
|
||||
AppMessage::EventOccurred(Event::Window(iced::window::Event::Resized(size))) => {
|
||||
state.window_size = size;
|
||||
// Remember the size in-memory; it's written to disk once on close.
|
||||
// Guard against bogus tiny/zero sizes some compositors emit transiently.
|
||||
if size.width >= 200.0 && size.height >= 200.0 {
|
||||
state.config.window_width = size.width;
|
||||
state.config.window_height = size.height;
|
||||
}
|
||||
// Keep divider positions valid for the new window dimensions. (Saved
|
||||
// with the next drag-release or other config write; not worth a disk
|
||||
// write on every resize tick.)
|
||||
@@ -746,6 +760,13 @@ fn update(state: &mut AppState, message: AppMessage) -> Task<AppMessage> {
|
||||
state.config.chat_drawer_width =
|
||||
clamp_chat_drawer_width(state.config.chat_drawer_width, size.width);
|
||||
}
|
||||
AppMessage::EventOccurred(Event::Window(iced::window::Event::CloseRequested)) => {
|
||||
// We took over the close path (exit_on_close_request:false) so we can
|
||||
// persist the final window size before quitting. The latest size is
|
||||
// already mirrored into config by the Resized handler above.
|
||||
state.config.save();
|
||||
return iced::exit();
|
||||
}
|
||||
AppMessage::EventOccurred(_) => {}
|
||||
AppMessage::NavigateToSettings => {
|
||||
state.current_screen = Screen::Settings;
|
||||
|
||||
@@ -92,6 +92,14 @@ fn default_chat_drawer_width() -> f32 {
|
||||
320.0
|
||||
}
|
||||
|
||||
fn default_window_width() -> f32 {
|
||||
900.0
|
||||
}
|
||||
|
||||
fn default_window_height() -> f32 {
|
||||
760.0
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub struct AppConfig {
|
||||
/// Last nickname used to join/create a room; pre-filled on the launch screen.
|
||||
@@ -149,6 +157,12 @@ pub struct AppConfig {
|
||||
/// Empty / unset = look it up on `$PATH`. Hand-editable; no Settings UI yet.
|
||||
#[serde(default)]
|
||||
pub pixelpass_path: Option<String>,
|
||||
/// Last window size (px), restored as the initial size on next launch.
|
||||
/// Saved on close. (Window *position* can't be restored on Wayland.)
|
||||
#[serde(default = "default_window_width")]
|
||||
pub window_width: f32,
|
||||
#[serde(default = "default_window_height")]
|
||||
pub window_height: f32,
|
||||
}
|
||||
|
||||
impl Default for AppConfig {
|
||||
@@ -177,6 +191,8 @@ impl Default for AppConfig {
|
||||
custom_sound_mic_toggle: None,
|
||||
custom_sound_reconnect_failed: None,
|
||||
pixelpass_path: None,
|
||||
window_width: default_window_width(),
|
||||
window_height: default_window_height(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -251,6 +267,27 @@ mod tests {
|
||||
assert!(deserialized.custom_sound_self_leave.is_none());
|
||||
assert!(deserialized.custom_sound_mic_toggle.is_none());
|
||||
assert!(deserialized.custom_sound_reconnect_failed.is_none());
|
||||
// Configs predating the remembered window size load the default size.
|
||||
assert_eq!(deserialized.window_width, 900.0);
|
||||
assert_eq!(deserialized.window_height, 760.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_window_size_fields() {
|
||||
// Default impl is the standard launch size.
|
||||
let def = AppConfig::default();
|
||||
assert_eq!(def.window_width, 900.0);
|
||||
assert_eq!(def.window_height, 760.0);
|
||||
// A saved size round-trips.
|
||||
let cfg = AppConfig {
|
||||
window_width: 1280.0,
|
||||
window_height: 720.0,
|
||||
..AppConfig::default()
|
||||
};
|
||||
let json = serde_json::to_string(&cfg).unwrap();
|
||||
let back: AppConfig = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(back.window_width, 1280.0);
|
||||
assert_eq!(back.window_height, 720.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user