feat(settings): add grouped configuration hub, languages and tray controls
This commit is contained in:
1 parent
6f34fd080f
commit
cc3b6f903f
90 files changed
+3625
-408
No files matched your search
@@ -0,0 +1,111 @@
|
||||
//! Read tray applications through the existing watcher without becoming a host.
|
||||
use super::{Alignment, App, Element, Length, Message, Task, column, row, set};
|
||||
use ferese_config::locale::text as t;
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Application {
|
||||
pub id: String,
|
||||
pub title: String,
|
||||
}
|
||||
async fn applications() -> Result<Vec<Application>, String> {
|
||||
let connection = zbus::Connection::session()
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let watcher = zbus::Proxy::new(
|
||||
&connection,
|
||||
"org.kde.StatusNotifierWatcher",
|
||||
"/StatusNotifierWatcher",
|
||||
"org.kde.StatusNotifierWatcher",
|
||||
)
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let addresses: Vec<String> = watcher
|
||||
.get_property("RegisteredStatusNotifierItems")
|
||||
.await
|
||||
.map_err(|e| e.to_string())?;
|
||||
let mut apps = Vec::new();
|
||||
for address in addresses.into_iter().take(128) {
|
||||
let (name, path) = address
|
||||
.find('/')
|
||||
.map_or((address.as_str(), "/StatusNotifierItem"), |i| {
|
||||
(&address[..i], &address[i..])
|
||||
});
|
||||
let Ok(proxy) =
|
||||
zbus::Proxy::new(&connection, name, path, "org.kde.StatusNotifierItem").await
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let Ok(id) = proxy.get_property::<String>("Id").await else {
|
||||
continue;
|
||||
};
|
||||
let title = proxy
|
||||
.get_property::<String>("Title")
|
||||
.await
|
||||
.unwrap_or_else(|_| id.clone());
|
||||
if !apps.iter().any(|a: &Application| a.id == id) {
|
||||
apps.push(Application { id, title });
|
||||
}
|
||||
}
|
||||
apps.sort_by(|a, b| a.title.cmp(&b.title));
|
||||
Ok(apps)
|
||||
}
|
||||
impl App {
|
||||
pub(super) fn load_tray_apps(&self) -> Task<Message> {
|
||||
cosmic::task::future(async { Message::TrayApps(applications().await.unwrap_or_default()) })
|
||||
}
|
||||
pub(super) fn tray_application_controls(&self) -> Element<'_, Message> {
|
||||
let hidden = self
|
||||
.draft
|
||||
.item("status.tray.hidden_items")
|
||||
.and_then(serde_json::Value::as_array)
|
||||
.map(|a| {
|
||||
a.iter()
|
||||
.filter_map(|v| v.as_str().map(str::to_owned))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let mut apps = self.tray_apps.clone();
|
||||
for id in &hidden {
|
||||
if !apps.iter().any(|a| &a.id == id) {
|
||||
apps.push(Application {
|
||||
id: id.clone(),
|
||||
title: id.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
let mut out = column([])
|
||||
.spacing(8)
|
||||
.push(self.panel_heading(t("Application icons"), 15.));
|
||||
for app in apps {
|
||||
let visible = !hidden.contains(&app.id);
|
||||
let mut next = hidden.clone();
|
||||
if visible {
|
||||
next.push(app.id);
|
||||
} else {
|
||||
next.retain(|id| id != &app.id);
|
||||
}
|
||||
out = out.push(
|
||||
row([])
|
||||
.spacing(8)
|
||||
.align_y(Alignment::Center)
|
||||
.push(self.label(app.title, 13.).width(Length::Fill))
|
||||
.push(
|
||||
ferese_theme::controls::switch(
|
||||
visible,
|
||||
super::visuals::Palette::from_resolved(&self.resolved.presented),
|
||||
)
|
||||
.on_press(Message::Change(set(
|
||||
"status.tray.hidden_items",
|
||||
serde_json::json!(next),
|
||||
))),
|
||||
),
|
||||
);
|
||||
}
|
||||
out.push(self.settings_button(
|
||||
t("Refresh applications"),
|
||||
"M3 10a8 8 0 1 1 1 7 M3 3v7h7",
|
||||
Some(Message::RefreshTrayApps),
|
||||
false,
|
||||
))
|
||||
.into()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user