summaryrefslogtreecommitdiff
path: root/qml_plugin/src
diff options
context:
space:
mode:
authorlittleblack111 <littleblack11111@gmail.com>2026-09-18 15:13:01 +0800
committerlittleblack111 <littleblack11111@gmail.com>2026-10-01 15:10:27 +0800
commit3cea94b72dbfdd2077a59fc52a7460e200b6061e (patch)
tree294a8cb1ef3aadc189073492bb041f6af2b17f70 /qml_plugin/src
parent8a71bd72f53e3629fb1d23d7c1b153207ba44789 (diff)
refactor: qml_pluginmain
Diffstat (limited to 'qml_plugin/src')
-rw-r--r--qml_plugin/src/lib.rs3
-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.rs55
-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.rs1
-rw-r--r--qml_plugin/src/services/network.rs66
-rw-r--r--qml_plugin/src/web/duckduckgo.rs78
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 }
- }),
- })
+ },
+ ),
+ },
+ )
}