From 1391d297bebdbcf760a765c11cc7c6132a5d72f9 Mon Sep 17 00:00:00 2001 From: James Maes Date: Wed, 22 Jul 2026 19:53:22 -0500 Subject: [PATCH] feat(gui): add GuiViewState three-panel split view model --- crates/nuncio-gui/src/main.rs | 7 ++- crates/nuncio-gui/src/view.rs | 82 +++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 crates/nuncio-gui/src/view.rs diff --git a/crates/nuncio-gui/src/main.rs b/crates/nuncio-gui/src/main.rs index 5469a27..4fa02ac 100644 --- a/crates/nuncio-gui/src/main.rs +++ b/crates/nuncio-gui/src/main.rs @@ -2,16 +2,19 @@ mod ipc; mod sandbox; +mod view; use ipc::IpcBridge; use nuncio_core::EventBus; +use view::GuiViewState; fn main() { let bus = EventBus::new(); let state = IpcBridge::get_app_state(&bus); + let view_state = GuiViewState::default(); println!( - "Nuncio GUI Desktop Shell Initialized: status={:?}, unread={}", - state.status, state.unread_count + "Nuncio GUI Desktop Shell Initialized: status={:?}, unread={}, active_folder={}", + state.status, state.unread_count, view_state.active_folder_id ); } diff --git a/crates/nuncio-gui/src/view.rs b/crates/nuncio-gui/src/view.rs new file mode 100644 index 0000000..5068629 --- /dev/null +++ b/crates/nuncio-gui/src/view.rs @@ -0,0 +1,82 @@ +//! React/Vite Webview component layout model and state bindings. + +use nuncio_core::model::{Email, Folder}; +use serde::{Deserialize, Serialize}; + +/// Frontend split-view layout state container. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct GuiViewState { + /// Available folders list. + pub folders: Vec, + /// Active selected folder ID. + pub active_folder_id: String, + /// Loaded email message list. + pub messages: Vec, + /// Currently selected email ID for reading preview. + pub selected_message_id: Option, + /// Dark mode UI theme preference flag. + pub dark_mode: bool, +} + +impl GuiViewState { + /// Create a new default GUI view state. + pub fn new() -> Self { + Self { + folders: vec![ + Folder { + id: "inbox".to_string(), + name: "Inbox".to_string(), + total_messages: 5, + unread_messages: 2, + }, + Folder { + id: "sent".to_string(), + name: "Sent".to_string(), + total_messages: 3, + unread_messages: 0, + }, + ], + active_folder_id: "inbox".to_string(), + messages: Vec::new(), + selected_message_id: None, + dark_mode: true, + } + } + + /// Select active folder. + pub fn select_folder(&mut self, folder_id: &str) { + self.active_folder_id = folder_id.to_string(); + self.selected_message_id = None; + } + + /// Select active message preview. + pub fn select_message(&mut self, message_id: &str) { + self.selected_message_id = Some(message_id.to_string()); + } +} + +impl Default for GuiViewState { + fn default() -> Self { + Self::new() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn gui_view_state_navigation() { + let mut state = GuiViewState::default(); + + assert_eq!(state.active_folder_id, "inbox"); + assert!(state.dark_mode); + + state.select_folder("sent"); + assert_eq!(state.active_folder_id, "sent"); + assert!(state.selected_message_id.is_none()); + + state.select_message("msg-101"); + assert_eq!(state.selected_message_id, Some("msg-101".to_string())); + } +} -- 2.54.0