Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/ui/identities/add_new_identity_screen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1113,7 +1113,12 @@ impl ScreenLike for AddNewIdentityScreen {
.stroke(egui::Stroke::new(1.0, message_color))
.show(ui, |ui| {
ui.horizontal(|ui| {
ui.label(egui::RichText::new(&error_message).color(message_color));
ui.add(
egui::Label::new(
egui::RichText::new(&error_message).color(message_color),
)
.wrap(),
);
ui.add_space(10.0);
if ui.small_button("Dismiss").clicked() {
self.error_message = None;
Expand Down
40 changes: 34 additions & 6 deletions src/ui/identities/keys/key_info_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ use crate::model::qualified_identity::encrypted_key_storage::{
PrivateKeyData, WalletDerivationPath,
};
use crate::model::wallet::Wallet;
use crate::ui::MessageType;
use crate::ui::ScreenLike;
use crate::ui::components::MessageBanner;
use crate::ui::components::info_popup::InfoPopup;
use crate::ui::components::left_panel::add_left_panel;
use crate::ui::components::styled::island_central_panel;
Expand Down Expand Up @@ -256,7 +258,12 @@ impl ScreenLike for KeyInfoScreen {
ui.label(RichText::new(hash_hex).color(text_primary));
}
Err(e) => {
ui.colored_label(egui::Color32::RED, format!("Error: {}", e));
MessageBanner::set_global(
ui.ctx(),
&format!("Error: {}", e),
MessageType::Error,
);
ui.label(RichText::new("Unavailable").color(text_primary));
}
}

Expand All @@ -281,7 +288,12 @@ impl ScreenLike for KeyInfoScreen {
);
}
Err(e) => {
ui.colored_label(egui::Color32::RED, format!("Error: {}", e));
MessageBanner::set_global(
ui.ctx(),
&format!("Error: {}", e),
MessageType::Error,
);
ui.label(RichText::new("Unavailable").color(text_primary));
}
}
}
Expand Down Expand Up @@ -420,14 +432,22 @@ impl ScreenLike for KeyInfoScreen {
self.decrypted_private_key = Some(private_key);
}
Err(e) => {
ui.label(format!("Error: {}", e));
ui.add(
egui::Label::new(format!("Error: {}", e)).wrap(),
);
return;
}
}
}
self.render_sign_input(ui);
} else if self.wallet_open {
ui.colored_label(Color32::DARK_RED, "Key is in encrypted wallet");
ui.add(
egui::Label::new(
egui::RichText::new("Key is in encrypted wallet")
.color(Color32::DARK_RED),
)
.wrap(),
);
ui.add_space(10.0);

if ui.button("View Private Key").clicked() {
Expand Down Expand Up @@ -476,14 +496,22 @@ impl ScreenLike for KeyInfoScreen {
self.decrypted_private_key = Some(private_key);
}
Err(e) => {
ui.label(format!("Error: {}", e));
ui.add(
egui::Label::new(format!("Error: {}", e)).wrap(),
);
return;
}
}
}
self.render_sign_input(ui);
} else {
ui.colored_label(Color32::DARK_RED, "Key is in encrypted wallet");
ui.add(
egui::Label::new(
egui::RichText::new("Key is in encrypted wallet")
.color(Color32::DARK_RED),
)
.wrap(),
);
ui.add_space(10.0);

if ui.button("View Private Key").clicked() {
Expand Down
35 changes: 19 additions & 16 deletions src/ui/identities/register_dpns_name_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::context::AppContext;
use crate::model::fee_estimation::format_credits_as_dash;
use crate::model::qualified_identity::QualifiedIdentity;
use crate::model::wallet::Wallet;
use crate::ui::components::MessageBanner;
use crate::ui::components::identity_selector::IdentitySelector;
use crate::ui::components::left_panel::add_left_panel;
use crate::ui::components::styled::island_central_panel;
Expand Down Expand Up @@ -296,6 +297,11 @@ impl RegisterDpnsNameScreen {
impl ScreenLike for RegisterDpnsNameScreen {
fn display_message(&mut self, message: &str, message_type: MessageType) {
if let MessageType::Error = message_type {
MessageBanner::set_global(
self.app_context.egui_ctx(),
&format!("Error: {}", message),
MessageType::Error,
);
self.register_dpns_name_status =
RegisterDpnsNameStatus::ErrorMessage(message.to_string());
}
Expand All @@ -306,6 +312,12 @@ impl ScreenLike for RegisterDpnsNameScreen {
backend_task_success_result
{
self.completed_fee_result = Some(fee_result);
if let RegisterDpnsNameStatus::ErrorMessage(msg) = &self.register_dpns_name_status {
MessageBanner::clear_global_message(
self.app_context.egui_ctx(),
&format!("Error: {}", msg),
);
}
self.register_dpns_name_status = RegisterDpnsNameStatus::Complete;
}
}
Expand Down Expand Up @@ -589,22 +601,13 @@ impl ScreenLike for RegisterDpnsNameScreen {
));
}
RegisterDpnsNameStatus::ErrorMessage(msg) => {
let error_color = DashColors::ERROR;
let msg = msg.clone();
Frame::new()
.fill(error_color.gamma_multiply(0.1))
.inner_margin(Margin::symmetric(10, 8))
.corner_radius(5.0)
.stroke(egui::Stroke::new(1.0, error_color))
.show(ui, |ui| {
ui.horizontal(|ui| {
ui.label(RichText::new(format!("Error: {}", msg)).color(error_color));
ui.add_space(10.0);
if ui.small_button("Dismiss").clicked() {
self.register_dpns_name_status = RegisterDpnsNameStatus::NotStarted;
}
});
});
let banner_text = format!("Error: {}", msg);
ui.horizontal(|ui| {
if ui.small_button("Dismiss").clicked() {
MessageBanner::clear_global_message(ui.ctx(), &banner_text);
self.register_dpns_name_status = RegisterDpnsNameStatus::NotStarted;
}
});
}
RegisterDpnsNameStatus::Complete => {}
}
Expand Down
1 change: 1 addition & 0 deletions src/ui/identities/top_up_identity_screen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,7 @@ impl ScreenLike for TopUpIdentityScreen {

action |= island_central_panel(ctx, |ui| {
let mut inner_action = AppAction::None;
let _dark_mode = ui.ctx().style().visuals.dark_mode;

ScrollArea::vertical().show(ui, |ui| {
let step = { *self.step.read().unwrap() };
Expand Down
7 changes: 6 additions & 1 deletion src/ui/identities/withdraw_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,12 @@ impl WithdrawalScreen {

// Show error next to input
if let Some(error) = &self.withdrawal_address_error {
ui.colored_label(DashColors::ERROR, error);
ui.add(
egui::Label::new(
egui::RichText::new(error).color(DashColors::ERROR),
)
.wrap(),
);
}
});

Expand Down
67 changes: 49 additions & 18 deletions src/ui/tokens/set_token_price_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::model::amount::{Amount, DASH_DECIMAL_PLACES};
use crate::model::fee_estimation::format_credits_as_dash;
use crate::model::wallet::Wallet;
use crate::ui::components::ComponentResponse;
use crate::ui::components::MessageBanner;
use crate::ui::components::amount_input::AmountInput;
use crate::ui::components::component_trait::Component;
use crate::ui::components::confirmation_dialog::{ConfirmationDialog, ConfirmationStatus};
Expand Down Expand Up @@ -113,6 +114,7 @@ pub struct SetTokenPriceScreen {
// If needed for password-based wallet unlocking:
selected_wallet: Option<Arc<RwLock<Wallet>>>,
wallet_unlock_popup: WalletUnlockPopup,
remove_pricing_warning_posted: bool,
// Fee result from completed operation
completed_fee_result: Option<FeeResult>,
}
Expand Down Expand Up @@ -283,6 +285,7 @@ impl SetTokenPriceScreen {
confirmation_dialog: None,
selected_wallet,
wallet_unlock_popup: WalletUnlockPopup::new(),
remove_pricing_warning_posted: false,
completed_fee_result: None,
}
}
Expand Down Expand Up @@ -340,6 +343,8 @@ impl SetTokenPriceScreen {

/// Renders the pricing input UI
fn render_pricing_input(&mut self, ui: &mut Ui) {
let previous_pricing_type = self.pricing_type.clone();

// Radio buttons for pricing type
ui.horizontal(|ui| {
ui.radio_value(
Expand All @@ -359,6 +364,18 @@ impl SetTokenPriceScreen {
);
});

let remove_pricing_warning = "WARNING: This will remove the pricing schedule, making the token unavailable for direct purchase.";
if self.pricing_type != PricingType::RemovePricing && self.remove_pricing_warning_posted {
MessageBanner::clear_global_message(ui.ctx(), remove_pricing_warning);
self.remove_pricing_warning_posted = false;
}
if self.pricing_type == PricingType::RemovePricing
&& (!self.remove_pricing_warning_posted || self.pricing_type != previous_pricing_type)
{
MessageBanner::set_global(ui.ctx(), remove_pricing_warning, MessageType::Warning);
self.remove_pricing_warning_posted = true;
}

ui.add_space(10.0);

match self.pricing_type {
Expand Down Expand Up @@ -519,7 +536,6 @@ impl SetTokenPriceScreen {
self.render_tiered_pricing_preview(ui);
}
PricingType::RemovePricing => {
ui.colored_label(Color32::from_rgb(180, 100, 0), "WARNING: This will remove the pricing schedule, making the token unavailable for direct purchase.");
ui.label("Users will no longer be able to buy this token directly.");
}
}
Expand Down Expand Up @@ -554,7 +570,13 @@ impl SetTokenPriceScreen {
}

if has_errors {
ui.colored_label(Color32::DARK_RED, "X Some tiers have invalid values");
ui.add(
egui::Label::new(
egui::RichText::new("X Some tiers have invalid values")
.color(Color32::DARK_RED),
)
.wrap(),
);
}

if !valid_tiers.is_empty() {
Expand Down Expand Up @@ -778,6 +800,13 @@ impl SetTokenPriceScreen {
fn set_error_state(&mut self, error: String) {
self.error_message = Some(error.clone());
self.status = SetTokenPriceStatus::ErrorMessage(error);
if let SetTokenPriceStatus::ErrorMessage(ref msg) = self.status {
MessageBanner::set_global(
self.app_context.egui_ctx(),
&format!("Error: {}", msg),
MessageType::Error,
);
}
}

/// Renders a confirm popup with the final "Are you sure?" step
Expand Down Expand Up @@ -822,12 +851,23 @@ impl ScreenLike for SetTokenPriceScreen {
if let MessageType::Error = message_type {
self.status = SetTokenPriceStatus::ErrorMessage(message.to_string());
self.error_message = Some(message.to_string());
MessageBanner::set_global(
self.app_context.egui_ctx(),
&format!("Error: {}", message),
MessageType::Error,
);
}
}

fn display_task_result(&mut self, backend_task_success_result: BackendTaskSuccessResult) {
if let BackendTaskSuccessResult::SetTokenPrice(fee_result) = backend_task_success_result {
self.completed_fee_result = Some(fee_result);
if let SetTokenPriceStatus::ErrorMessage(msg) = &self.status {
MessageBanner::clear_global_message(
self.app_context.egui_ctx(),
&format!("Error: {}", msg),
);
}
self.status = SetTokenPriceStatus::Complete;
}
}
Expand Down Expand Up @@ -1149,22 +1189,13 @@ impl ScreenLike for SetTokenPriceScreen {
ui.label(format!("Setting price... elapsed: {} seconds", elapsed));
}
SetTokenPriceStatus::ErrorMessage(msg) => {
let error_color = DashColors::ERROR;
let msg = msg.clone();
Frame::new()
.fill(error_color.gamma_multiply(0.1))
.inner_margin(Margin::symmetric(10, 8))
.corner_radius(5.0)
.stroke(egui::Stroke::new(1.0, error_color))
.show(ui, |ui| {
ui.horizontal(|ui| {
ui.label(RichText::new(format!("Error: {}", msg)).color(error_color));
ui.add_space(10.0);
if ui.small_button("Dismiss").clicked() {
self.status = SetTokenPriceStatus::NotStarted;
}
});
});
let banner_text = format!("Error: {}", msg);
ui.horizontal(|ui| {
if ui.small_button("Dismiss").clicked() {
MessageBanner::clear_global_message(ui.ctx(), &banner_text);
self.status = SetTokenPriceStatus::NotStarted;
}
});
}
Comment on lines 1191 to 1199
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Error status only shows a dismiss button — no inline error context.

Same pattern as the SK unlock dialog in wallets_screen/mod.rs: the error text is only visible via the global MessageBanner. If the banner is no longer visible (auto-expired, pushed out, or rendered elsewhere), the user sees only a bare dismiss button with no indication of what went wrong.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/ui/tokens/set_token_price_screen.rs` around lines 1191 - 1199, The
ErrorMessage branch for SetTokenPriceStatus currently only renders a Dismiss
button and clears the global MessageBanner, leaving no inline error context;
update the UI in the SetTokenPriceStatus::ErrorMessage(msg) block to show the
error text inline (e.g., render a label with the formatted banner_text)
alongside the Dismiss button within the ui.horizontal closure so users always
see the error even if the global MessageBanner is not visible, while keeping the
existing MessageBanner::clear_global_message call and the transition to
self.status = SetTokenPriceStatus::NotStarted when the button is clicked.

SetTokenPriceStatus::Complete => {
// handled above
Expand Down
7 changes: 6 additions & 1 deletion src/ui/tokens/tokens_screen/keyword_search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,12 @@ impl TokensScreen {
.stroke(egui::Stroke::new(1.0, error_color))
.show(ui, |ui| {
ui.horizontal(|ui| {
ui.label(RichText::new(format!("Error: {}", msg)).color(error_color));
ui.add(
egui::Label::new(
RichText::new(format!("Error: {}", msg)).color(error_color),
)
.wrap(),
);
ui.add_space(10.0);
if ui.small_button("Dismiss").clicked() {
self.contract_search_status = ContractSearchStatus::NotStarted;
Expand Down
29 changes: 26 additions & 3 deletions src/ui/tokens/tokens_screen/token_creator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,16 @@ impl TokensScreen {
Ok(identities) => identities.into_iter().filter(|qi| !qi.private_keys.private_keys.is_empty()).collect::<Vec<_>>(),
Err(e) => {
tracing::error!(err=?e, "Error loading identities from local DB.");
ui.colored_label(Color32::DARK_RED,format!("Error loading identities from local DB: {}", e));
ui.add(
egui::Label::new(
egui::RichText::new(format!(
"Error loading identities from local DB: {}",
e
))
.color(Color32::DARK_RED),
)
.wrap(),
);
return;
}
};
Expand Down Expand Up @@ -547,7 +556,16 @@ impl TokensScreen {
seen_keywords.insert(name.0.clone());
for keyword in contract_keywords.iter() {
if seen_keywords.contains(*keyword) {
ui.colored_label(Color32::DARK_RED, format!("Duplicate contract keyword: {}", keyword));
ui.add(
egui::Label::new(
egui::RichText::new(format!(
"Duplicate contract keyword: {}",
keyword
))
.color(Color32::DARK_RED),
)
.wrap(),
);
}
seen_keywords.insert(keyword.to_string());
}
Expand Down Expand Up @@ -979,7 +997,12 @@ impl TokensScreen {
.stroke(egui::Stroke::new(1.0, error_color))
.show(ui, |ui| {
ui.horizontal(|ui| {
ui.label(RichText::new(format!("Error: {}", err_msg)).color(error_color));
ui.add(
egui::Label::new(
RichText::new(format!("Error: {}", err_msg)).color(error_color),
)
.wrap(),
);
ui.add_space(10.0);
if ui.small_button("Dismiss").clicked() {
self.token_creator_error_message = None;
Expand Down
Loading
Loading