|
|
@@ -23,17 +23,18 @@ use darkfi_serial::Decodable;
|
|
|
|
|
|
use crate::{
|
|
|
app::{
|
|
|
- node::{create_layer, create_text},
|
|
|
+ node::{create_layer, create_text, create_vector_art},
|
|
|
App,
|
|
|
},
|
|
|
expr,
|
|
|
gfx::gfxtag,
|
|
|
+ mesh::{COLOR_DARKTEAL, COLOR_GREEN, COLOR_RED},
|
|
|
prop::{
|
|
|
Property, PropertyAtomicGuard, PropertyBool, PropertyFloat32, PropertyPermission,
|
|
|
PropertySubType, PropertyType, Role,
|
|
|
},
|
|
|
scene::{SceneNodePtr, Slot},
|
|
|
- ui::{Layer, Text},
|
|
|
+ ui::{Layer, Text, VectorArt, VectorShape},
|
|
|
util::i18n::I18nBabelFish,
|
|
|
};
|
|
|
|
|
|
@@ -55,6 +56,7 @@ pub async fn make(
|
|
|
cc.add_const_f32("AMOUNT_FONTSIZE", AMOUNT_FONTSIZE);
|
|
|
cc.add_const_f32("BASE_FONTSIZE", BASE_FONTSIZE);
|
|
|
cc.add_const_f32("HINT_FONTSIZE", HINT_FONTSIZE);
|
|
|
+ cc.add_const_f32("HINT_H", HINT_H);
|
|
|
cc.add_const_f32("PADDING_X", PADDING_X);
|
|
|
cc.add_const_f32("PADDING_Y", PADDING_Y);
|
|
|
cc.add_const_f32("RECIPIENT_INPUT_MARGIN", RECIPIENT_INPUT_MARGIN);
|
|
|
@@ -100,6 +102,29 @@ pub async fn make(
|
|
|
prop.set_defaults_str(vec!["".to_string()]).unwrap();
|
|
|
tx_status_layer.add_property(prop).unwrap();
|
|
|
|
|
|
+ // Add tx_id property to store the transaction ID for status polling
|
|
|
+ let mut prop = Property::new(
|
|
|
+ "tx_status",
|
|
|
+ PropertyType::Enum,
|
|
|
+ PropertySubType::Null,
|
|
|
+ PropertyPermission::default(),
|
|
|
+ );
|
|
|
+ prop.set_enum_items(vec!["confirming", "confirmed", "error"]).unwrap();
|
|
|
+ prop.set_default_enum(0, "confirming").unwrap();
|
|
|
+ tx_status_layer.add_property(prop).unwrap();
|
|
|
+
|
|
|
+ // Height of the hint zone
|
|
|
+ const HINT_H: f32 = PADDING_X + PADDING_Y + HINT_FONTSIZE * 2.;
|
|
|
+ let mut prop = Property::new(
|
|
|
+ "hint_h",
|
|
|
+ PropertyType::Float32,
|
|
|
+ PropertySubType::Pixel,
|
|
|
+ PropertyPermission::default(),
|
|
|
+ );
|
|
|
+ prop.set_defaults_f32(vec![HINT_H]).unwrap();
|
|
|
+ tx_status_layer.add_property(prop).unwrap();
|
|
|
+ let hint_h_prop = tx_status_layer.get_property("hint_h").unwrap();
|
|
|
+
|
|
|
let prop = tx_status_layer.get_property("rect").unwrap();
|
|
|
prop.set_default_f32(0, 0.).unwrap();
|
|
|
prop.set_default_f32(1, 0.).unwrap();
|
|
|
@@ -117,20 +142,16 @@ pub async fn make(
|
|
|
|
|
|
create_bg_mesh(app, atom, &tx_status_layer, "tx_status_bg").await;
|
|
|
|
|
|
- let mut y = HEADER_HEIGHT;
|
|
|
-
|
|
|
- create_title(app, atom, &tx_status_layer, &window_scale, i18n_fish, "SEND", "SEND", &mut y)
|
|
|
- .await;
|
|
|
-
|
|
|
- // Status text
|
|
|
+ // Status headline
|
|
|
let node = create_text("status");
|
|
|
let prop = node.get_property("rect").unwrap();
|
|
|
- prop.set_default_f32(0, PADDING_X).unwrap();
|
|
|
- prop.set_default_f32(1, y + PADDING_Y).unwrap();
|
|
|
- prop.set_default_f32(2, 1000.).unwrap();
|
|
|
+ prop.set_default_f32(0, 0.).unwrap();
|
|
|
+ prop.set_default_f32(1, HEADER_HEIGHT + PADDING_Y).unwrap();
|
|
|
+ prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
prop.set_default_f32(3, BASE_FONTSIZE).unwrap();
|
|
|
node.get_property("font_size").unwrap().set_default_f32(0, BASE_FONTSIZE).unwrap();
|
|
|
- node.set_property_str(atom, Role::App, "text", "Broadcasting...").unwrap();
|
|
|
+ node.set_property_enum(atom, Role::App, "text_align", "center").unwrap();
|
|
|
+ node.set_property_str(atom, Role::App, "text", "Transaction in process...").unwrap();
|
|
|
let prop = node.get_property("text_color").unwrap();
|
|
|
prop.set_default_f32_multi(&[1., 1., 1., 1.]).unwrap();
|
|
|
node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
@@ -147,22 +168,76 @@ pub async fn make(
|
|
|
.await;
|
|
|
tx_status_layer.link(node);
|
|
|
|
|
|
- y += PADDING_Y * 2. + BASE_FONTSIZE + 1.;
|
|
|
+ // Transaction info: "Sending" / "{amount} {token_symbol}" / "to" / "{recipient}"
|
|
|
+ // stacked below each other, centered horizontally, inside a layer that is
|
|
|
+ // vertically centered in the free space below the header.
|
|
|
+ let info_h = PADDING_Y * 5. + BASE_FONTSIZE * 4. + 1.;
|
|
|
+ cc.add_const_f32("TX_TOP", HEADER_HEIGHT);
|
|
|
+ let tx_info_layer = create_layer("tx_info");
|
|
|
+ tx_info_layer.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
|
|
|
+ let prop = tx_info_layer.get_property("rect").unwrap();
|
|
|
+ prop.set_default_f32(0, 0.).unwrap();
|
|
|
+ let code = cc
|
|
|
+ .compile(
|
|
|
+ "
|
|
|
+ info_h = PADDING_Y * 5 + BASE_FONTSIZE * 4 + 1;
|
|
|
+ free_h = h - PADDING_X * 2 - BUTTON_HEIGHT - hint_h - TX_TOP;
|
|
|
+ if free_h < info_h {
|
|
|
+ TX_TOP
|
|
|
+ } else {
|
|
|
+ TX_TOP + (free_h - info_h) / 2
|
|
|
+ }
|
|
|
+ ",
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+ prop.set_default_expr(1, code).unwrap();
|
|
|
+ prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
+ prop.set_default_f32(3, info_h).unwrap();
|
|
|
+ prop.add_depend(Role::App, &hint_h_prop, 0, "hint_h");
|
|
|
+ tx_info_layer.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
+ let tx_info_layer = tx_info_layer
|
|
|
+ .setup(|me| Layer::new(me, app.renderer.clone(), app.redraw_trigger.clone()))
|
|
|
+ .await;
|
|
|
+ tx_status_layer.link(tx_info_layer.clone());
|
|
|
|
|
|
- create_separator(&app, atom, &tx_status_layer, "tx_status_separator", &mut y, false).await;
|
|
|
+ // Inset box shadow
|
|
|
+ let shadow_node = create_vector_art("tx_status_shadow");
|
|
|
+ let prop = shadow_node.get_property("rect").unwrap();
|
|
|
+ prop.set_default_f32(0, 0.).unwrap();
|
|
|
+ prop.set_default_expr(1, cc.compile("TX_TOP").unwrap()).unwrap();
|
|
|
+ prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
+ prop.set_default_expr(
|
|
|
+ 3,
|
|
|
+ cc.compile("h - PADDING_X * 2 - BUTTON_HEIGHT - TX_TOP - hint_h").unwrap(),
|
|
|
+ )
|
|
|
+ .unwrap();
|
|
|
+ prop.add_depend(Role::App, &hint_h_prop, 0, "hint_h");
|
|
|
+ shadow_node.set_property_u32(atom, Role::App, "z_index", 1).unwrap();
|
|
|
+ let shadow_node = shadow_node
|
|
|
+ .setup(|me| VectorArt::new(me, app.renderer.clone(), app.redraw_trigger.clone()))
|
|
|
+ .await;
|
|
|
+ let mut shadow_shape = VectorShape::new();
|
|
|
+ shadow_shape.add_box_shadow_inset(
|
|
|
+ expr::const_f32(0.),
|
|
|
+ expr::const_f32(0.),
|
|
|
+ expr::load_var("w"),
|
|
|
+ expr::load_var("h"),
|
|
|
+ 100.,
|
|
|
+ [0., 0., 0., 0.],
|
|
|
+ );
|
|
|
+ shadow_node.set_property_shape(atom, Role::App, "shape", shadow_shape).unwrap();
|
|
|
+ tx_status_layer.link(shadow_node);
|
|
|
|
|
|
- // Transaction info text: "Sending {amount} {token_symbol} to {recipient_address}"
|
|
|
- let node = create_text("tx_info");
|
|
|
- let info_h_prop = node.get_property("height").unwrap();
|
|
|
+ // "Sending" or "Sent"
|
|
|
+ let node = create_text("action");
|
|
|
let prop = node.get_property("rect").unwrap();
|
|
|
- prop.set_default_f32(0, PADDING_X).unwrap();
|
|
|
- prop.set_default_f32(1, y + PADDING_Y).unwrap();
|
|
|
- let code = cc.compile("w - PADDING_X * 2").unwrap();
|
|
|
- prop.set_default_expr(2, code).unwrap();
|
|
|
+ prop.set_default_f32(0, 0.).unwrap();
|
|
|
+ prop.set_default_f32(1, PADDING_Y).unwrap();
|
|
|
+ prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
prop.set_default_f32(3, BASE_FONTSIZE).unwrap();
|
|
|
node.get_property("font_size").unwrap().set_default_f32(0, BASE_FONTSIZE).unwrap();
|
|
|
- node.set_property_str(atom, Role::App, "text", "Sending 0 DRK to recipient").unwrap();
|
|
|
- node.set_property_enum(atom, Role::App, "overflow_wrap", "anywhere").unwrap();
|
|
|
+ node.set_property_str(atom, Role::App, "text", "Sending").unwrap();
|
|
|
+ node.set_property_enum(atom, Role::App, "text_align", "center").unwrap();
|
|
|
let prop = node.get_property("text_color").unwrap();
|
|
|
prop.set_default_f32_multi(&[1., 1., 1., 1.]).unwrap();
|
|
|
node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
@@ -177,29 +252,119 @@ pub async fn make(
|
|
|
)
|
|
|
})
|
|
|
.await;
|
|
|
- tx_status_layer.link(node);
|
|
|
+ tx_info_layer.link(node);
|
|
|
|
|
|
- let sep = create_separator(
|
|
|
- app,
|
|
|
- atom,
|
|
|
- &tx_status_layer,
|
|
|
- "tx_info_separator",
|
|
|
- &mut 0.,
|
|
|
- false,
|
|
|
- )
|
|
|
- .await;
|
|
|
- let prop = sep.get_property("rect").unwrap();
|
|
|
- let code = cc.compile(format!("{y} + PADDING_Y * 2 + info_height + 1")).unwrap();
|
|
|
+ // Amount + token symbol
|
|
|
+ let node = create_text("amount");
|
|
|
+ let prop = node.get_property("rect").unwrap();
|
|
|
+ prop.set_default_f32(0, 0.).unwrap();
|
|
|
+ let code = cc.compile("PADDING_Y * 2 + BASE_FONTSIZE").unwrap();
|
|
|
+ prop.set_default_expr(1, code).unwrap();
|
|
|
+ prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
+ prop.set_default_f32(3, BASE_FONTSIZE).unwrap();
|
|
|
+ node.get_property("font_size").unwrap().set_default_f32(0, BASE_FONTSIZE).unwrap();
|
|
|
+ node.set_property_str(atom, Role::App, "text", "").unwrap();
|
|
|
+ node.set_property_enum(atom, Role::App, "text_align", "center").unwrap();
|
|
|
+ let prop = node.get_property("text_color").unwrap();
|
|
|
+ prop.set_default_f32_multi(&[0.5451, 1., 1., 1.]).unwrap();
|
|
|
+ let prop = node.get_property("text_shadow_color").unwrap();
|
|
|
+ prop.set_default_f32_multi(&[0.5451, 1., 1., 1.]).unwrap();
|
|
|
+ let prop = node.get_property("text_shadow_blur").unwrap();
|
|
|
+ prop.set_default_f32(0, BASE_FONTSIZE / 2.).unwrap();
|
|
|
+ node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
+ let node = node
|
|
|
+ .setup(|me| {
|
|
|
+ Text::new(
|
|
|
+ me,
|
|
|
+ window_scale.clone(),
|
|
|
+ app.renderer.clone(),
|
|
|
+ i18n_fish.clone(),
|
|
|
+ app.redraw_trigger.clone(),
|
|
|
+ )
|
|
|
+ })
|
|
|
+ .await;
|
|
|
+ tx_info_layer.link(node);
|
|
|
+
|
|
|
+ // "to"
|
|
|
+ let node = create_text("to");
|
|
|
+ let prop = node.get_property("rect").unwrap();
|
|
|
+ prop.set_default_f32(0, 0.).unwrap();
|
|
|
+ let code = cc.compile("PADDING_Y * 3 + BASE_FONTSIZE * 2").unwrap();
|
|
|
+ prop.set_default_expr(1, code).unwrap();
|
|
|
+ prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
+ prop.set_default_f32(3, BASE_FONTSIZE).unwrap();
|
|
|
+ node.get_property("font_size").unwrap().set_default_f32(0, BASE_FONTSIZE).unwrap();
|
|
|
+ node.set_property_str(atom, Role::App, "text", "to").unwrap();
|
|
|
+ node.set_property_enum(atom, Role::App, "text_align", "center").unwrap();
|
|
|
+ let prop = node.get_property("text_color").unwrap();
|
|
|
+ prop.set_default_f32_multi(&[1., 1., 1., 1.]).unwrap();
|
|
|
+ node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
+ let node = node
|
|
|
+ .setup(|me| {
|
|
|
+ Text::new(
|
|
|
+ me,
|
|
|
+ window_scale.clone(),
|
|
|
+ app.renderer.clone(),
|
|
|
+ i18n_fish.clone(),
|
|
|
+ app.redraw_trigger.clone(),
|
|
|
+ )
|
|
|
+ })
|
|
|
+ .await;
|
|
|
+ tx_info_layer.link(node);
|
|
|
+
|
|
|
+ // Recipient address
|
|
|
+ let node = create_text("recipient");
|
|
|
+ let prop = node.get_property("rect").unwrap();
|
|
|
+ prop.set_default_f32(0, 0.).unwrap();
|
|
|
+ let code = cc.compile("PADDING_Y * 4 + BASE_FONTSIZE * 3").unwrap();
|
|
|
prop.set_default_expr(1, code).unwrap();
|
|
|
- prop.add_depend(Role::App, &info_h_prop, 0, "info_height");
|
|
|
+ prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
+ prop.set_default_f32(3, BASE_FONTSIZE).unwrap();
|
|
|
+ node.get_property("font_size").unwrap().set_default_f32(0, BASE_FONTSIZE).unwrap();
|
|
|
+ node.set_property_str(atom, Role::App, "text", "").unwrap();
|
|
|
+ node.set_property_enum(atom, Role::App, "text_align", "center").unwrap();
|
|
|
+ node.set_property_enum(atom, Role::App, "overflow_wrap", "anywhere").unwrap();
|
|
|
+ let prop = node.get_property("text_color").unwrap();
|
|
|
+ prop.set_default_f32_multi(&[0., 1., 0.6392, 1.]).unwrap();
|
|
|
+ let prop = node.get_property("text_shadow_color").unwrap();
|
|
|
+ prop.set_default_f32_multi(&[0., 1., 0.6392, 1.]).unwrap();
|
|
|
+ let prop = node.get_property("text_shadow_blur").unwrap();
|
|
|
+ prop.set_default_f32(0, BASE_FONTSIZE / 2.).unwrap();
|
|
|
+ node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
+ let node = node
|
|
|
+ .setup(|me| {
|
|
|
+ Text::new(
|
|
|
+ me,
|
|
|
+ window_scale.clone(),
|
|
|
+ app.renderer.clone(),
|
|
|
+ i18n_fish.clone(),
|
|
|
+ app.redraw_trigger.clone(),
|
|
|
+ )
|
|
|
+ })
|
|
|
+ .await;
|
|
|
+ tx_info_layer.link(node);
|
|
|
+
|
|
|
+ // Hint text. Only shown while the tx is confirming (see the
|
|
|
+ // "tx_status" property subscription below). Wrapped in its own layer
|
|
|
+ // since Text has no is_visible property.
|
|
|
+ let hint_layer = create_layer("hint_layer");
|
|
|
+ hint_layer.set_property_bool(atom, Role::App, "is_visible", true).unwrap();
|
|
|
+ let prop = hint_layer.get_property("rect").unwrap();
|
|
|
+ prop.set_default_f32(0, 0.).unwrap();
|
|
|
+ prop.set_default_f32(1, 0.).unwrap();
|
|
|
+ prop.set_default_expr(2, expr::load_var("w")).unwrap();
|
|
|
+ prop.set_default_expr(3, expr::load_var("h")).unwrap();
|
|
|
+ hint_layer.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
+ let hint_layer = hint_layer
|
|
|
+ .setup(|me| Layer::new(me, app.renderer.clone(), app.redraw_trigger.clone()))
|
|
|
+ .await;
|
|
|
+ tx_status_layer.link(hint_layer.clone());
|
|
|
|
|
|
- // Hint text
|
|
|
- let hint_node = create_text("tx_status_hint");
|
|
|
+ let hint_node = create_text("hint");
|
|
|
let prop = hint_node.get_property("rect").unwrap();
|
|
|
let code = cc.compile("w / 2 - (HINT_FONTSIZE * 0.7 * 31) / 2").unwrap();
|
|
|
prop.set_default_expr(0, code).unwrap();
|
|
|
- let code =
|
|
|
- cc.compile("h - PADDING_X * 2 - BUTTON_HEIGHT - PADDING_Y - HINT_FONTSIZE * 2").unwrap();
|
|
|
+ let code = cc.compile("h - PADDING_X - HINT_H + PADDING_Y").unwrap();
|
|
|
prop.set_default_expr(1, code).unwrap();
|
|
|
let code = cc.compile("HINT_FONTSIZE * 0.7 * 31").unwrap();
|
|
|
prop.set_default_expr(2, code).unwrap();
|
|
|
@@ -215,7 +380,7 @@ pub async fn make(
|
|
|
)
|
|
|
.unwrap();
|
|
|
let prop = hint_node.get_property("text_color").unwrap();
|
|
|
- prop.set_default_f32_multi(&[1., 1., 1., 0.45]).unwrap();
|
|
|
+ prop.set_default_f32_multi(&COLOR_DARKTEAL).unwrap();
|
|
|
hint_node.set_property_u32(atom, Role::App, "z_index", 2).unwrap();
|
|
|
let hint_node = hint_node
|
|
|
.setup(|me| {
|
|
|
@@ -228,26 +393,29 @@ pub async fn make(
|
|
|
)
|
|
|
})
|
|
|
.await;
|
|
|
- tx_status_layer.link(hint_node.clone());
|
|
|
+ hint_layer.link(hint_node);
|
|
|
|
|
|
// Separator line
|
|
|
create_separator_expr(
|
|
|
app,
|
|
|
atom,
|
|
|
&tx_status_layer,
|
|
|
- "tx_status_hint_separator",
|
|
|
+ "hint_separator",
|
|
|
&mut cc,
|
|
|
- "h - PADDING_X * 2 - BUTTON_HEIGHT",
|
|
|
+ "h - PADDING_X * 2 - BUTTON_HEIGHT - hint_h",
|
|
|
false,
|
|
|
)
|
|
|
- .await;
|
|
|
+ .await
|
|
|
+ .get_property("rect")
|
|
|
+ .unwrap()
|
|
|
+ .add_depend(Role::App, &hint_h_prop, 0, "hint_h");
|
|
|
|
|
|
// Close button
|
|
|
let node = create_bottom_button(
|
|
|
app,
|
|
|
atom,
|
|
|
&tx_status_layer,
|
|
|
- "tx_status_close_btn",
|
|
|
+ "close_btn",
|
|
|
&mut cc,
|
|
|
Some("close"),
|
|
|
&window_scale,
|
|
|
@@ -255,6 +423,13 @@ pub async fn make(
|
|
|
)
|
|
|
.await;
|
|
|
|
|
|
+ // Move the button group above the hint zone
|
|
|
+ let btn_layer = tx_status_layer.lookup_node("/close_btn_layer").unwrap();
|
|
|
+ let prop = btn_layer.get_property("rect").unwrap();
|
|
|
+ let code = cc.compile("h - PADDING_X - BUTTON_HEIGHT - hint_h").unwrap();
|
|
|
+ prop.set_expr(atom, Role::App, 1, code).unwrap();
|
|
|
+ prop.add_depend(Role::App, &hint_h_prop, 0, "hint_h");
|
|
|
+
|
|
|
let main_is_visible = PropertyBool::wrap(&main_layer, Role::App, "is_visible", 0).unwrap();
|
|
|
let redraw = app.redraw_trigger.clone();
|
|
|
let tx_status_is_visible1 = tx_status_is_visible.clone();
|
|
|
@@ -286,7 +461,7 @@ pub async fn make(
|
|
|
|
|
|
let mut cur = std::io::Cursor::new(mcall.data);
|
|
|
let tx_id = Option::<String>::decode(&mut cur).unwrap();
|
|
|
- let status_text = Option::<String>::decode(&mut cur).unwrap();
|
|
|
+ let confirmed = Option::<bool>::decode(&mut cur).unwrap();
|
|
|
let amount = Option::<String>::decode(&mut cur).unwrap();
|
|
|
let token_symbol = Option::<String>::decode(&mut cur).unwrap();
|
|
|
let recipient_str = Option::<String>::decode(&mut cur).unwrap();
|
|
|
@@ -296,25 +471,34 @@ pub async fn make(
|
|
|
tx_status_layer_clone.set_property_str(atom, Role::App, "tx_id", id).unwrap();
|
|
|
}
|
|
|
|
|
|
- // Update status text
|
|
|
- if let Some(text) = status_text {
|
|
|
- if let Some(status_node) =
|
|
|
- sg_root.lookup_node("/window/content/wallet/tx_status_layer/status")
|
|
|
- {
|
|
|
- status_node.set_property_str(atom, Role::App, "text", &text).unwrap();
|
|
|
- }
|
|
|
+ // Store the tx_status
|
|
|
+ if let Some(confirmed) = confirmed {
|
|
|
+ let status = match confirmed {
|
|
|
+ false => "confirming",
|
|
|
+ true => "confirmed",
|
|
|
+ };
|
|
|
+ tx_status_layer_clone
|
|
|
+ .set_property_enum(atom, Role::App, "tx_status", status)
|
|
|
+ .unwrap();
|
|
|
}
|
|
|
|
|
|
// Update transaction info display
|
|
|
if let (Some(amount), Some(token_symbol), Some(recipient_str)) =
|
|
|
(amount, token_symbol, recipient_str)
|
|
|
{
|
|
|
- if let Some(tx_info) =
|
|
|
- sg_root.lookup_node("/window/content/wallet/tx_status_layer/tx_info")
|
|
|
+ if let Some(tx_info_amount) =
|
|
|
+ sg_root.lookup_node("/window/content/wallet/tx_status_layer/tx_info/amount")
|
|
|
{
|
|
|
- let tx_text =
|
|
|
- format!("Sending {} {} to {}", amount, token_symbol, recipient_str);
|
|
|
- tx_info.set_property_str(atom, Role::App, "text", tx_text).unwrap();
|
|
|
+ let amount_text = format!("{} {}", amount, token_symbol);
|
|
|
+ tx_info_amount.set_property_str(atom, Role::App, "text", amount_text).unwrap();
|
|
|
+ }
|
|
|
+
|
|
|
+ if let Some(tx_info_recipient) =
|
|
|
+ sg_root.lookup_node("/window/content/wallet/tx_status_layer/tx_info/recipient")
|
|
|
+ {
|
|
|
+ tx_info_recipient
|
|
|
+ .set_property_str(atom, Role::App, "text", format_address(&recipient_str))
|
|
|
+ .unwrap();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -333,5 +517,73 @@ pub async fn make(
|
|
|
}
|
|
|
}));
|
|
|
|
|
|
+ // Subscribe to the current tx status and update the screen accordingly
|
|
|
+ let status_prop = tx_status_layer.get_property("tx_status").unwrap();
|
|
|
+ let text_sub = status_prop.subscribe_modify();
|
|
|
+ let redraw = app.redraw_trigger.clone();
|
|
|
+ let shadow_node = tx_status_layer.lookup_node("/tx_status_shadow").unwrap();
|
|
|
+ let action_node = tx_status_layer.lookup_node("/tx_info/action").unwrap();
|
|
|
+ let status_node = tx_status_layer.lookup_node("/status").unwrap();
|
|
|
+ let hint_layer = tx_status_layer.lookup_node("/hint_layer").unwrap();
|
|
|
+ let hint_layer_is_visible =
|
|
|
+ PropertyBool::wrap(&hint_layer, Role::App, "is_visible", 0).unwrap();
|
|
|
+
|
|
|
+ let listen_status_text = {
|
|
|
+ let redraw = redraw.clone();
|
|
|
+ let shadow_node = shadow_node.clone();
|
|
|
+ app.ex.spawn(async move {
|
|
|
+ while let Ok(_) = text_sub.receive().await {
|
|
|
+ let atom = &mut redraw.make_guard(gfxtag!("tx status updated"));
|
|
|
+
|
|
|
+ let status = status_prop.get_enum(0).unwrap();
|
|
|
+
|
|
|
+ // Toggle hint
|
|
|
+ let confirming = status == "confirming";
|
|
|
+ hint_layer_is_visible.set(atom, confirming);
|
|
|
+ hint_h_prop
|
|
|
+ .set_f32(atom, Role::App, 0, if confirming { HINT_H } else { 0. })
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ // Update headline text + color
|
|
|
+ let (headline, headline_color) = match status.as_str() {
|
|
|
+ "confirmed" => ("Transaction successful", COLOR_GREEN),
|
|
|
+ "error" => ("Transaction failed", COLOR_RED),
|
|
|
+ _ => ("Transaction in process...", [0.5725, 1., 0.898, 1.]),
|
|
|
+ };
|
|
|
+ status_node.set_property_str(atom, Role::App, "text", headline).unwrap();
|
|
|
+ let prop = status_node.get_property("text_color").unwrap();
|
|
|
+ for i in 0..4 {
|
|
|
+ prop.set_f32(atom, Role::App, i, headline_color[i]).unwrap();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Update action text
|
|
|
+ let text = match status.as_str() {
|
|
|
+ "confirmed" => "Sent",
|
|
|
+ "error" => "Failed to send",
|
|
|
+ _ => "Sending",
|
|
|
+ };
|
|
|
+ action_node.set_property_str(atom, Role::App, "text", text).unwrap();
|
|
|
+
|
|
|
+ // Shadow color follows the tx status
|
|
|
+ let color = match status.as_str() {
|
|
|
+ "confirmed" => [COLOR_GREEN[0], COLOR_GREEN[1], COLOR_GREEN[2], 0.3],
|
|
|
+ "error" => [COLOR_RED[0], COLOR_RED[1], COLOR_RED[2], 0.3],
|
|
|
+ _ => [0., 0., 0., 0.],
|
|
|
+ };
|
|
|
+ let mut shape = VectorShape::new();
|
|
|
+ shape.add_box_shadow_inset(
|
|
|
+ expr::const_f32(0.),
|
|
|
+ expr::const_f32(0.),
|
|
|
+ expr::load_var("w"),
|
|
|
+ expr::load_var("h"),
|
|
|
+ 100.,
|
|
|
+ color,
|
|
|
+ );
|
|
|
+ shadow_node.set_property_shape(atom, Role::App, "shape", shape).unwrap();
|
|
|
+ }
|
|
|
+ })
|
|
|
+ };
|
|
|
+ app.tasks.lock().push(listen_status_text);
|
|
|
+
|
|
|
tx_status_layer
|
|
|
}
|