feat: Add Settings page and refactor view navigation

This commit is contained in:
2026-05-27 15:49:08 -04:00
parent 3834b35de2
commit a503a4c2eb
+69 -7
View File
@@ -14,6 +14,13 @@ use tokio::sync::Mutex;
static UI_RX: OnceLock<Mutex<Option<tokio::sync::mpsc::Receiver<UiEvent>>>> = OnceLock::new(); static UI_RX: OnceLock<Mutex<Option<tokio::sync::mpsc::Receiver<UiEvent>>>> = OnceLock::new();
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Screen {
Home,
Room,
Settings,
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum AppMessage { pub enum AppMessage {
NicknameChanged(String), NicknameChanged(String),
@@ -31,6 +38,8 @@ pub enum AppMessage {
InputDeviceChanged(String), InputDeviceChanged(String),
OutputDeviceChanged(String), OutputDeviceChanged(String),
EventOccurred(Event), EventOccurred(Event),
NavigateToSettings,
NavigateBack,
} }
fn core_subscription() -> impl iced::futures::Stream<Item = UiEvent> { fn core_subscription() -> impl iced::futures::Stream<Item = UiEvent> {
@@ -65,6 +74,7 @@ pub struct AppState {
peer_volumes: HashMap<EndpointId, f32>, peer_volumes: HashMap<EndpointId, f32>,
audio_levels: HashMap<EndpointId, f32>, audio_levels: HashMap<EndpointId, f32>,
controller: Arc<CoreController>, controller: Arc<CoreController>,
current_screen: Screen,
} }
impl Default for AppState { impl Default for AppState {
@@ -91,6 +101,7 @@ impl Default for AppState {
peer_volumes: HashMap::new(), peer_volumes: HashMap::new(),
audio_levels: HashMap::new(), audio_levels: HashMap::new(),
controller, controller,
current_screen: Screen::Home,
} }
} }
} }
@@ -161,15 +172,15 @@ fn update(state: &mut AppState, message: AppMessage) -> Task<AppMessage> {
UiEvent::RoomJoined { ticket, self_id } => { UiEvent::RoomJoined { ticket, self_id } => {
state.ticket = ticket; state.ticket = ticket;
state.self_id = self_id; state.self_id = self_id;
state.status_message = "Connected to room".to_string(); state.status_message = "Connected".to_string();
state.peers.clear(); state.current_screen = Screen::Room;
state.audio_levels.clear();
} }
UiEvent::RoomLeft => { UiEvent::RoomLeft => {
state.ticket = "".to_string(); state.ticket = "".to_string();
state.peers.clear(); state.peers.clear();
state.audio_levels.clear(); state.audio_levels.clear();
state.status_message = "Ready to connect".to_string(); state.status_message = "Ready to connect".to_string();
state.current_screen = Screen::Home;
} }
UiEvent::PeerJoined { id, state: peer_state } => { UiEvent::PeerJoined { id, state: peer_state } => {
state.peers.insert(id, peer_state); state.peers.insert(id, peer_state);
@@ -229,6 +240,16 @@ fn update(state: &mut AppState, message: AppMessage) -> Task<AppMessage> {
} }
} }
AppMessage::EventOccurred(_) => {} AppMessage::EventOccurred(_) => {}
AppMessage::NavigateToSettings => {
state.current_screen = Screen::Settings;
}
AppMessage::NavigateBack => {
if state.ticket.is_empty() {
state.current_screen = Screen::Home;
} else {
state.current_screen = Screen::Room;
}
}
} }
Task::none() Task::none()
} }
@@ -303,7 +324,43 @@ fn view(state: &AppState) -> Element<'_, AppMessage> {
} }
}; };
if state.ticket.is_empty() { let top_bar = row![
horizontal_space(),
button(text("⚙ Settings").size(14))
.on_press(AppMessage::NavigateToSettings)
.style(b_style(color_surface, color_blue, color_text, 6.0))
.padding(8)
].width(iced::Length::Fill).padding(10);
if state.current_screen == Screen::Settings {
let content = column![
text("Settings").size(32).color(color_text),
vertical_space(20.0),
text("Future settings and controls will be added here.").size(16).color(color_subtext),
vertical_space(40.0),
button(
text("Back")
.size(16)
.align_x(iced::alignment::Horizontal::Center)
)
.on_press(AppMessage::NavigateBack)
.style(b_style(color_surface, color_blue, color_text, 8.0))
.padding(14)
.width(iced::Length::Fixed(150.0))
]
.align_x(iced::alignment::Horizontal::Center)
.spacing(10);
return container(content)
.width(iced::Length::Fill)
.height(iced::Length::Fill)
.center_x(iced::Length::Fill)
.center_y(iced::Length::Fill)
.style(c_style(color_crust, Color::TRANSPARENT, 0.0))
.into();
}
if state.current_screen == Screen::Home {
// --- HOME SCREEN --- // --- HOME SCREEN ---
let logo = text("PEERSPEAK") let logo = text("PEERSPEAK")
.size(36) .size(36)
@@ -384,11 +441,15 @@ fn view(state: &AppState) -> Element<'_, AppMessage> {
.padding(30) .padding(30)
.width(420); .width(420);
container(content) container(
column![
top_bar,
vertical_space(40.0),
content
].align_x(iced::alignment::Horizontal::Center)
)
.width(iced::Length::Fill) .width(iced::Length::Fill)
.height(iced::Length::Fill) .height(iced::Length::Fill)
.align_x(iced::alignment::Horizontal::Center)
.align_y(iced::alignment::Vertical::Center)
.style(c_style(color_crust, Color::TRANSPARENT, 0.0)) .style(c_style(color_crust, Color::TRANSPARENT, 0.0))
.into() .into()
} else { } else {
@@ -569,6 +630,7 @@ fn view(state: &AppState) -> Element<'_, AppMessage> {
container( container(
column![ column![
top_bar,
header_container, header_container,
vertical_space(15.0), vertical_space(15.0),
main_layout main_layout