Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
2 changes: 1 addition & 1 deletion src/backend_task/system_task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ impl AppContext {
theme_mode: ThemeMode,
) -> Result<BackendTaskSuccessResult, String> {
let _guard = self.invalidate_settings_cache();

self.db
.update_theme_preference(theme_mode)
.map_err(|e| e.to_string())?;
Expand Down
60 changes: 47 additions & 13 deletions src/ui/components/amount_input.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::model::amount::Amount;
use crate::ui::components::{Component, ComponentResponse};
use dash_sdk::dpp::balances::credits::MAX_CREDITS;
use dash_sdk::dpp::fee::Credits;
use egui::{InnerResponse, Response, TextEdit, Ui, Vec2, WidgetText};

Expand Down Expand Up @@ -113,12 +114,12 @@ impl AmountInput {
unit_name: amount.unit_name().map(|s| s.to_string()),
label: None,
hint_text: None,
max_amount: None,
max_amount: Some(MAX_CREDITS),
min_amount: Some(1), // Default minimum is 1 (greater than zero)
show_max_button: false,
desired_width: None,
show_validation_errors: true, // Default to showing validation errors
changed: false,
changed: true, // Start as changed to force initial validation
}
}

Expand All @@ -135,13 +136,22 @@ impl AmountInput {
self.decimal_places
}

/// Sets decimal places for the input, preserving displayed value. Intristic value will be multiplied by 10^n,
/// where n is difference between new and old decimal places.
pub fn set_decimal_places(&mut self, decimal_places: u8) -> &mut Self {
self.decimal_places = decimal_places;
self.changed = true;

self
}
Comment thread
pauldelucia marked this conversation as resolved.
Outdated

/// Gets the unit name this input is configured for.
pub fn unit_name(&self) -> Option<&str> {
self.unit_name.as_deref()
}

/// Sets the label for the input field.
pub fn label<T: Into<WidgetText>>(mut self, label: T) -> Self {
pub fn with_label<T: Into<WidgetText>>(mut self, label: T) -> Self {
self.label = Some(label.into());
self
}
Expand All @@ -153,8 +163,19 @@ impl AmountInput {
self
}

/// Sets value of the input field.
///
/// This will update the internal state and mark the component as changed.
pub fn set_value(&mut self, value: Amount) -> &mut Self {
self.amount_str = value.to_string_without_unit();
self.decimal_places = value.decimal_places();
self.unit_name = value.unit_name().map(|s| s.to_string());
self.changed = true; // Mark as changed to trigger validation
self
}

/// Sets the hint text for the input field.
pub fn hint_text<T: Into<WidgetText>>(mut self, hint_text: T) -> Self {
pub fn with_hint_text<T: Into<WidgetText>>(mut self, hint_text: T) -> Self {
self.hint_text = Some(hint_text.into());
self
}
Expand All @@ -167,21 +188,25 @@ impl AmountInput {

/// Sets the maximum amount allowed. If provided, a "Max" button will be shown
/// when `show_max_button` is true.
pub fn max_amount(mut self, max_amount: Option<Credits>) -> Self {
///
/// Defaults to [`MAX_CREDITS`](dash_sdk::dpp::balances::credits::MAX_CREDITS).
pub fn with_max_amount(mut self, max_amount: Option<Credits>) -> Self {
self.max_amount = max_amount;
self
}

/// Sets the maximum amount allowed (mutable reference version).
/// Use this for dynamic configuration when the max amount changes at runtime (e.g., balance updates).
///
/// Defaults to [`MAX_CREDITS`](dash_sdk::dpp::balances::credits::MAX_CREDITS).
pub fn set_max_amount(&mut self, max_amount: Option<Credits>) -> &mut Self {
self.max_amount = max_amount;
self
}

/// Sets the minimum amount allowed. Defaults to 1 (must be greater than zero).
/// Set to Some(0) to allow zero amounts, or None to disable minimum validation.
pub fn min_amount(mut self, min_amount: Option<Credits>) -> Self {
pub fn with_min_amount(mut self, min_amount: Option<Credits>) -> Self {
self.min_amount = min_amount;
self
}
Expand All @@ -193,7 +218,7 @@ impl AmountInput {
}

/// Whether to show a "Max" button that sets the amount to the maximum.
pub fn max_button(mut self, show: bool) -> Self {
pub fn with_max_button(mut self, show: bool) -> Self {
self.show_max_button = show;
self
}
Expand All @@ -205,7 +230,7 @@ impl AmountInput {
}

/// Sets the desired width of the input field.
pub fn desired_width(mut self, width: f32) -> Self {
pub fn with_desired_width(mut self, width: f32) -> Self {
self.desired_width = Some(width);
self
}
Expand Down Expand Up @@ -343,6 +368,15 @@ impl Component for AmountInput {
fn show(&mut self, ui: &mut Ui) -> InnerResponse<Self::Response> {
AmountInput::show_internal(self, ui)
}

fn current_value(&self) -> Option<Self::DomainType> {
// Validate the current amount string and return the parsed amount
match self.validate_amount() {
Ok(Some(amount)) => Some(amount),
Ok(None) => None, // Empty input
Err(_) => None, // Invalid input returns None
}
}
}

#[cfg(test)]
Expand Down Expand Up @@ -382,15 +416,15 @@ mod tests {
assert_eq!(input.min_amount, Some(1));

// Custom minimum
let input = AmountInput::new(Amount::new(0, 8)).min_amount(Some(1000));
let input = AmountInput::new(Amount::new(0, 8)).with_min_amount(Some(1000));
assert_eq!(input.min_amount, Some(1000));

// Allow zero
let input = AmountInput::new(Amount::new(0, 8)).min_amount(Some(0));
let input = AmountInput::new(Amount::new(0, 8)).with_min_amount(Some(0));
assert_eq!(input.min_amount, Some(0));

// No minimum
let input = AmountInput::new(Amount::new(0, 8)).min_amount(None);
let input = AmountInput::new(Amount::new(0, 8)).with_min_amount(None);
assert_eq!(input.min_amount, None);
}

Expand Down Expand Up @@ -478,8 +512,8 @@ mod tests {
fn test_min_max_validation() {
let amount = Amount::new(0, 2);
let mut input = AmountInput::new(amount)
.min_amount(Some(100)) // Minimum 1.00
.max_amount(Some(10000)); // Maximum 100.00
.with_min_amount(Some(100)) // Minimum 1.00
.with_max_amount(Some(10000)); // Maximum 100.00

// Test amount below minimum
input.amount_str = "0.50".to_string(); // 50 (below min of 100)
Expand Down
9 changes: 9 additions & 0 deletions src/ui/components/component_trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,13 @@ pub trait Component {
/// An [`InnerResponse`] containing the component's response data in [`InnerResponse::inner`] field.
/// [`InnerResponse::inner`] should implement [`ComponentResponse`] trait.
fn show(&mut self, ui: &mut Ui) -> InnerResponse<Self::Response>;

/// Returns the current value of the component.
///
/// This method is an equivalent of binding some variable using [`ComponentResponse::update()`].
///
/// ## See also
///
/// See [`ComponentResponse::update`].
fn current_value(&self) -> Option<Self::DomainType>;
}
4 changes: 3 additions & 1 deletion src/ui/contracts_documents/group_actions_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,9 @@ impl GroupActionsScreen {
}
TokenEvent::ChangePriceForDirectPurchase(schedule, note_opt) => {
let mut change_price_screen =
SetTokenPriceScreen::new(identity_token_info, &self.app_context);
SetTokenPriceScreen::new(identity_token_info, &self.app_context)
.with_schedule(schedule.clone());

change_price_screen.group_action_id = Some(action_id);
change_price_screen.token_pricing_schedule = format!("{:?}", schedule);
change_price_screen.public_note = note_opt.clone();
Expand Down
6 changes: 3 additions & 3 deletions src/ui/identities/transfer_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ impl TransferScreen {

let amount_input = self.amount_input.get_or_insert_with(|| {
AmountInput::new(Amount::new_dash(0.0))
.label("Amount:")
.max_button(true)
.max_amount(Some(max_amount_credits))
.with_label("Amount:")
.with_max_button(true)
.with_max_amount(Some(max_amount_credits))
});

// Check if input should be disabled when operation is in progress
Expand Down
4 changes: 2 additions & 2 deletions src/ui/identities/withdraw_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ impl WithdrawalScreen {
// Lazy initialization with basic configuration
let amount_input = self.withdrawal_amount_input.get_or_insert_with(|| {
AmountInput::new(Amount::new_dash(0.0))
.label("Amount:")
.max_button(true)
.with_label("Amount:")
.with_max_button(true)
});

// Check if input should be disabled when operation is in progress
Expand Down
Loading