diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2026-09-18 15:13:01 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2026-10-01 15:10:27 +0800 |
| commit | 3cea94b72dbfdd2077a59fc52a7460e200b6061e (patch) | |
| tree | 294a8cb1ef3aadc189073492bb041f6af2b17f70 /qml_plugin/src | |
| parent | 8a71bd72f53e3629fb1d23d7c1b153207ba44789 (diff) | |
refactor: qml_pluginmain
Diffstat (limited to 'qml_plugin/src')
| -rw-r--r-- | qml_plugin/src/lib.rs | 3 | ||||
| -rw-r--r-- | qml_plugin/src/qml_interface.rs (renamed from qml_plugin/src/launcher.rs) | 5 | ||||
| -rw-r--r-- | qml_plugin/src/qml_interface/duckduckgo.rs (renamed from qml_plugin/src/launcher/duckduckgo.rs) | 0 | ||||
| -rw-r--r-- | qml_plugin/src/qml_interface/mathcalc.rs (renamed from qml_plugin/src/launcher/mathcalc.rs) | 0 | ||||
| -rw-r--r-- | qml_plugin/src/qml_interface/network.rs | 55 | ||||
| -rw-r--r-- | qml_plugin/src/qml_interface/smartcalc.rs (renamed from qml_plugin/src/launcher/smartcalc.rs) | 0 | ||||
| -rw-r--r-- | qml_plugin/src/services.rs | 1 | ||||
| -rw-r--r-- | qml_plugin/src/services/network.rs | 66 | ||||
| -rw-r--r-- | qml_plugin/src/web/duckduckgo.rs | 78 |
9 files changed, 174 insertions, 34 deletions
diff --git a/qml_plugin/src/lib.rs b/qml_plugin/src/lib.rs index 0f1411c..b00b8be 100644 --- a/qml_plugin/src/lib.rs +++ b/qml_plugin/src/lib.rs @@ -34,5 +34,6 @@ impl ExclusiveExecutor { } } -mod launcher; +mod qml_interface; +mod services; mod web; diff --git a/qml_plugin/src/launcher.rs b/qml_plugin/src/qml_interface.rs index 180a756..f93fa23 100644 --- a/qml_plugin/src/launcher.rs +++ b/qml_plugin/src/qml_interface.rs @@ -1,5 +1,8 @@ +// TODO: use background worker + mpsc +/// Launchers pub mod duckduckgo; pub mod mathcalc; pub mod smartcalc; -// TODO: use background worker + mpsc +/// Services +pub mod network; diff --git a/qml_plugin/src/launcher/duckduckgo.rs b/qml_plugin/src/qml_interface/duckduckgo.rs index 0375cdf..0375cdf 100644 --- a/qml_plugin/src/launcher/duckduckgo.rs +++ b/qml_plugin/src/qml_interface/duckduckgo.rs diff --git a/qml_plugin/src/launcher/mathcalc.rs b/qml_plugin/src/qml_interface/mathcalc.rs index 601dc3b..601dc3b 100644 --- a/qml_plugin/src/launcher/mathcalc.rs +++ b/qml_plugin/src/qml_interface/mathcalc.rs diff --git a/qml_plugin/src/qml_interface/network.rs b/qml_plugin/src/qml_interface/network.rs new file mode 100644 index 0000000..7ece121 --- /dev/null +++ b/qml_plugin/src/qml_interface/network.rs @@ -0,0 +1,55 @@ +use cxx_qt::{CxxQtType, Threading}; +use cxx_qt_lib::{QString, QVariant}; +use std::pin::Pin; +use unwrap_print::PrintableResult; +use zbus::zvariant::NoneValue; + +use crate::{ExclusiveExecutor, services::network}; + +#[cxx_qt::bridge] +mod qobject { + extern "C++" { + include!("cxx-qt-lib/qvariant.h"); + type QVariant = cxx_qt_lib::QVariant; + } + + extern "RustQt" { + #[qobject] + #[qml_element] + #[qml_singleton] + #[qproperty( + QVariant, result + )] + type Network = super::NetworkRs; + + #[qinvokable] + fn query_primary_device(self: Pin<&mut Network>); + } + + impl cxx_qt::Threading for Network {} +} + +#[derive(Default)] +pub struct NetworkRs { + result: QVariant, + + executor: ExclusiveExecutor, +} + +impl qobject::Network { + fn query_primary_device(self: Pin<&mut Self>) { + let qt_thread = self.qt_thread(); + self.rust_mut().executor.spawn( + async move { + let result = match network::get().await { + Ok(o) => { + let r: QString = o.into(); + QVariant::from(&r) + } + Err(_) => QVariant::null_value(), + }; + _ = qt_thread.queue(|mut qo| qo.as_mut().set_result(result)).unwrap_print(); + }, + ); + } +} diff --git a/qml_plugin/src/launcher/smartcalc.rs b/qml_plugin/src/qml_interface/smartcalc.rs index 9b5f05a..9b5f05a 100644 --- a/qml_plugin/src/launcher/smartcalc.rs +++ b/qml_plugin/src/qml_interface/smartcalc.rs diff --git a/qml_plugin/src/services.rs b/qml_plugin/src/services.rs new file mode 100644 index 0000000..a61610b --- /dev/null +++ b/qml_plugin/src/services.rs @@ -0,0 +1 @@ +pub mod network; diff --git a/qml_plugin/src/services/network.rs b/qml_plugin/src/services/network.rs new file mode 100644 index 0000000..4883dba --- /dev/null +++ b/qml_plugin/src/services/network.rs @@ -0,0 +1,66 @@ +use zbus::{Connection, proxy, zvariant::OwnedObjectPath}; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("The connection is not active.")] + InactiveConnection, + #[error("Device doesn't exist")] + DeviceNotFound, + #[error("Failed to communicate with NetworkManager: {0}")] + Zbus(#[from] zbus::Error), +} + +#[proxy( + interface = "org.freedesktop.NetworkManager", + default_service = "org.freedesktop.NetworkManager", + default_path = "/org/freedesktop/NetworkManager" +)] +trait NetworkManager { + #[zbus(property)] + fn primary_connection(&self) -> zbus::Result<OwnedObjectPath>; +} + +#[proxy( + interface = "org.freedesktop.NetworkManager.Connection.Active", + default_service = "org.freedesktop.NetworkManager" +)] +trait ActiveConnection { + #[zbus(property)] + fn id(&self) -> zbus::Result<String>; + + #[zbus( + property, + name = "Type" + )] + fn type_(&self) -> zbus::Result<String>; + + #[zbus(property)] + fn devices(&self) -> zbus::Result<Vec<OwnedObjectPath>>; +} + +#[proxy( + interface = "org.freedesktop.NetworkManager.Device", + default_service = "org.freedesktop.NetworkManager" +)] +trait Device { + #[zbus(property)] + fn interface(&self) -> zbus::Result<String>; +} + +pub async fn get() -> Result<String, Error> { + let conn = Connection::system().await?; + + let nm_conn = NetworkManagerProxy::new(&conn).await?.primary_connection().await?; + + if nm_conn.as_str() == "/" { + return Err(Error::InactiveConnection); + } + + if let Some(device_path) = + ActiveConnectionProxy::builder(&conn).path(nm_conn)?.build().await?.devices().await?.first() + { + Ok(DeviceProxy::builder(&conn).path(device_path)?.build().await?.interface().await?) + } else { + Err(Error::DeviceNotFound) + } +} diff --git a/qml_plugin/src/web/duckduckgo.rs b/qml_plugin/src/web/duckduckgo.rs index 6b4edae..e5f1b64 100644 --- a/qml_plugin/src/web/duckduckgo.rs +++ b/qml_plugin/src/web/duckduckgo.rs @@ -1,6 +1,5 @@ use std::ops::{Deref, DerefMut}; -use crate::launcher::duckduckgo::QmlDuckDuckGo; use duckduckgo::{ browser::Browser, params::{SafeSearch, SearchParams, Toggle}, @@ -8,6 +7,8 @@ use duckduckgo::{ use reqwest::Url; use serde::Deserialize; +use crate::qml_interface::duckduckgo::QmlDuckDuckGo; + const DUCKDUCKGO: &str = "https://duckduckgo.com"; #[derive(Default, PartialEq)] @@ -83,36 +84,49 @@ pub async fn query(input: &str) -> anyhow::Result<DuckDuckGoContent> { _ => None, }; - let alt_desc = resp.entity.unwrap_or(match infobox { - Some(i) => i - .iter() - .find(|i| i.data_type == "wd_description" || i.data_type == "official_website") - .map_or(String::new(), |i| { - if i.data_type == "official_website" { - i.label.clone() - } else { - match i.value { - InfoboxValue::Entity(_) => unreachable!(), - InfoboxValue::String(ref s) => s.to_string(), + let alt_desc = resp.entity.unwrap_or( + match infobox { + Some(i) => i + .iter() + .find(|i| i.data_type == "wd_description" || i.data_type == "official_website") + .map_or( + String::new(), + |i| { + if i.data_type == "official_website" { + i.label.clone() + } else { + match i.value { + InfoboxValue::Entity(_) => unreachable!(), + InfoboxValue::String(ref s) => s.to_string(), + } + } + }, + ), + // TODO: find better way to get title from infobox + None => String::new(), + }, + ); + + Ok( + DuckDuckGoContent { + title: resp + .heading + .filter(|h| !h.is_empty()) + .unwrap_or(resp.definition.filter(|d| !d.is_empty()).unwrap_or(alt_desc.clone())), + description_html: resp + .answer + .filter(|a| !a.is_empty()) + .unwrap_or(resp.r#abstract.filter(|a| !a.is_empty()).unwrap_or(alt_desc)), + // TODO: try also Results[*].Icon.URL and RelatedTopics[*].Icon.URL + image: resp.image.filter(|i| !i.is_empty()).and_then( + |i| { + if !i.is_empty() { + Url::parse(&format!("{DUCKDUCKGO}{i}",)).ok() + } else { + None } - } - }), - // TODO: find better way to get title from infobox - None => String::new(), - }); - - Ok(DuckDuckGoContent { - title: resp - .heading - .filter(|h| !h.is_empty()) - .unwrap_or(resp.definition.filter(|d| !d.is_empty()).unwrap_or(alt_desc.clone())), - description_html: resp - .answer - .filter(|a| !a.is_empty()) - .unwrap_or(resp.r#abstract.filter(|a| !a.is_empty()).unwrap_or(alt_desc)), - // TODO: try also Results[*].Icon.URL and RelatedTopics[*].Icon.URL - image: resp.image.filter(|i| !i.is_empty()).and_then(|i| { - if !i.is_empty() { Url::parse(&format!("{DUCKDUCKGO}{i}",)).ok() } else { None } - }), - }) + }, + ), + }, + ) } |
