diff options
Diffstat (limited to 'qml_plugin/src/qml_interface')
| -rw-r--r-- | qml_plugin/src/qml_interface/duckduckgo.rs | 88 | ||||
| -rw-r--r-- | qml_plugin/src/qml_interface/mathcalc.rs | 106 | ||||
| -rw-r--r-- | qml_plugin/src/qml_interface/network.rs | 55 | ||||
| -rw-r--r-- | qml_plugin/src/qml_interface/smartcalc.rs | 123 |
4 files changed, 372 insertions, 0 deletions
diff --git a/qml_plugin/src/qml_interface/duckduckgo.rs b/qml_plugin/src/qml_interface/duckduckgo.rs new file mode 100644 index 0000000..0375cdf --- /dev/null +++ b/qml_plugin/src/qml_interface/duckduckgo.rs @@ -0,0 +1,88 @@ +use cxx_qt::{CxxQtType, Threading}; +use cxx_qt_lib::QString; +use std::pin::Pin; +use unwrap_print::PrintableResult; + +use crate::{ExclusiveExecutor, web::duckduckgo}; + +#[cxx_qt::bridge] +mod qobject { + extern "C++" { + include!("cxx-qt-lib/qstring.h"); + type QString = cxx_qt_lib::QString; + } + + extern "RustQt" { + #[qobject] + #[qml_element] + #[qml_singleton] + #[qproperty(bool, ok)] + #[qproperty(QString, title)] + #[qproperty(QString, description_html)] + #[qproperty(QString, image)] + type DuckDuckGo = super::DuckDuckGoRs; + + #[qinvokable] + fn query(self: Pin<&mut DuckDuckGo>, input: QString); + + #[qinvokable] + fn reset(self: Pin<&mut DuckDuckGo>); + } + + impl cxx_qt::Threading for DuckDuckGo {} +} + +#[derive(Default)] +pub struct QmlDuckDuckGo { + pub title: QString, + pub description_html: QString, + pub image: QString, +} + +#[derive(Default)] +pub struct DuckDuckGoRs { + ok: bool, + title: QString, + description_html: QString, + image: QString, + + executor: ExclusiveExecutor, +} + +impl qobject::DuckDuckGo { + fn query(self: Pin<&mut Self>, input: QString) { + let qt_thread = self.qt_thread(); + self.rust_mut().executor.spawn(async move { + let qinput = input.to_string(); + let result: Result<QmlDuckDuckGo, _> = + duckduckgo::query(&qinput).await.map(|r| r.into()); + // consider just unwrapping since this is in a separate thread and + // is already end of life anw + _ = qt_thread + .queue(move |mut qo| match result { + Ok(r) => { + if (r.title.to_lower() == input.to_lower() || r.title.is_empty()) + && r.description_html.is_empty() + && r.image.is_empty() + { + qo.as_mut().set_ok(false); + } else { + qo.as_mut().set_ok(true); + qo.as_mut().set_title(r.title); + qo.as_mut().set_description_html(r.description_html); + qo.as_mut().set_image(r.image); + } + } + Err(_) => qo.set_ok(false), + }) + .unwrap_print(); + }); + } + + fn reset(mut self: Pin<&mut Self>) { + self.as_mut().set_ok(false); + self.as_mut().set_title("".into()); + self.as_mut().set_description_html("".into()); + self.as_mut().set_image("".into()); + } +} diff --git a/qml_plugin/src/qml_interface/mathcalc.rs b/qml_plugin/src/qml_interface/mathcalc.rs new file mode 100644 index 0000000..601dc3b --- /dev/null +++ b/qml_plugin/src/qml_interface/mathcalc.rs @@ -0,0 +1,106 @@ +use cxx_qt::{CxxQtType, Threading}; +use cxx_qt_lib::{QString, QVariant}; +use kalk::parser; +use std::{pin::Pin, sync::Arc}; +use tokio::sync::Mutex; +use unwrap_print::PrintableResult; + +use crate::ExclusiveExecutor; + +const DEFAULT_ANGLE_UNIT: &str = "deg"; + +#[cxx_qt::bridge] +mod qobject { + extern "C++" { + include!("cxx-qt-lib/qstring.h"); + include!("cxx-qt-lib/qvariant.h"); + type QString = cxx_qt_lib::QString; + type QVariant = cxx_qt_lib::QVariant; + } + + extern "RustQt" { + #[qobject] + #[qml_element] + #[qml_singleton] + #[qproperty(QVariant, result)] + type MathCalc = super::MathCalcRs; + + #[qinvokable] + fn query(self: Pin<&mut MathCalc>, input: QString); + + #[qinvokable] + fn reset(self: Pin<&mut MathCalc>); + + #[qinvokable] + fn reset_ctx(self: Pin<&mut MathCalc>); + + #[qinvokable] + fn reset_result(self: Pin<&mut MathCalc>); + } + + impl cxx_qt::Threading for MathCalc {} +} + +pub struct MathCalcRs { + result: QVariant, + ctx: Arc<Mutex<parser::Context>>, + + executor: ExclusiveExecutor, +} + +impl Default for MathCalcRs { + fn default() -> Self { + Self { + result: QVariant::default(), + ctx: Arc::new(Mutex::new(qobject::MathCalc::new_ctx())), + executor: ExclusiveExecutor::default(), + } + } +} + +impl qobject::MathCalc { + fn query(mut self: Pin<&mut Self>, input: QString) { + let qt_thread = self.qt_thread(); + let ctx = Arc::clone(&self.as_mut().rust_mut().ctx); + // TODO: consider moving to spawn_blocking + self.rust_mut().executor.spawn(async move { + let input = input.to_string(); + let result = parser::eval( + &mut *ctx.lock().await, + &input, + // TODO: move to const/config + 53, + ) + .map_or_default(|r| { + r.map_or_default(|r| { + let r: QString = r + // to display scientific notation properly + // other ones show both version without e or shows *10^_ + // and have a = prefix + // to_string_big will result in 1/2=5.0000000000000000e − 1 + .to_string() + .into(); + if r != input.into() { QVariant::from(&r) } else { QVariant::default() } + }) + }); + _ = qt_thread.queue(|mut qo| qo.as_mut().set_result(result)).unwrap_print(); + }); + } + + fn reset(mut self: Pin<&mut Self>) { + self.as_mut().reset_result(); + self.reset_ctx(); + } + + fn new_ctx() -> parser::Context { + parser::Context::default().set_angle_unit(DEFAULT_ANGLE_UNIT) + } + + fn reset_ctx(mut self: Pin<&mut Self>) { + self.as_mut().rust_mut().ctx = Arc::new(Mutex::new(Self::new_ctx())) + } + + fn reset_result(mut self: Pin<&mut Self>) { + self.as_mut().set_result(QVariant::default()) + } +} 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/qml_interface/smartcalc.rs b/qml_plugin/src/qml_interface/smartcalc.rs new file mode 100644 index 0000000..9b5f05a --- /dev/null +++ b/qml_plugin/src/qml_interface/smartcalc.rs @@ -0,0 +1,123 @@ +use cxx_qt::{CxxQtType, Threading}; +use cxx_qt_lib::{QString, QVariant}; +use std::pin::Pin; +use unwrap_print::PrintableResult; + +use crate::ExclusiveExecutor; + +#[cxx_qt::bridge] +mod qobject { + extern "C++" { + include!("cxx-qt-lib/qstring.h"); + include!("cxx-qt-lib/qvariant.h"); + type QString = cxx_qt_lib::QString; + type QVariant = cxx_qt_lib::QVariant; + } + + extern "RustQt" { + #[qobject] + #[qml_element] + #[qml_singleton] + #[qproperty(QVariant, result)] + #[qproperty(ResultType, result_type)] + #[qproperty(QVariant, cached_query)] + type SmartCalc = super::SmartCalcRs; + + #[qinvokable] + fn query(self: Pin<&mut SmartCalc>, input: QString); + + #[qinvokable] + fn reset(self: Pin<&mut SmartCalc>); + + #[qinvokable] + fn reset_result(self: Pin<&mut SmartCalc>); + } + + impl cxx_qt::Threading for SmartCalc {} + + #[qenum(SmartCalc)] + pub enum ResultType { + Math, + Unit, + Currency, + Crypto, + Time, + Date, + Unset, + } +} + +impl Default for qobject::ResultType { + fn default() -> Self { + qobject::ResultType::Unset + } +} + +impl From<&smart_calculator::types::ResultType> for qobject::ResultType { + fn from(value: &smart_calculator::types::ResultType) -> Self { + match value { + smart_calculator::types::ResultType::Math => qobject::ResultType::Math, + smart_calculator::types::ResultType::Unit => qobject::ResultType::Unit, + smart_calculator::types::ResultType::Currency => qobject::ResultType::Currency, + smart_calculator::types::ResultType::Crypto => qobject::ResultType::Crypto, + smart_calculator::types::ResultType::Time => qobject::ResultType::Time, + smart_calculator::types::ResultType::Date => qobject::ResultType::Date, + } + } +} + +#[derive(Default)] +pub struct SmartCalcRs { + result: QVariant, + result_type: qobject::ResultType, + + cached_query: QVariant, + + executor: ExclusiveExecutor, +} + +impl qobject::SmartCalc { + fn query(mut self: Pin<&mut Self>, input: QString) { + if self.cached_query == (&input).into() { + return; + } + self.as_mut().set_cached_query((&input.clone()).into()); + let qt_thread = self.qt_thread(); + self.as_mut().rust_mut().executor.spawn(async move { + let result = smart_calculator::calculate(&input.to_string(), None).await; + _ = qt_thread + .queue(|mut qo| { + qo.as_mut().set_result_type(match &result { + Ok(value) => (&value.res_type).into(), + Err(_) => qobject::ResultType::Unset, + }); + qo.as_mut().set_result( + // TODO: do the calc outside of ts main qt ui render + // thread.(all *.rs) + match result { + Ok(value) => { + if value.formatted == value.input { + QVariant::default() + } else { + let result: QString = value.formatted.into(); + QVariant::from(&result) + } + } + Err(_) => QVariant::default(), + }, + ) + }) + .unwrap_print(); + }); + } + + fn reset(mut self: Pin<&mut Self>) { + self.as_mut().set_cached_query(QVariant::default()); + self.reset_result(); + } + + fn reset_result(mut self: Pin<&mut Self>) { + self.as_mut().set_result(QVariant::default()); + self.as_mut().set_result_type(qobject::ResultType::Unset); + } +} |
