summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/components/smart_summary.rs73
-rw-r--r--src/lib.rs32
2 files changed, 67 insertions, 38 deletions
diff --git a/src/components/smart_summary.rs b/src/components/smart_summary.rs
index 37bbd74..b360d77 100644
--- a/src/components/smart_summary.rs
+++ b/src/components/smart_summary.rs
@@ -3,7 +3,6 @@ use relm4::{gtk, prelude::{AsyncComponent, AsyncComponentParts}, AsyncComponentS
 
 #[derive(Debug, Default)]
 pub(crate) struct SmartSummaryButton {
-    content_buffer: gtk::TextBuffer,
     busy: bool,
 }
 
@@ -13,6 +12,12 @@ pub(crate) enum Error {
 }
 
 #[derive(Debug)]
+pub(crate) enum Input {
+    ButtonPressed,
+    Text(String)
+}
+
+#[derive(Debug)]
 pub(crate) enum Output {
     Start,
     Chunk(String),
@@ -23,17 +28,17 @@ pub(crate) enum Output {
 
 #[relm4::component(pub(crate) async)]
 impl AsyncComponent for SmartSummaryButton {
-    type Input = ();
+    type Input = Input;
     type Output = Output;
 
-    type Init = gtk::TextBuffer;
+    type Init = ();
     type CommandOutput = ();
 
     view! {
         #[root]
         #[name = "button"]
         gtk::Button {
-            connect_clicked => (),
+            connect_clicked => Input::ButtonPressed,
             #[watch]
             set_sensitive: !model.busy,
             set_tooltip_markup: Some("<b>Smart Summary</b>\nAsk a language model for a single-sentence summary."),
@@ -47,38 +52,44 @@ impl AsyncComponent for SmartSummaryButton {
         }
     }
 
-    async fn init(init: Self::Init, root: Self::Root, sender: AsyncComponentSender<Self>) -> AsyncComponentParts<Self> {
-        let model = SmartSummaryButton {
-            content_buffer: init,
-            ..Default::default()
-        };
+    async fn init(
+        _init: Self::Init,
+        root: Self::Root,
+        sender: AsyncComponentSender<Self>
+    ) -> AsyncComponentParts<Self> {
+        let model = Self::default();
         let widgets = view_output!();
 
         AsyncComponentParts { model, widgets }
     }
 
-    async fn update_with_view(&mut self, widgets: &mut Self::Widgets, _msg: Self::Input, sender: AsyncComponentSender<Self>, _root: &Self::Root) {
-        log::debug!("Starting Smart Summary generation");
-        self.busy = true;
-        let _ = sender.output(Output::Start);
-        self.update_view(widgets, sender.clone());
-
-        let text = self.content_buffer.text(
-            &self.content_buffer.start_iter(),
-            &self.content_buffer.end_iter(),
-            false
-        );
-        log::debug!("Would generate summary for the following text:\n{}", text);
-        tokio::time::sleep(std::time::Duration::from_millis(450)).await;
-
-        for i in ["I'", "m ", "sorry,", " I", " am ", "unable", " to", " ", "write", " you ", "a summary.", " I", " am", " not ", "really ", "an ", "LLM."] {
-            tokio::time::sleep(std::time::Duration::from_millis(100)).await;
-            let _ = sender.output(Output::Chunk(i.to_string()));
+    async fn update_with_view(
+        &mut self,
+        widgets: &mut Self::Widgets,
+        msg: Self::Input,
+        sender: AsyncComponentSender<Self>,
+        _root: &Self::Root
+    ) {
+        match msg {
+            Input::ButtonPressed => if let Ok(()) = sender.output(Output::Start) {
+                self.busy = true;
+                log::debug!("Requesting text to summarize from parent component...");
+                self.update_view(widgets, sender.clone());
+            },
+            Input::Text(text) => {
+                log::debug!("Would generate summary for the following text:\n{}", text);
+                tokio::time::sleep(std::time::Duration::from_millis(450)).await;
+
+                for i in ["I'", "m ", "sorry,", " I", " am ", "unable", " to", " ", "write", " you ", "a summary.", " I", " am", " not ", "really ", "an ", "LLM."] {
+                    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
+                    let _ = sender.output(Output::Chunk(i.to_string()));
+                }
+
+                log::debug!("Done with the summary.");
+                self.busy = false;
+                let _ = sender.output(Output::Done);
+                self.update_view(widgets, sender.clone());
+            }
         }
-
-        log::debug!("Done with the summary.");
-        self.busy = false;
-        let _ = sender.output(Output::Done);
-        self.update_view(widgets, sender.clone());
     }
 }
diff --git a/src/lib.rs b/src/lib.rs
index f95a40a..244c09f 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,7 +6,9 @@ use relm4::{gtk, prelude::{AsyncComponent, AsyncComponentController, AsyncCompon
 
 pub mod components {
     pub(crate) mod smart_summary;
-    pub(crate) use smart_summary::{SmartSummaryButton, Output as SmartSummaryOutput};
+    pub(crate) use smart_summary::{
+        SmartSummaryButton, Output as SmartSummaryOutput, Input as SmartSummaryInput
+    };
 }
 mod widgets;
 pub mod secrets;
@@ -36,6 +38,14 @@ pub struct PostComposerModel {
     #[do_not_track] smart_summary: AsyncController<components::SmartSummaryButton>,
 }
 
+impl PostComposerModel {
+    fn busy_changed(&self) -> bool {
+        self.changed(Self::submit_busy_guard() | Self::smart_summary_busy_guard())
+    }
+    fn busy(&self) -> bool {
+        self.submit_busy_guard.is_some() || self.smart_summary_busy_guard.is_some()
+    }
+}
 
 #[derive(Debug)]
 #[allow(private_interfaces)]
@@ -72,8 +82,8 @@ impl AsyncComponent for PostComposerModel {
                         send_button = gtk::Button {
                             set_label: "Post",
                             connect_clicked => Self::Input::Submit,
-                            #[track = "model.changed(Self::submit_busy_guard())"]
-                            set_sensitive: model.submit_busy_guard.is_none(),
+                            #[track = "model.busy_changed()"]
+                            set_sensitive: !model.busy(),
                         },
 
                         bar = adw::HeaderBar::new() {
@@ -128,8 +138,8 @@ impl AsyncComponent for PostComposerModel {
                                 gtk::Entry {
                                     set_hexpand: true,
                                     set_buffer: &model.summary_buffer,
-                                    #[track = "model.changed(Self::smart_summary_busy_guard() | Self::submit_busy_guard())"]
-                                    set_sensitive: model.smart_summary_busy_guard.is_none() && model.submit_busy_guard.is_none(),
+                                    #[track = "model.busy_changed()"]
+                                    set_sensitive: !model.busy(),
                                 },
 
                                 model.smart_summary.widget(),
@@ -264,7 +274,7 @@ impl AsyncComponent for PostComposerModel {
 
             micropub: Arc::new(init),
             smart_summary: components::SmartSummaryButton::builder()
-                .launch(content_buffer)
+                .launch(())
                 .forward(sender.input_sender(), PostComposerInput::SmartSummary),
 
             tracker: Default::default()
@@ -335,7 +345,15 @@ impl AsyncComponent for PostComposerModel {
                 self.set_smart_summary_busy_guard(
                     Some(relm4::main_adw_application().mark_busy())
                 );
-                self.summary_buffer.set_text("");
+                if self.smart_summary.sender().send(components::SmartSummaryInput::Text(
+                    self.content_buffer.text(
+                        &self.content_buffer.start_iter(),
+                        &self.content_buffer.end_iter(),
+                        false
+                    ).into()
+                )).is_ok() {
+                    self.summary_buffer.set_text("");
+                }
             },
             PostComposerInput::SmartSummary(components::SmartSummaryOutput::Chunk(text)) => {
                 self.summary_buffer.insert_text(self.summary_buffer.length(), text);