revault-gui icon indicating copy to clipboard operation
revault-gui copied to clipboard

UI: Do not display zero value when state is not fully loaded

Open edouardparis opened this issue 4 years ago • 8 comments

  • [x] deposit.rs
  • [x] emergency.rs
  • [x] manager.rs
  • [ ] settings.rs
  • [ ] sign.rs
  • [ ] spend_transaction.rs
  • [x] stakeholder.rs
  • [ ] vault.rs
  • [x] vaults.rs
  • [x] history.rs

edouardparis avatar Mar 09 '21 15:03 edouardparis

What was the context for this? I don't remember.

darosior avatar Apr 18 '21 17:04 darosior

The GUI is a little slow without the --release flag, then when changing state, the view display default values like 0 balance while waiting the response of revaultd. We should display nothing until, all revaultd responses are returned

edouardparis avatar Apr 19 '21 06:04 edouardparis

My idea was to have an object like:

pub enum Loadable<T> {
    Loading,
    Loaded(T)
}

and then passing to the view method a Loadable object, so for example:

    pub fn view<'a>(
        &'a mut self,
        ctx: &Context,
        spend_txs: Vec<Element<'a, Message>>,

would become

    pub fn view<'a>(
        &'a mut self,
        ctx: &Context,
        spend_txs: Loadable<Vec<Element<'a, Message>>>,

then matching on the Loadable, and if it's in a Loading state you don't show certain parts of the UI

danielabrozzoni avatar May 12 '21 15:05 danielabrozzoni

Can you provide an example how it is store in the State owning the view ?

edouardparis avatar May 13 '21 08:05 edouardparis

Ok, it's way worse than what I expected: (disclaimer, this doesn't compile yet as there are some iter_mut and iter around that need to be transformed in if let)

diff --git a/src/ui/mod.rs b/src/ui/mod.rs
index 36f2081..10b710e 100644
--- a/src/ui/mod.rs
+++ b/src/ui/mod.rs
@@ -5,3 +5,9 @@ mod menu;
 mod message;
 mod state;
 mod view;
+
+#[derive(Debug)]
+pub enum Loadable<T> {
+    Loading,
+    Ready(T),
+}
diff --git a/src/ui/state/stakeholder.rs b/src/ui/state/stakeholder.rs
index 0f53800..14c0548 100644
--- a/src/ui/state/stakeholder.rs
+++ b/src/ui/state/stakeholder.rs
@@ -21,6 +21,7 @@ use crate::ui::{
         Context, StakeholderACKFundsView, StakeholderDelegateFundsView, StakeholderHomeView,
         StakeholderNetworkView,
     },
+    Loadable,
 };
 
 #[derive(Debug)]
@@ -228,7 +229,7 @@ pub struct StakeholderACKFundsState {
 
     warning: Option<Error>,
     balance: u64,
-    deposits: Vec<VaultListItem<AcknowledgeVaultListItemView>>,
+    deposits: Loadable<Vec<VaultListItem<AcknowledgeVaultListItemView>>>,
     selected_vault: Option<Vault>,
 
     view: StakeholderACKFundsView,
@@ -239,7 +240,7 @@ impl StakeholderACKFundsState {
         StakeholderACKFundsState {
             revaultd,
             warning: None,
-            deposits: Vec::new(),
+            deposits: Loadable::Loading,
             view: StakeholderACKFundsView::new(),
             balance: 0,
             selected_vault: None,
@@ -254,25 +255,27 @@ impl StakeholderACKFundsState {
             }
         }
 
-        if let Some(selected) = self
-            .deposits
-            .iter()
-            .find(|vlt| vlt.vault.outpoint() == outpoint)
-        {
-            self.selected_vault = Some(Vault::new(selected.vault.clone()));
-            return Command::perform(
-                get_revocation_txs(self.revaultd.clone(), selected.vault.outpoint()),
-                move |res| {
-                    Message::Vault(outpoint.clone(), VaultMessage::RevocationTransactions(res))
-                },
-            );
-        };
+        if let Loadable::Ready(deposits) = self.deposits {
+            if let Some(selected) =
+                deposits
+                .iter()
+                .find(|vlt| vlt.vault.outpoint() == outpoint)
+            {
+                self.selected_vault = Some(Vault::new(selected.vault.clone()));
+                return Command::perform(
+                    get_revocation_txs(self.revaultd.clone(), selected.vault.outpoint()),
+                    move |res| {
+                        Message::Vault(outpoint.clone(), VaultMessage::RevocationTransactions(res))
+                    },
+                );
+            };
+        }
         Command::none()
     }
 
     fn update_deposits(&mut self, vaults: Vec<model::Vault>) {
         self.calculate_balance(&vaults);
-        self.deposits = vaults.into_iter().map(VaultListItem::new).collect();
+        self.deposits = Loadable::Ready(vaults.into_iter().map(VaultListItem::new).collect());
     }
 
     fn calculate_balance(&mut self, vaults: &[model::Vault]) {
diff --git a/src/ui/view/stakeholder.rs b/src/ui/view/stakeholder.rs
index b189ebe..e238e62 100644
--- a/src/ui/view/stakeholder.rs
+++ b/src/ui/view/stakeholder.rs
@@ -10,6 +10,7 @@ use crate::ui::{
     menu::Menu,
     message::Message,
     view::Context,
+    Loadable,
 };
 
 #[derive(Debug)]
@@ -29,7 +30,7 @@ impl StakeholderACKFundsView {
     pub fn view<'a>(
         &'a mut self,
         _ctx: &Context,
-        deposits: Vec<Element<'a, Message>>,
+        deposits: Loadable<Vec<Element<'a, Message>>>,
     ) -> Element<'a, Message> {
         let mut col_deposits = Column::new();
         for element in deposits.into_iter() {

My point was to use Loadable as if it was an Option. The problem is that you don't have some utilities like map() and you have to continuosly map or if let...

danielabrozzoni avatar May 13 '21 09:05 danielabrozzoni

A second way could be to create an enum from the State and collecting every loading models in one message. Ex:

#[derive(Debug)]
pub enum VaultsState {
    Loading,
    Loaded {
        revaultd: Arc<RevaultD>,
        view: VaultsView,

        blockheight: u64,

        vault_status_filter: &'static [VaultStatus],
        vaults: Vec<VaultListItem<VaultListItemView>>,
        selected_vault: Option<Vault>,

        warning: Option<Error>,
    },
}

whith load like:

fn load(&self, revaultd: Arc<RevaultD>) -> Command<Message> {
        Command::batch(vec![Command::perform(
            load_vaults_state(revaultd.clone()),
            Message::LoadVaultState,
        )])
    }

with view like:

fn view(&mut self, ctx: &Context) -> Element<Message> {
        match self {
            Self::Loading => view::dashboard_loading(ctx); 
            Self::Loaded{view, ..} => view.view(ctx,...)
        }

I think we use revaultd only for update and load, we can stop allocate it each time we change state and just pass it as arg

fn update(&mut self, revaultd: Arc<RevaultD>, message: Message) -> Command<Message>

edouardparis avatar May 13 '21 09:05 edouardparis

Was this addressed?

darosior avatar Dec 15 '21 19:12 darosior

Nope, we still have 0 in some screens

I think it's important to fix this, at least in the home

danielabrozzoni avatar Dec 16 '21 11:12 danielabrozzoni