Add Wi-Fi and Bluetooth settings and compact controls

This commit is contained in:
Samuel Onoja committed 2026-10-01 15:28:16 +01:00
1 parent 94afc6eb5c
commit a3431cab5b
21 files changed
+3745 -225

No files matched your search

+45 -39
View File
@@ -18,7 +18,7 @@ impl App {
.into_owned()
};
let labels = column([])
.spacing(3)
.spacing(2)
.width(Length::Fill)
.push(self.label("Theme overrides", 13.))
.push(widget::tooltip(
@@ -39,32 +39,29 @@ impl App {
scopes = scopes.push(
button::custom(self.label(label, 12.))
.name(format!("Theme file: {label}"))
.padding([6, 8])
.padding([4, 8])
.class(visuals::button_style(palette, index == self.theme_file_target))
.on_press(Message::ThemeFileTarget(index)),
);
}
let mut controls = row([])
.spacing(8)
.spacing(6)
.align_y(Alignment::Center)
.push(
container(scopes)
.padding(3)
.class(visuals::surface(palette.sidebar, 10.)),
)
.push(
ferese_theme::controls::text_button(
if file.is_empty() { "Choose…" } else { "Replace…" },
self.font,
palette,
false,
)
.on_press(Message::PickThemeFile(path)),
);
.push(self.settings_button(
if file.is_empty() { "Choose…" } else { "Replace…" },
"M3 7V5h6l2 2h10v13H3z",
Some(Message::PickThemeFile(path)),
false,
));
if !file.is_empty() {
controls = controls.push(widget::tooltip(
button::custom(visuals::action_icon("M6 6l12 12M6 18L18 6", palette.muted))
.padding(5)
.padding(4)
.on_press(Message::Change(Edit::Unset(path.into()))),
self.label("Remove override", 11.),
widget::tooltip::Position::Bottom,
@@ -72,12 +69,12 @@ impl App {
}
container(
row([])
.spacing(16)
.spacing(6)
.align_y(Alignment::Center)
.push(labels)
.push(controls),
)
.padding([12, 12])
.padding([7, 10])
.width(Length::Fill)
.class(visuals::surface(palette.card, 0.))
.into()
@@ -88,24 +85,29 @@ impl App {
let scheduled = self.draft.string("theme.schedule.source", "schedule") == "schedule";
let mut sources = row([]).spacing(4);
for (source, label) in [("system", "System"), ("schedule", "Schedule")] {
sources = sources.push(
ferese_theme::controls::text_button(label, self.font, palette, scheduled == (source == "schedule"))
.name(format!("Auto source: {label}"))
.on_press(Message::Change(set("theme.schedule.source", source))),
);
sources = sources.push(self.settings_button(
label,
if source == "schedule" {
"M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18 M12 7v5l3 2"
} else {
"M3 4h18v13H3z M12 17v4 M8 21h8"
},
Some(Message::Change(set("theme.schedule.source", source))),
scheduled == (source == "schedule"),
));
}
let description = if scheduled {
"Switch between light and dark at set times."
} else {
"Follow the GTK/GNOME appearance preference."
};
let mut options = column([]).spacing(8).push(
let mut options = column([]).spacing(6).push(
row([])
.spacing(12)
.spacing(6)
.align_y(Alignment::Center)
.push(
column([])
.spacing(3)
.spacing(2)
.width(Length::Fill)
.push(self.label("Automatic appearance", 13.))
.push(self.note(description)),
@@ -113,7 +115,7 @@ impl App {
.push(sources),
);
if scheduled {
let mut times = row([]).spacing(16).align_y(Alignment::Center);
let mut times = row([]).spacing(6).align_y(Alignment::Center);
for field in schema::fields(Page::Appearance)
.into_iter()
.filter(|field| field.path.starts_with("theme.schedule."))
@@ -130,6 +132,7 @@ impl App {
let submit = field.clone();
let input = text_input(*default, value)
.font(self.font)
.padding([4, 8])
.size(12)
.style(visuals::input_style(palette))
.on_input(move |value| Message::Draft(path.clone(), value))
@@ -138,7 +141,7 @@ impl App {
.width(if field.path.ends_with("timezone") { 150 } else { 75 });
times = times.push(
row([])
.spacing(8)
.spacing(6)
.align_y(Alignment::Center)
.push(self.label(field.label, 12.))
.push(input),
@@ -147,7 +150,7 @@ impl App {
options = options.push(times);
}
container(options)
.padding(12)
.padding([7, 10])
.width(Length::Fill)
.class(visuals::surface(palette.card, 0.))
.into()
@@ -162,32 +165,35 @@ impl App {
let selected_id = visuals::family_selection(&self.draft, appearance);
let choices = self.resolved.families.clone();
let ids: Vec<_> = choices.iter().map(|family| family.id.clone()).collect();
let mut heading = row([]).align_y(Alignment::Center).spacing(12).push(
let mut heading = row([]).align_y(Alignment::Center).spacing(6).push(
self.label(
match appearance {
Some(Light) => "Light theme",
Some(Dark) => "Dark theme",
None => "Theme",
},
15.,
14.,
)
.width(Length::Fill),
);
if appearance != Some(Dark) {
if self.undo.is_some() {
heading = heading.push(
ferese_theme::controls::text_button("Undo", self.font, palette, false)
.on_press_maybe((!self.saving).then_some(Message::Undo)),
);
heading = heading.push(self.settings_icon_button(
"Undo",
"M4 10h8 M4 10V3 M4 10c3-7 16-6 16 3a7 7 0 0 1-7 7",
(!self.saving).then_some(Message::Undo),
));
}
heading = heading.push(
ferese_theme::controls::text_button("Import…", self.font, palette, false)
.on_press(Message::ImportTheme),
);
heading = heading.push(self.settings_button(
"Import…",
"M3 7V5h6l2 2h10v13H3z M12 10v7 M9 14l3 3 3-3",
Some(Message::ImportTheme),
false,
));
}
let mut gallery = column([]).spacing(10).push(heading);
let mut gallery = column([]).spacing(6).push(heading);
for (chunk, families) in choices.chunks(3).enumerate() {
let mut tiles = row([]).spacing(12);
let mut tiles = row([]).spacing(6);
for (offset, family) in families.iter().enumerate() {
let selected = family.id == selected_id;
let index = chunk * 3 + offset;
@@ -220,7 +226,7 @@ impl App {
gallery = gallery.push(tiles);
}
gallery::group(
container(gallery).width(Length::Fill).max_width(640),
container(gallery).width(Length::Fill),
cosmic::iced::advanced::widget::Id::new(format!("theme-gallery-{appearance:?}")),
match appearance {
Some(Light) => "Light theme",