Skip to content

Commit f9f24d3

Browse files
lklimekclaude
andcommitted
refactor(ui): migrate direct Button callsites to ComponentStyles helpers
Supersedes the mechanical ui.add_sized fix from the prior version of this PR. Each primary CTA, tab switcher, and toolbar button that was constructing Button::new(...).fill(...).min_size(...) manually now delegates to the appropriate ComponentStyles helper. Helpers already go through ui.add_sized after 8428fb3, so the centering bug is fixed at the source — callsites stop carrying the boilerplate. Accepts the DIALOG_BUTTON_MIN_SIZE (96×36) default for every callsite; the custom widths (120×28 tabs, 160×36 send, 150×36 toolbar) are dropped in favor of one source of truth. Migrations by bucket: - Primary CTA (add_primary_button / add_primary_button_enabled): dashpay/mod.rs, my_tokens.rs (Import/Refresh), token_creator.rs (Load Identity / Create Token / Register Token Contract / View JSON), top_up by_platform_address.rs, send_screen.rs (2 sends), single_key_send_screen.rs, withdraw_screen.rs, network_chooser (Connect). - Danger (add_danger_button): network_chooser Disconnect. - Tab switch (primary/secondary swap): contacts_list.rs, contact_requests.rs, transfer_screen.rs. - Bucket 7 (custom glass-panel styling — keep direct Button, drop .min_size and add_sized, plain ui.add): the 4 *_subscreen_chooser panels and grovestark_screen mode tabs. Also adds a kittest suite (tests/kittest/button_sizing.rs) that verifies the helpers do NOT cap button max width — long labels ("Register Token Contract") grow beyond the 96px floor; short labels ("OK") stay at the floor. This locks in the correct semantics of ui.add_sized: it treats its arg as a MAX, but egui's horizontal layout expands frame_size to max(desired, available) in next_frame_ignore_wrap, so content overflows upward rather than clipping. Future reviewers can rerun the tests instead of re-reading egui internals. Net diff: 17 files, -214 lines. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 8428fb3 commit f9f24d3

18 files changed

Lines changed: 200 additions & 304 deletions

src/ui/components/dashpay_subscreen_chooser_panel.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ pub fn add_dashpay_subscreen_chooser_panel(
7070
.fill(DashColors::DASH_BLUE)
7171
.stroke(egui::Stroke::NONE)
7272
.corner_radius(egui::CornerRadius::same(Shape::RADIUS_MD))
73-
.min_size(egui::Vec2::new(150.0, 28.0))
7473
} else {
7574
egui::Button::new(
7675
RichText::new(display_name)
@@ -80,7 +79,6 @@ pub fn add_dashpay_subscreen_chooser_panel(
8079
.fill(DashColors::glass_white(dark_mode))
8180
.stroke(egui::Stroke::new(1.0, DashColors::border(dark_mode)))
8281
.corner_radius(egui::CornerRadius::same(Shape::RADIUS_MD))
83-
.min_size(egui::Vec2::new(150.0, 28.0))
8482
};
8583

8684
// Show the subscreen name as a clickable option

src/ui/components/dpns_subscreen_chooser_panel.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ pub fn add_dpns_subscreen_chooser_panel(ctx: &Context, app_context: &AppContext)
6161
.fill(DashColors::DASH_BLUE)
6262
.stroke(egui::Stroke::NONE)
6363
.corner_radius(egui::CornerRadius::same(Shape::RADIUS_MD))
64-
.min_size(egui::Vec2::new(150.0, 28.0))
6564
} else {
6665
egui::Button::new(
6766
RichText::new(subscreen.display_name())
@@ -71,7 +70,6 @@ pub fn add_dpns_subscreen_chooser_panel(ctx: &Context, app_context: &AppContext)
7170
.fill(DashColors::glass_white(dark_mode))
7271
.stroke(egui::Stroke::new(1.0, DashColors::border(dark_mode)))
7372
.corner_radius(egui::CornerRadius::same(Shape::RADIUS_MD))
74-
.min_size(egui::Vec2::new(150.0, 28.0))
7573
};
7674

7775
// Show the subscreen name as a clickable option

src/ui/components/tokens_subscreen_chooser_panel.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ pub fn add_tokens_subscreen_chooser_panel(ctx: &Context, app_context: &AppContex
6060
.fill(DashColors::DASH_BLUE)
6161
.stroke(egui::Stroke::NONE)
6262
.corner_radius(egui::CornerRadius::same(Shape::RADIUS_MD))
63-
.min_size(egui::Vec2::new(150.0, 28.0))
6463
} else {
6564
egui::Button::new(
6665
RichText::new(subscreen.display_name())
@@ -70,7 +69,6 @@ pub fn add_tokens_subscreen_chooser_panel(ctx: &Context, app_context: &AppContex
7069
.fill(DashColors::glass_white(dark_mode))
7170
.stroke(egui::Stroke::new(1.0, DashColors::border(dark_mode)))
7271
.corner_radius(egui::CornerRadius::same(Shape::RADIUS_MD))
73-
.min_size(egui::Vec2::new(150.0, 28.0))
7472
};
7573

7674
// Show the subscreen name as a clickable option

src/ui/components/tools_subscreen_chooser_panel.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ pub fn add_tools_subscreen_chooser_panel(ctx: &Context, app_context: &AppContext
128128
.fill(DashColors::DASH_BLUE)
129129
.stroke(egui::Stroke::NONE)
130130
.corner_radius(egui::CornerRadius::same(Shape::RADIUS_MD))
131-
.min_size(egui::Vec2::new(150.0, 28.0))
132131
} else {
133132
egui::Button::new(
134133
RichText::new(subscreen.display_name())
@@ -138,7 +137,6 @@ pub fn add_tools_subscreen_chooser_panel(ctx: &Context, app_context: &AppContext
138137
.fill(DashColors::glass_white(dark_mode))
139138
.stroke(egui::Stroke::new(1.0, DashColors::border(dark_mode)))
140139
.corner_radius(egui::CornerRadius::same(Shape::RADIUS_MD))
141-
.min_size(egui::Vec2::new(150.0, 28.0))
142140
};
143141

144142
// Show the subscreen name as a clickable option. Disable

src/ui/dashpay/contact_requests.rs

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::ui::components::wallet_unlock_popup::{
1414
use crate::ui::components::{MessageBanner, ResultBannerExt};
1515
use crate::ui::identities::get_selected_wallet;
1616
use crate::ui::identities::keys::add_key_screen::AddKeyScreen;
17-
use crate::ui::theme::DashColors;
17+
use crate::ui::theme::{ComponentStyles, DashColors};
1818
use crate::ui::{MessageType, Screen, ScreenLike, ScreenType};
1919
use dash_sdk::dpp::document::DocumentV0Getters;
2020
use dash_sdk::dpp::identity::accessors::IdentityGettersV0;
@@ -650,53 +650,23 @@ impl ContactRequests {
650650
// Tabs
651651
let dark_mode = ui.ctx().style().visuals.dark_mode;
652652
ui.horizontal(|ui| {
653-
let incoming_tab = egui::Button::new(RichText::new("Incoming").color(
654-
if self.active_tab == RequestTab::Incoming {
655-
DashColors::WHITE
656-
} else {
657-
DashColors::text_primary(dark_mode)
658-
},
659-
))
660-
.fill(if self.active_tab == RequestTab::Incoming {
661-
DashColors::DASH_BLUE
662-
} else {
663-
DashColors::glass_white(dark_mode)
664-
})
665-
.stroke(if self.active_tab == RequestTab::Incoming {
666-
egui::Stroke::NONE
653+
let incoming_response = if self.active_tab == RequestTab::Incoming {
654+
ComponentStyles::add_primary_button(ui, "Incoming")
667655
} else {
668-
egui::Stroke::new(1.0, DashColors::border(dark_mode))
669-
})
670-
.corner_radius(egui::CornerRadius::same(4))
671-
.min_size(egui::Vec2::new(120.0, 28.0));
672-
673-
if ui.add(incoming_tab).clicked() {
656+
ComponentStyles::add_secondary_button(ui, "Incoming", dark_mode)
657+
};
658+
if incoming_response.clicked() {
674659
self.active_tab = RequestTab::Incoming;
675660
}
676661

677662
ui.add_space(8.0);
678663

679-
let outgoing_tab = egui::Button::new(RichText::new("Outgoing").color(
680-
if self.active_tab == RequestTab::Outgoing {
681-
DashColors::WHITE
682-
} else {
683-
DashColors::text_primary(dark_mode)
684-
},
685-
))
686-
.fill(if self.active_tab == RequestTab::Outgoing {
687-
DashColors::DASH_BLUE
688-
} else {
689-
DashColors::glass_white(dark_mode)
690-
})
691-
.stroke(if self.active_tab == RequestTab::Outgoing {
692-
egui::Stroke::NONE
664+
let outgoing_response = if self.active_tab == RequestTab::Outgoing {
665+
ComponentStyles::add_primary_button(ui, "Outgoing")
693666
} else {
694-
egui::Stroke::new(1.0, DashColors::border(dark_mode))
695-
})
696-
.corner_radius(egui::CornerRadius::same(4))
697-
.min_size(egui::Vec2::new(120.0, 28.0));
698-
699-
if ui.add(outgoing_tab).clicked() {
667+
ComponentStyles::add_secondary_button(ui, "Outgoing", dark_mode)
668+
};
669+
if outgoing_response.clicked() {
700670
self.active_tab = RequestTab::Outgoing;
701671
}
702672
});

src/ui/dashpay/contacts_list.rs

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::ui::components::ResultBannerExt;
88
use crate::ui::components::identity_selector::IdentitySelector;
99
use crate::ui::components::wallet_unlock_popup::WalletUnlockResult;
1010
use crate::ui::dashpay::contact_requests::ContactRequests;
11-
use crate::ui::theme::DashColors;
11+
use crate::ui::theme::{ComponentStyles, DashColors};
1212
use crate::ui::{MessageType, ScreenLike, ScreenType};
1313
use dash_sdk::dpp::identity::accessors::IdentityGettersV0;
1414
use dash_sdk::dpp::platform_value::string_encoding::Encoding;
@@ -341,27 +341,12 @@ impl ContactsList {
341341

342342
// Tab bar
343343
ui.horizontal(|ui| {
344-
let contacts_tab = egui::Button::new(RichText::new("My Contacts").color(
345-
if self.active_tab == ContactsTab::Contacts {
346-
DashColors::WHITE
347-
} else {
348-
DashColors::text_primary(dark_mode)
349-
},
350-
))
351-
.fill(if self.active_tab == ContactsTab::Contacts {
352-
DashColors::DASH_BLUE
353-
} else {
354-
DashColors::glass_white(dark_mode)
355-
})
356-
.stroke(if self.active_tab == ContactsTab::Contacts {
357-
egui::Stroke::NONE
344+
let contacts_response = if self.active_tab == ContactsTab::Contacts {
345+
ComponentStyles::add_primary_button(ui, "My Contacts")
358346
} else {
359-
egui::Stroke::new(1.0, DashColors::border(dark_mode))
360-
})
361-
.corner_radius(egui::CornerRadius::same(4))
362-
.min_size(egui::Vec2::new(120.0, 28.0));
363-
364-
if ui.add(contacts_tab).clicked() {
347+
ComponentStyles::add_secondary_button(ui, "My Contacts", dark_mode)
348+
};
349+
if contacts_response.clicked() {
365350
self.active_tab = ContactsTab::Contacts;
366351
}
367352

@@ -375,27 +360,12 @@ impl ContactsList {
375360
"Requests".to_string()
376361
};
377362

378-
let requests_tab = egui::Button::new(RichText::new(requests_label).color(
379-
if self.active_tab == ContactsTab::Requests {
380-
DashColors::WHITE
381-
} else {
382-
DashColors::text_primary(dark_mode)
383-
},
384-
))
385-
.fill(if self.active_tab == ContactsTab::Requests {
386-
DashColors::DASH_BLUE
387-
} else {
388-
DashColors::glass_white(dark_mode)
389-
})
390-
.stroke(if self.active_tab == ContactsTab::Requests {
391-
egui::Stroke::NONE
363+
let requests_response = if self.active_tab == ContactsTab::Requests {
364+
ComponentStyles::add_primary_button(ui, requests_label)
392365
} else {
393-
egui::Stroke::new(1.0, DashColors::border(dark_mode))
394-
})
395-
.corner_radius(egui::CornerRadius::same(4))
396-
.min_size(egui::Vec2::new(120.0, 28.0));
397-
398-
if ui.add(requests_tab).clicked() {
366+
ComponentStyles::add_secondary_button(ui, requests_label, dark_mode)
367+
};
368+
if requests_response.clicked() {
399369
self.active_tab = ContactsTab::Requests;
400370
}
401371
});

src/ui/dashpay/mod.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub use profile_search::ProfileSearchScreen;
1818
use crate::app::AppAction;
1919
use crate::context::AppContext;
2020
use crate::ui::ScreenType;
21-
use crate::ui::theme::DashColors;
21+
use crate::ui::theme::{ComponentStyles, DashColors};
2222
use chrono::{LocalResult, TimeZone, Utc};
2323
use chrono_humanize::HumanTime;
2424

@@ -94,15 +94,7 @@ pub fn render_no_identities_card(ui: &mut Ui, app_context: &Arc<AppContext>) ->
9494

9595
ui.add_space(15.0);
9696

97-
let button = egui::Button::new(
98-
RichText::new("Load Identity")
99-
.color(egui::Color32::WHITE)
100-
.strong(),
101-
)
102-
.fill(DashColors::DASH_BLUE)
103-
.min_size(egui::vec2(150.0, 36.0));
104-
105-
if ui.add(button).clicked() {
97+
if ComponentStyles::add_primary_button(ui, "Load Identity").clicked() {
10698
return AppAction::AddScreen(
10799
ScreenType::AddExistingIdentity.create_screen(app_context),
108100
);

src/ui/identities/top_up_identity_screen/by_platform_address.rs

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::ui::components::MessageBanner;
99
use crate::ui::components::amount_input::AmountInput;
1010
use crate::ui::components::component_trait::{Component, ComponentResponse};
1111
use crate::ui::identities::funding_common::WalletFundedScreenStep;
12-
use crate::ui::theme::DashColors;
12+
use crate::ui::theme::{ComponentStyles, DashColors};
1313
use dash_sdk::dpp::address_funds::PlatformAddress;
1414
use dash_sdk::dpp::balances::credits::Credits;
1515
use dash_sdk::dpp::dashcore::Address;
@@ -183,19 +183,7 @@ impl TopUpIdentityScreen {
183183
_ => "Top Up Identity",
184184
};
185185

186-
let button = egui::Button::new(
187-
RichText::new(button_text)
188-
.color(egui::Color32::WHITE)
189-
.strong(),
190-
)
191-
.fill(if can_top_up {
192-
DashColors::DASH_BLUE
193-
} else {
194-
DashColors::DASH_BLUE.gamma_multiply(0.5)
195-
})
196-
.min_size(egui::vec2(120.0, 36.0));
197-
198-
if ui.add_enabled(can_top_up, button).clicked() {
186+
if ComponentStyles::add_primary_button_enabled(ui, can_top_up, button_text).clicked() {
199187
match self.validate_and_top_up_from_platform() {
200188
Ok(top_up_action) => {
201189
action = top_up_action;

src/ui/identities/transfer_screen.rs

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use crate::ui::components::wallet_unlock_popup::{
3636
WalletUnlockPopup, WalletUnlockResult, try_open_wallet_no_password, wallet_needs_unlock,
3737
};
3838
use crate::ui::helpers::{TransactionType, add_key_chooser};
39-
use crate::ui::theme::{DashColors, ResponseExt};
39+
use crate::ui::theme::{ComponentStyles, DashColors, ResponseExt};
4040

4141
/// Transfer destination type
4242
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
@@ -183,12 +183,6 @@ impl TransferScreen {
183183
fn render_destination_type_selector(&mut self, ui: &mut Ui) {
184184
let dark_mode = ui.ctx().style().visuals.dark_mode;
185185

186-
// Colors for selected/unselected states
187-
let selected_fill = DashColors::DASH_BLUE;
188-
let selected_text = Color32::WHITE;
189-
let unselected_fill = DashColors::unselected_fill(dark_mode);
190-
let unselected_text = DashColors::text_primary(dark_mode);
191-
192186
ui.horizontal(|ui| {
193187
ui.vertical(|ui| {
194188
ui.add_space(5.0);
@@ -198,23 +192,12 @@ impl TransferScreen {
198192

199193
// Identity button
200194
let identity_selected = self.destination_type == TransferDestinationType::Identity;
201-
let identity_button = egui::Button::new(
202-
RichText::new("Identity")
203-
.color(if identity_selected {
204-
selected_text
205-
} else {
206-
unselected_text
207-
})
208-
.strong(),
209-
)
210-
.fill(if identity_selected {
211-
selected_fill
195+
let identity_response = if identity_selected {
196+
ComponentStyles::add_primary_button(ui, "Identity")
212197
} else {
213-
unselected_fill
214-
})
215-
.min_size(egui::vec2(120.0, 28.0));
216-
217-
if ui.add(identity_button).clicked() {
198+
ComponentStyles::add_secondary_button(ui, "Identity", dark_mode)
199+
};
200+
if identity_response.clicked() {
218201
self.destination_type = TransferDestinationType::Identity;
219202
}
220203

@@ -223,23 +206,12 @@ impl TransferScreen {
223206
// Platform Address button
224207
let platform_selected =
225208
self.destination_type == TransferDestinationType::PlatformAddress;
226-
let platform_button = egui::Button::new(
227-
RichText::new("Platform Address")
228-
.color(if platform_selected {
229-
selected_text
230-
} else {
231-
unselected_text
232-
})
233-
.strong(),
234-
)
235-
.fill(if platform_selected {
236-
selected_fill
209+
let platform_response = if platform_selected {
210+
ComponentStyles::add_primary_button(ui, "Platform Address")
237211
} else {
238-
unselected_fill
239-
})
240-
.min_size(egui::vec2(140.0, 28.0));
241-
242-
if ui.add(platform_button).clicked() {
212+
ComponentStyles::add_secondary_button(ui, "Platform Address", dark_mode)
213+
};
214+
if platform_response.clicked() {
243215
self.destination_type = TransferDestinationType::PlatformAddress;
244216
}
245217
});

src/ui/identities/withdraw_screen.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::ui::components::wallet_unlock_popup::{
1818
use crate::ui::components::{BannerHandle, MessageBanner, OptionBannerExt, ResultBannerExt};
1919
use crate::ui::components::{Component, ComponentResponse};
2020
use crate::ui::helpers::{TransactionType, add_key_chooser};
21-
use crate::ui::theme::{DashColors, ResponseExt};
21+
use crate::ui::theme::{ComponentStyles, DashColors, ResponseExt};
2222
use crate::ui::{MessageType, Screen, ScreenLike};
2323
use dash_sdk::dashcore_rpc::dashcore::{Address, Network};
2424
use dash_sdk::dpp::fee::Credits;
@@ -597,13 +597,6 @@ impl ScreenLike for WithdrawalScreen {
597597
ui.add_space(10.0);
598598

599599
// Withdraw button
600-
601-
let button = egui::Button::new(RichText::new("Withdraw").color(Color32::WHITE))
602-
.fill(DashColors::DASH_BLUE)
603-
.frame(true)
604-
.corner_radius(3.0)
605-
.min_size(egui::vec2(60.0, 30.0));
606-
607600
let has_valid_amount = self.withdrawal_amount.is_some();
608601
let has_address_error = self.withdrawal_address_error.is_some();
609602
let has_enough_balance = self.max_amount > estimated_fee;
@@ -622,8 +615,7 @@ impl ScreenLike for WithdrawalScreen {
622615
String::new()
623616
};
624617

625-
if ui
626-
.add_enabled(ready, button)
618+
if ComponentStyles::add_primary_button_enabled(ui, ready, "Withdraw")
627619
.disabled_tooltip(&hover_text)
628620
.clicked()
629621
&& self.confirmation_dialog.is_none()

0 commit comments

Comments
 (0)