feat(ui): category headers on the Settings page
Reorganize Settings into six clearly-headed categories with a reusable section_header (color_blue size-16 title + thin full-width divider): Audio Devices, Microphone, Network & Privacy, Room Layout, Theme, Notifications & Sounds. Splits the old shared Mic|Network row, drops the inconsistent inline size-14 sublabels, and removes the hardcoded "Theme" title from theme_section so it's rendered by the same header helper as every other section. Left-aligns the content (was centered) so headers, dividers, and hints line up. Presentational only; no message/logic changes. User-verified live. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+78
-51
@@ -1144,8 +1144,9 @@ fn view(state: &AppState) -> Element<'_, AppMessage> {
|
||||
AppTheme::ALL[0..5].iter().map(|&t| theme_choice(t)).collect();
|
||||
let theme_row2: Vec<Element<'_, AppMessage>> =
|
||||
AppTheme::ALL[5..].iter().map(|&t| theme_choice(t)).collect();
|
||||
// Title comes from the "Theme" section header (added below), so this body
|
||||
// is just the swatch rows + hint.
|
||||
let theme_section = column![
|
||||
text("Theme").size(14).color(color_subtext),
|
||||
iced::widget::Row::with_children(theme_row1).spacing(12),
|
||||
iced::widget::Row::with_children(theme_row2).spacing(12),
|
||||
text("Colour theme for the whole UI. Applies live.")
|
||||
@@ -1155,10 +1156,28 @@ fn view(state: &AppState) -> Element<'_, AppMessage> {
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill);
|
||||
|
||||
// Reusable category header: a coloured title with a thin full-width
|
||||
// divider beneath, so each class of settings reads as its own section.
|
||||
let section_header = |title: &'static str| -> Element<'_, AppMessage> {
|
||||
column![
|
||||
text(title).size(16).color(color_blue),
|
||||
container(text(""))
|
||||
.width(iced::Length::Fill)
|
||||
.height(iced::Length::Fixed(1.0))
|
||||
.style(c_style(color_surface, Color::TRANSPARENT, 0.0)),
|
||||
]
|
||||
.spacing(6)
|
||||
.width(iced::Length::Fill)
|
||||
.into()
|
||||
};
|
||||
|
||||
// Spacing between one category and the next.
|
||||
let section_gap = 18.0;
|
||||
|
||||
let settings_content = scrollable(
|
||||
column![
|
||||
text("Device Settings").size(14).color(color_subtext),
|
||||
vertical_space(6.0),
|
||||
// --- Audio Devices ---
|
||||
section_header("Audio Devices"),
|
||||
row![
|
||||
column![
|
||||
text("Input Device").size(12).color(color_subtext),
|
||||
@@ -1185,32 +1204,37 @@ fn view(state: &AppState) -> Element<'_, AppMessage> {
|
||||
.on_release(AppMessage::PersistConfig),
|
||||
].spacing(4).width(iced::Length::Fill),
|
||||
].spacing(20).align_y(iced::alignment::Vertical::Top).width(iced::Length::Fill),
|
||||
vertical_space(12.0),
|
||||
row![
|
||||
column![
|
||||
text("Mic Level & Noise Gate").size(14).color(color_subtext),
|
||||
mic_meter,
|
||||
text("Drag the yellow handle to set the gate. While talking, place it just above your quiet-room level so silence is muted but your voice passes through.").size(11).color(color_subtext),
|
||||
vertical_space(4.0),
|
||||
checkbox(state.config.echo_cancellation_enabled)
|
||||
.label("Echo cancellation")
|
||||
.on_toggle(AppMessage::ToggleEchoCancellation),
|
||||
text("Cancels speaker echo + suppresses noise (PipeWire). Takes effect on your next room join.").size(11).color(color_subtext),
|
||||
].spacing(8).width(iced::Length::Fill),
|
||||
column![
|
||||
text("Network Privacy").size(14).color(color_subtext),
|
||||
pick_list(
|
||||
&NetworkMode::ALL[..],
|
||||
Some(state.config.network_mode),
|
||||
AppMessage::NetworkModeSelected,
|
||||
).width(iced::Length::Fill),
|
||||
text(network_mode_hint(state.config.network_mode)).size(11).color(color_subtext),
|
||||
text("Takes effect on your next room join.").size(11).color(color_surface),
|
||||
].spacing(4).width(iced::Length::Fill),
|
||||
].spacing(20).align_y(iced::alignment::Vertical::Top).width(iced::Length::Fill),
|
||||
vertical_space(12.0),
|
||||
vertical_space(section_gap),
|
||||
|
||||
// --- Microphone ---
|
||||
section_header("Microphone"),
|
||||
column![
|
||||
mic_meter,
|
||||
text("Drag the yellow handle to set the gate. While talking, place it just above your quiet-room level so silence is muted but your voice passes through.").size(11).color(color_subtext),
|
||||
vertical_space(4.0),
|
||||
checkbox(state.config.echo_cancellation_enabled)
|
||||
.label("Echo cancellation")
|
||||
.on_toggle(AppMessage::ToggleEchoCancellation),
|
||||
text("Cancels speaker echo + suppresses noise (PipeWire). Takes effect on your next room join.").size(11).color(color_subtext),
|
||||
].spacing(8).width(iced::Length::Fill),
|
||||
vertical_space(section_gap),
|
||||
|
||||
// --- Network & Privacy ---
|
||||
section_header("Network & Privacy"),
|
||||
column![
|
||||
pick_list(
|
||||
&NetworkMode::ALL[..],
|
||||
Some(state.config.network_mode),
|
||||
AppMessage::NetworkModeSelected,
|
||||
).width(iced::Length::Fill),
|
||||
text(network_mode_hint(state.config.network_mode)).size(11).color(color_subtext),
|
||||
text("Takes effect on your next room join.").size(11).color(color_subtext),
|
||||
].spacing(4).width(iced::Length::Fill),
|
||||
vertical_space(section_gap),
|
||||
|
||||
// --- Room Layout ---
|
||||
section_header("Room Layout"),
|
||||
column![
|
||||
text("Room Layout").size(14).color(color_subtext),
|
||||
row![
|
||||
layout_choice(RoomLayout::ThreeColumn, "3-Column"),
|
||||
layout_choice(RoomLayout::BottomDock, "Bottom Dock"),
|
||||
@@ -1218,36 +1242,39 @@ fn view(state: &AppState) -> Element<'_, AppMessage> {
|
||||
].spacing(16),
|
||||
text("How the in-call room is arranged. Applies live.").size(11).color(color_subtext),
|
||||
].spacing(8).width(iced::Length::Fill),
|
||||
vertical_space(12.0),
|
||||
vertical_space(section_gap),
|
||||
|
||||
// --- Theme ---
|
||||
section_header("Theme"),
|
||||
theme_section,
|
||||
vertical_space(12.0),
|
||||
vertical_space(section_gap),
|
||||
|
||||
// --- Notifications & Sounds ---
|
||||
section_header("Notifications & Sounds"),
|
||||
column![
|
||||
text("Notification Chimes").size(14).color(color_subtext),
|
||||
checkbox(state.config.notifications_enabled)
|
||||
.label("Enable sound notifications")
|
||||
.on_toggle(AppMessage::ToggleNotifications),
|
||||
vertical_space(6.0),
|
||||
text("Custom chime files (WAV paths) — leave blank for the built-in sounds.").size(12).color(color_subtext),
|
||||
row![
|
||||
path_field("Self Join", Sound::SelfJoin),
|
||||
path_field("Peer Join", Sound::PeerJoin),
|
||||
].spacing(20).width(iced::Length::Fill),
|
||||
row![
|
||||
path_field("Self Leave", Sound::SelfLeave),
|
||||
path_field("Peer Leave", Sound::PeerLeave),
|
||||
].spacing(20).width(iced::Length::Fill),
|
||||
row![
|
||||
path_field("Reconnect Attempt", Sound::ReconnectAttempt),
|
||||
path_field("Reconnected", Sound::Reconnected),
|
||||
].spacing(20).width(iced::Length::Fill),
|
||||
row![
|
||||
path_field("Mic Toggle", Sound::MicToggle),
|
||||
path_field("Reconnect Failed", Sound::ReconnectFailed),
|
||||
].spacing(20).width(iced::Length::Fill),
|
||||
].spacing(8).width(iced::Length::Fill),
|
||||
vertical_space(12.0),
|
||||
text("Custom Chime Files (WAV Paths)").size(14).color(color_subtext),
|
||||
|
||||
row![
|
||||
path_field("Self Join", Sound::SelfJoin),
|
||||
path_field("Peer Join", Sound::PeerJoin),
|
||||
].spacing(20).width(iced::Length::Fill),
|
||||
row![
|
||||
path_field("Self Leave", Sound::SelfLeave),
|
||||
path_field("Peer Leave", Sound::PeerLeave),
|
||||
].spacing(20).width(iced::Length::Fill),
|
||||
row![
|
||||
path_field("Reconnect Attempt", Sound::ReconnectAttempt),
|
||||
path_field("Reconnected", Sound::Reconnected),
|
||||
].spacing(20).width(iced::Length::Fill),
|
||||
row![
|
||||
path_field("Mic Toggle", Sound::MicToggle),
|
||||
path_field("Reconnect Failed", Sound::ReconnectFailed),
|
||||
].spacing(20).width(iced::Length::Fill),
|
||||
]
|
||||
.align_x(iced::alignment::Horizontal::Center)
|
||||
.spacing(10)
|
||||
.width(iced::Length::Fill)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user