Просмотр исходного кода

app: make connect status indicator clickable- doing so will force a reconnect

jkds 7 месяцев назад
Родитель
Сommit
9f716a283c
2 измененных файлов с 123 добавлено и 3 удалено
  1. 87 2
      bin/app/src/app/schema/mod.rs
  2. 36 1
      bin/app/src/plugin/darkirc.rs

+ 87 - 2
bin/app/src/app/schema/mod.rs

@@ -16,6 +16,7 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+use darkfi::system::msleep;
 use darkfi_serial::Encodable;
 use indoc::indoc;
 use sled_overlay::sled;
@@ -23,7 +24,7 @@ use std::fs::File;
 
 use crate::{
     app::{
-        node::{create_layer, create_shortcut, create_vector_art, create_video},
+        node::{create_button, create_layer, create_shortcut, create_vector_art, create_video},
         App,
     },
     expr::{self, Compiler},
@@ -31,7 +32,7 @@ use crate::{
     prop::{PropertyAtomicGuard, Role},
     scene::{SceneNodePtr, Slot},
     shape,
-    ui::{emoji_picker, Layer, Shortcut, VectorArt, VectorShape, Video},
+    ui::{emoji_picker, Button, Layer, ShapeVertex, Shortcut, VectorArt, VectorShape, Video},
     util::{i18n::I18nBabelFish, spawn_thread},
 };
 
@@ -40,6 +41,9 @@ mod menu;
 //mod settings;
 pub mod test;
 
+macro_rules! i { ($($arg:tt)*) => { info!(target: "app::schema", $($arg)*); } }
+macro_rules! e { ($($arg:tt)*) => { error!(target: "app::schema", $($arg)*); } }
+
 const COLOR_SCHEME: ColorScheme = ColorScheme::DarkMode;
 //const COLOR_SCHEME: ColorScheme = ColorScheme::PaperLight;
 
@@ -411,6 +415,87 @@ pub async fn make(app: &App, window: SceneNodePtr, i18n_fish: &I18nBabelFish) {
     let net3_node = node.setup(|me| VectorArt::new(me, shape, app.render_api.clone())).await;
     netlayer_node.link(net3_node);
 
+    // netstat-klik icon (visual feedback when reconnect button is clicked)
+    let klik_color = [0., 0.5, 1., 1.]; // Blue
+    let node = create_vector_art("netstat_klik");
+    let prop = node.get_property("rect").unwrap();
+    prop.set_f32(atom, Role::App, 0, 0.).unwrap();
+    prop.set_f32(atom, Role::App, 1, 0.).unwrap();
+    prop.set_f32(atom, Role::App, 2, NETSTATUS_ICON_SIZE).unwrap();
+    prop.set_f32(atom, Role::App, 3, NETSTATUS_ICON_SIZE).unwrap();
+    node.set_property_bool(atom, Role::App, "is_visible", false).unwrap();
+    // Above other icons
+    node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
+    let mut shape = VectorShape::new();
+    shape.add_filled_box(
+        expr::const_f32(0.),
+        expr::const_f32(0.),
+        expr::const_f32(NETSTATUS_ICON_SIZE),
+        expr::const_f32(NETSTATUS_ICON_SIZE),
+        klik_color,
+    );
+    let netstat_klik_node =
+        node.setup(|me| VectorArt::new(me, shape, app.render_api.clone())).await;
+    netlayer_node.link(netstat_klik_node.clone());
+
+    // Reconnect Button (overlaid on netstatus icons)
+    let node = create_button("reconnect_btn");
+    node.set_property_bool(atom, Role::App, "is_active", true).unwrap();
+    let prop = node.get_property("rect").unwrap();
+    prop.set_f32(atom, Role::App, 0, 0.).unwrap();
+    prop.set_f32(atom, Role::App, 1, 0.).unwrap();
+    prop.set_f32(atom, Role::App, 2, NETSTATUS_ICON_SIZE).unwrap();
+    prop.set_f32(atom, Role::App, 3, NETSTATUS_ICON_SIZE).unwrap();
+
+    let sg_root = app.sg_root.clone();
+    let render_api = app.render_api.clone();
+    let (slot, recvr) = Slot::new("reconnect_clicked");
+    node.register("click", slot).unwrap();
+    let reconnect_task = app.ex.spawn(async move {
+        while let Ok(_) = recvr.recv().await {
+            i!("Reconnect button clicked");
+
+            // Show netstat-klik icon
+            let netstat_klik =
+                sg_root.lookup_node("/window/content/netstatus_layer/netstat_klik").unwrap();
+
+            {
+                let atom = &mut render_api.make_guard(gfxtag!("netstat_klik_show"));
+                if let Err(e) = netstat_klik.set_property_bool(atom, Role::App, "is_visible", true)
+                {
+                    e!("Failed to show netstat_klik: {e}");
+                }
+            }
+
+            // Trigger reconnect
+            match sg_root.lookup_node("/plugin/darkirc") {
+                Some(darkirc) => {
+                    if let Err(e) = darkirc.call_method("reconnect", vec![]).await {
+                        e!("Failed to trigger reconnect: {e}");
+                    }
+                }
+                None => {
+                    e!("DarkIrc plugin has not been loaded");
+                }
+            }
+
+            msleep(200).await;
+
+            // Hide netstat-klik icon
+            {
+                let atom = &mut render_api.make_guard(gfxtag!("netstat_klik_hide"));
+                if let Err(e) = netstat_klik.set_property_bool(atom, Role::App, "is_visible", false)
+                {
+                    e!("Failed to hide netstat_klik: {e}");
+                }
+            }
+        }
+    });
+    app.tasks.lock().unwrap().push(reconnect_task);
+
+    let node = node.setup(Button::new).await;
+    netlayer_node.link(node);
+
     // Navbar Settings Button
 
     /*

+ 36 - 1
bin/app/src/plugin/darkirc.rs

@@ -517,6 +517,33 @@ impl DarkIrc {
         self_.settings.update_p2p_settings(&mut write_guard);
     }
 
+    async fn process_reconnect(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
+        let Ok(method_call) = sub.receive().await else {
+            d!("Reconnect method closed");
+            return false
+        };
+
+        t!("method called: reconnect({method_call:?})");
+
+        let Some(self_) = me.upgrade() else {
+            e!("DarkIrc destroyed before reconnect completed");
+            return false
+        };
+
+        i!("Manual P2P reconnection triggered");
+        self_.p2p.clone().stop().await;
+
+        while let Err(err) = self_.p2p.clone().start().await {
+            e!("Failed to start P2P network: {err}!");
+            e!("Retrying in {P2P_RETRY_TIME} secs");
+            sleep(P2P_RETRY_TIME).await;
+        }
+
+        i!("P2P reconnection completed");
+
+        true
+    }
+
     async fn start(self: Arc<Self>, sg_root: SceneNodePtr, ex: ExecutorPtr) {
         i!("Registering EventGraph P2P protocol");
         let event_graph_ = Arc::clone(&self.event_graph);
@@ -537,6 +564,13 @@ impl DarkIrc {
         let send_method_task =
             ex.spawn(async move { while Self::process_send(&me2, &method_sub).await {} });
 
+        let reconnect_method_sub = node.subscribe_method_call("reconnect").unwrap();
+        let me2 = me.clone();
+        let reconnect_method_task =
+            ex.spawn(
+                async move { while Self::process_reconnect(&me2, &reconnect_method_sub).await {} },
+            );
+
         let mut on_modify = OnModify::new(ex.clone(), self.node.clone(), me.clone());
         async fn save_nick(self_: Arc<DarkIrc>, _batch: BatchGuardPtr) {
             let _ = std::fs::write(nick_filename(), self_.nick.get());
@@ -583,7 +617,8 @@ impl DarkIrc {
             }
         });
 
-        let mut tasks = vec![send_method_task, ev_task, dag_task, start_task, stop_task];
+        let mut tasks =
+            vec![send_method_task, reconnect_method_task, ev_task, dag_task, start_task, stop_task];
         tasks.append(&mut on_modify.tasks);
         self.tasks.set(tasks).unwrap();
     }