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

wallet: allow specifying dependencies for properties that causes them to be re-evaluated when the parent depends value changes.

darkfi 1 год назад
Родитель
Сommit
98e8c9aec9

+ 1 - 1
bin/darkwallet/src/app/schema.rs

@@ -53,7 +53,7 @@ mod android_ui_consts {
     pub const TEXTBAR_BASELINE: f32 = 93.;
     pub const EDITCHAT_LHS_PAD: f32 = 30.;
     pub const SENDLABEL_WIDTH: f32 = 200.;
-    pub const SENDLABEL_LHS_PAD: f32 = 30.;
+    pub const SENDLABEL_LHS_PAD: f32 = 40.;
     pub const FONTSIZE: f32 = 40.;
     pub const TIMESTAMP_FONTSIZE: f32 = 30.;
     pub const TIMESTAMP_WIDTH: f32 = 135.;

+ 29 - 5
bin/darkwallet/src/prop/mod.rs

@@ -20,7 +20,7 @@ use crate::error::{Error, Result};
 use darkfi_serial::{async_trait, Encodable, FutAsyncWriteExt, SerialDecodable, SerialEncodable};
 use std::{
     io::Write,
-    sync::{Arc, Mutex},
+    sync::{Arc, Mutex as SyncMutex, Weak},
 };
 
 use crate::{
@@ -212,6 +212,14 @@ pub enum ModifyAction {
 }
 
 pub type PropertyPtr = Arc<Property>;
+pub type PropertyWeak = Weak<Property>;
+
+#[derive(Debug, Clone)]
+pub struct PropertyDepend {
+    pub prop: PropertyWeak,
+    pub i: usize,
+    pub local_name: String,
+}
 
 #[derive(Debug)]
 pub struct Property {
@@ -220,10 +228,10 @@ pub struct Property {
     pub subtype: PropertySubType,
     pub defaults: Vec<PropertyValue>,
     // either a value or an expr must be set
-    pub vals: Mutex<Vec<PropertyValue>>,
+    pub vals: SyncMutex<Vec<PropertyValue>>,
     // only used valid when PropertyValue is an expr
     // caches the last calculated value
-    pub cache: Mutex<Vec<PropertyValue>>,
+    pub cache: SyncMutex<Vec<PropertyValue>>,
     pub ui_name: String,
     pub desc: String,
 
@@ -239,6 +247,7 @@ pub struct Property {
     pub enum_items: Option<Vec<String>>,
 
     on_modify: PublisherPtr<(Role, ModifyAction)>,
+    depends: SyncMutex<Vec<PropertyDepend>>,
 }
 
 impl Property {
@@ -249,8 +258,8 @@ impl Property {
             subtype,
 
             defaults: vec![typ.default_value()],
-            vals: Mutex::new(vec![PropertyValue::Unset]),
-            cache: Mutex::new(vec![PropertyValue::Null]),
+            vals: SyncMutex::new(vec![PropertyValue::Unset]),
+            cache: SyncMutex::new(vec![PropertyValue::Null]),
 
             ui_name: String::new(),
             desc: String::new(),
@@ -264,6 +273,7 @@ impl Property {
             enum_items: None,
 
             on_modify: Publisher::new(),
+            depends: SyncMutex::new(vec![]),
         }
     }
 
@@ -678,6 +688,20 @@ impl Property {
     pub fn subscribe_modify(&self) -> Subscription<(Role, ModifyAction)> {
         self.on_modify.clone().subscribe()
     }
+
+    // Dependencies
+
+    pub fn add_depend<S: Into<String>>(&self, prop: &PropertyPtr, i: usize, local_name: S) {
+        self.depends.lock().unwrap().push(PropertyDepend {
+            prop: Arc::downgrade(prop),
+            i,
+            local_name: local_name.into(),
+        });
+    }
+
+    pub fn get_depends(&self) -> Vec<PropertyDepend> {
+        self.depends.lock().unwrap().clone()
+    }
 }
 
 #[cfg(test)]

+ 14 - 7
bin/darkwallet/src/prop/wrap.rs

@@ -282,6 +282,19 @@ impl PropertyRect {
     }
 
     pub fn eval(&self, parent_rect: &Rectangle) -> Result<()> {
+        let mut globals = vec![
+            ("w".to_string(), SExprVal::Float32(parent_rect.w)),
+            ("h".to_string(), SExprVal::Float32(parent_rect.h)),
+        ];
+
+        for dep in self.prop.get_depends() {
+            let Some(prop) = dep.prop.upgrade() else { return Err(Error::PropertyNotFound) };
+
+            let value = prop.get_f32(dep.i)?;
+
+            globals.push((dep.local_name, SExprVal::Float32(value)));
+        }
+
         for i in 0..4 {
             if !self.prop.is_expr(i)? {
                 continue
@@ -289,13 +302,7 @@ impl PropertyRect {
 
             let expr = self.prop.get_expr(i).unwrap();
 
-            let mut machine = SExprMachine {
-                globals: vec![
-                    ("w".to_string(), SExprVal::Float32(parent_rect.w)),
-                    ("h".to_string(), SExprVal::Float32(parent_rect.h)),
-                ],
-                stmts: &expr,
-            };
+            let mut machine = SExprMachine { globals: globals.clone(), stmts: &expr };
 
             let v = machine.call()?.as_f32()?;
             self.prop.set_cache_f32(self.role, i, v).unwrap();

+ 14 - 2
bin/darkwallet/src/ui/mod.rs

@@ -17,6 +17,7 @@
  */
 
 use async_trait::async_trait;
+use futures::stream::{FuturesUnordered, StreamExt};
 use miniquad::{KeyCode, KeyMods, MouseButton, TouchPhase};
 use std::sync::{Arc, Weak};
 
@@ -117,12 +118,23 @@ impl<T: Send + Sync + 'static> OnModify<T> {
     {
         let node_name = self.node_name.clone();
         let node_id = self.node_id;
-        let on_modify_sub = prop.subscribe_modify();
+
+        let mut on_modify_subs = vec![prop.subscribe_modify()];
+        for dep in prop.get_depends() {
+            let Some(dep_prop) = dep.prop.upgrade() else { continue };
+            on_modify_subs.push(dep_prop.subscribe_modify());
+        }
+
         let prop_name = prop.name.clone();
         let me = self.me.clone();
         let task = self.ex.spawn(async move {
             loop {
-                let Ok((role, _)) = on_modify_sub.receive().await else {
+                let mut poll_queues = FuturesUnordered::new();
+                for on_modify_sub in &on_modify_subs {
+                    poll_queues.push(on_modify_sub.receive());
+                }
+
+                let Some(Ok((role, _))) = poll_queues.next().await else {
                     error!(target: "app", "Property '{}':{}/'{}' on_modify pipe is broken", node_name, node_id, prop_name);
                     return
                 };