diff --git a/src/gui/views/network/connections.rs b/src/gui/views/network/connections.rs index f299f9c..bc9f8cc 100644 --- a/src/gui/views/network/connections.rs +++ b/src/gui/views/network/connections.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Align, Id, Layout, RichText, Rounding, TextStyle, Widget}; +use egui::{Align, Id, Layout, RichText, Rounding}; use url::Url; use crate::AppConfig; @@ -20,7 +20,7 @@ use crate::gui::Colors; use crate::gui::icons::{CARET_RIGHT, CHECK_CIRCLE, COMPUTER_TOWER, DOTS_THREE_CIRCLE, PENCIL, POWER, TRASH, X_CIRCLE}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, NodeSetup, View}; -use crate::gui::views::types::{ModalContainer, ModalPosition}; +use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions}; use crate::node::{Node, NodeConfig}; use crate::wallet::{ConnectionsConfig, ExternalConnection}; @@ -133,12 +133,12 @@ impl ConnectionsContent { if !Node::is_running() { // Draw button to start integrated node. - View::item_button(ui, Rounding::none(), POWER, Some(Colors::GREEN), || { + View::item_button(ui, Rounding::default(), POWER, Some(Colors::GREEN), || { Node::start(); }); } else if !Node::is_starting() && !Node::is_stopping() && !Node::is_restarting() { // Draw button to open closed wallet. - View::item_button(ui, Rounding::none(), POWER, Some(Colors::RED), || { + View::item_button(ui, Rounding::default(), POWER, Some(Colors::RED), || { Node::stop(false); }); } @@ -197,7 +197,7 @@ impl ConnectionsContent { View::item_button(ui, button_rounding, TRASH, None, || { ConnectionsConfig::remove_ext_conn(conn.id); }); - View::item_button(ui, Rounding::none(), PENCIL, None, || { + View::item_button(ui, Rounding::default(), PENCIL, None, || { self.show_add_ext_conn_modal(Some(conn), cb); }); } @@ -267,20 +267,13 @@ impl ConnectionsContent { ui.add_space(8.0); // Draw node URL text edit. - let url_edit_resp = egui::TextEdit::singleline(&mut self.ext_node_url_edit) - .id(Id::from(modal.id).with(self.ext_conn_id_edit)) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .ui(ui); - ui.add_space(8.0); + let url_edit_id = Id::from(modal.id).with(self.ext_conn_id_edit); + let mut url_edit_opts = TextEditOptions::new(url_edit_id).paste().no_focus(); if self.first_modal_launch { self.first_modal_launch = false; - url_edit_resp.request_focus(); - } - if url_edit_resp.clicked() { - cb.show_keyboard(); + url_edit_opts.focus = true; } + View::text_edit(ui, cb, &mut self.ext_node_url_edit, url_edit_opts); ui.label(RichText::new(t!("wallets.node_secret")) .size(17.0) @@ -288,20 +281,13 @@ impl ConnectionsContent { ui.add_space(8.0); // Draw node API secret text edit. - let secret_edit_resp = egui::TextEdit::singleline(&mut self.ext_node_secret_edit) - .id(Id::from(modal.id).with("node_secret_edit")) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .ui(ui); - ui.add_space(8.0); - if secret_edit_resp.clicked() { - cb.show_keyboard(); - } + let secret_edit_id = Id::from(modal.id).with(self.ext_conn_id_edit).with("node_secret"); + let secret_edit_opts = TextEditOptions::new(secret_edit_id).paste().no_focus(); + View::text_edit(ui, cb, &mut self.ext_node_secret_edit, secret_edit_opts); // Show error when specified URL is not valid. if self.ext_node_url_error { - ui.add_space(2.0); + ui.add_space(12.0); ui.label(RichText::new(t!("wallets.invalid_url")) .size(17.0) .color(Colors::RED)); diff --git a/src/gui/views/network/setup/dandelion.rs b/src/gui/views/network/setup/dandelion.rs index 3da6257..f0c4c28 100644 --- a/src/gui/views/network/setup/dandelion.rs +++ b/src/gui/views/network/setup/dandelion.rs @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Id, RichText, TextStyle, Widget}; +use egui::{Id, RichText}; use crate::gui::Colors; use crate::gui::icons::{CLOCK_COUNTDOWN, GRAPH, TIMER, WATCH}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, View}; use crate::gui::views::network::settings::NetworkSettings; -use crate::gui::views::types::{ModalContainer, ModalPosition}; +use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions}; use crate::node::NodeConfig; /// Dandelion server setup section content. @@ -165,16 +165,8 @@ impl DandelionSetup { ui.add_space(8.0); // Draw epoch text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.epoch_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(52.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let epoch_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.epoch_edit, epoch_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.epoch_edit.parse::().is_err() { @@ -250,16 +242,8 @@ impl DandelionSetup { ui.add_space(8.0); // Draw embargo text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.embargo_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(52.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let embargo_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.embargo_edit, embargo_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.embargo_edit.parse::().is_err() { @@ -335,16 +319,8 @@ impl DandelionSetup { ui.add_space(8.0); // Draw aggregation period text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.aggregation_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(42.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let aggregation_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.aggregation_edit, aggregation_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.aggregation_edit.parse::().is_err() { @@ -420,16 +396,8 @@ impl DandelionSetup { ui.add_space(8.0); // Draw stem phase probability text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.stem_prob_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(42.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let stem_prob_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.stem_prob_edit, stem_prob_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.stem_prob_edit.parse::().is_err() { diff --git a/src/gui/views/network/setup/node.rs b/src/gui/views/network/setup/node.rs index 8d21fcc..37ad76e 100644 --- a/src/gui/views/network/setup/node.rs +++ b/src/gui/views/network/setup/node.rs @@ -12,17 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Id, RichText, TextStyle, Widget}; -use egui_extras::{Size, StripBuilder}; +use egui::{Id, RichText}; use grin_core::global::ChainTypes; use crate::AppConfig; use crate::gui::Colors; -use crate::gui::icons::{CLIPBOARD_TEXT, CLOCK_CLOCKWISE, COMPUTER_TOWER, COPY, PLUG, POWER, SHIELD, SHIELD_SLASH}; +use crate::gui::icons::{CLOCK_CLOCKWISE, COMPUTER_TOWER, PLUG, POWER, SHIELD, SHIELD_SLASH}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, NetworkContent, View}; use crate::gui::views::network::settings::NetworkSettings; -use crate::gui::views::types::{ModalContainer, ModalPosition}; +use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions}; use crate::node::{Node, NodeConfig}; /// Integrated node general setup section content. @@ -286,15 +285,8 @@ impl NodeSetup { ui.add_space(6.0); // Draw API port text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.api_port_edit) - .font(TextStyle::Heading) - .desired_width(64.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let api_port_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.api_port_edit, api_port_edit_opts); // Show error when specified port is unavailable or reminder to restart enabled node. if !self.api_port_available_edit { @@ -390,49 +382,11 @@ impl NodeSetup { }; ui.label(RichText::new(description).size(17.0).color(Colors::GRAY)); ui.add_space(8.0); - StripBuilder::new(ui) - .size(Size::exact(42.0)) - .vertical(|mut strip| { - strip.strip(|builder| { - builder - .size(Size::remainder()) - .size(Size::exact(48.0)) - .size(Size::exact(48.0)) - .horizontal(|mut strip| { - strip.cell(|ui| { - ui.add_space(2.0); - // Draw API secret token value text edit. - let edit = egui::TextEdit::singleline(&mut self.secret_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Button) - .cursor_at_end(true) - .ui(ui); - edit.request_focus(); - if edit.clicked() { - cb.show_keyboard(); - } - }); - strip.cell(|ui| { - ui.vertical_centered(|ui| { - // Draw copy button. - let copy_icon = COPY.to_string(); - View::button(ui, copy_icon, Colors::WHITE, || { - cb.copy_string_to_buffer(self.secret_edit.clone()); - }); - }); - }); - strip.cell(|ui| { - ui.vertical_centered(|ui| { - // Draw paste button. - let paste_icon = CLIPBOARD_TEXT.to_string(); - View::button(ui, paste_icon, Colors::WHITE, || { - self.secret_edit = cb.get_string_from_buffer(); - }); - }); - }); - }); - }) - }); + + // Draw API secret token value text edit. + let secret_edit_opts = TextEditOptions::new(Id::from(modal.id)).copy().paste(); + View::text_edit(ui, cb, &mut self.secret_edit, secret_edit_opts); + ui.add_space(6.0); // Show reminder to restart enabled node. if Node::is_running() { @@ -440,7 +394,7 @@ impl NodeSetup { .size(16.0) .color(Colors::GREEN) ); - ui.add_space(8.0); + ui.add_space(6.0); } ui.add_space(4.0); }); @@ -516,16 +470,8 @@ impl NodeSetup { ui.add_space(8.0); // Draw ftl value text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.ftl_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(52.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let ftl_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.ftl_edit, ftl_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.ftl_edit.parse::().is_err() { diff --git a/src/gui/views/network/setup/p2p.rs b/src/gui/views/network/setup/p2p.rs index bb4b348..ccf015e 100644 --- a/src/gui/views/network/setup/p2p.rs +++ b/src/gui/views/network/setup/p2p.rs @@ -12,17 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Align, Id, Layout, RichText, TextStyle, Widget}; -use egui_extras::{Size, StripBuilder}; +use egui::{Align, Id, Layout, RichText}; use grin_core::global::ChainTypes; use crate::AppConfig; use crate::gui::Colors; -use crate::gui::icons::{ARROW_FAT_LINE_UP, ARROW_FAT_LINES_DOWN, ARROW_FAT_LINES_UP, CLIPBOARD_TEXT, GLOBE_SIMPLE, HANDSHAKE, PLUG, PLUS_CIRCLE, PROHIBIT_INSET, TRASH}; +use crate::gui::icons::{ARROW_FAT_LINE_UP, ARROW_FAT_LINES_DOWN, ARROW_FAT_LINES_UP, GLOBE_SIMPLE, HANDSHAKE, PLUG, PLUS_CIRCLE, PROHIBIT_INSET, TRASH}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, View}; use crate::gui::views::network::settings::NetworkSettings; -use crate::gui::views::types::{ModalContainer, ModalPosition}; +use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions}; use crate::node::{NodeConfig, PeersConfig}; /// Type of peer. @@ -283,16 +282,8 @@ impl P2PSetup { ui.add_space(8.0); // Draw p2p port text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.port_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(64.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let text_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.port_edit, text_edit_opts); // Show error when specified port is unavailable. if !self.port_available_edit { @@ -389,6 +380,7 @@ impl P2PSetup { }; View::button(ui, add_text, Colors::BUTTON, || { // Setup values for modal. + self.is_correct_address_edit = true; self.peer_edit = "".to_string(); // Select modal id. let modal_id = match peer_type { @@ -425,50 +417,19 @@ impl P2PSetup { }; ui.label(RichText::new(label_text).size(17.0).color(Colors::GRAY)); ui.add_space(8.0); - StripBuilder::new(ui) - .size(Size::exact(42.0)) - .vertical(|mut strip| { - strip.strip(|builder| { - builder - .size(Size::remainder()) - .size(Size::exact(48.0)) - .horizontal(|mut strip| { - strip.cell(|ui| { - ui.add_space(2.0); - // Draw peer address text edit. - let text_edit = egui::TextEdit::singleline(&mut self.peer_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Button) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .ui(ui); - text_edit.request_focus(); - if text_edit.clicked() { - cb.show_keyboard(); - } - }); - strip.cell(|ui| { - ui.vertical_centered(|ui| { - // Draw paste button. - let paste_icon = CLIPBOARD_TEXT.to_string(); - View::button(ui, paste_icon, Colors::WHITE, || { - self.peer_edit = cb.get_string_from_buffer(); - }); - }); - }); - }); - }) - }); + + // Draw peer address text edit. + let peer_text_edit_opts = TextEditOptions::new(Id::from(modal.id)).paste(); + View::text_edit(ui, cb, &mut self.peer_edit, peer_text_edit_opts); // Show error when specified address is incorrect. if !self.is_correct_address_edit { + ui.add_space(10.0); ui.label(RichText::new(t!("network_settings.peer_address_error")) .size(16.0) .color(Colors::RED)); - ui.add_space(6.0); } - - ui.add_space(4.0); + ui.add_space(12.0); // Show modal buttons. ui.scope(|ui| { @@ -572,16 +533,8 @@ impl P2PSetup { ui.add_space(8.0); // Draw ban window text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.ban_window_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(84.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let text_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.ban_window_edit, text_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.ban_window_edit.parse::().is_err() { @@ -658,16 +611,8 @@ impl P2PSetup { ui.add_space(8.0); // Draw maximum number of inbound peers text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.max_inbound_count) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(42.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let text_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.max_inbound_count, text_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.max_inbound_count.parse::().is_err() { @@ -744,16 +689,8 @@ impl P2PSetup { ui.add_space(8.0); // Draw maximum number of outbound peers text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.max_outbound_count) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(42.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let text_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.max_outbound_count, text_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.max_outbound_count.parse::().is_err() { @@ -834,16 +771,8 @@ impl P2PSetup { ui.add_space(8.0); // Draw maximum number of outbound peers text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.min_outbound_count) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(42.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let text_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.min_outbound_count, text_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.min_outbound_count.parse::().is_err() { diff --git a/src/gui/views/network/setup/pool.rs b/src/gui/views/network/setup/pool.rs index 6491fec..df6b5c2 100644 --- a/src/gui/views/network/setup/pool.rs +++ b/src/gui/views/network/setup/pool.rs @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Id, RichText, TextStyle, Widget}; +use egui::{Id, RichText}; use crate::gui::Colors; use crate::gui::icons::{BEZIER_CURVE, BOUNDING_BOX, CHART_SCATTER, CIRCLES_THREE, CLOCK_COUNTDOWN, HAND_COINS}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, View}; use crate::gui::views::network::settings::NetworkSettings; -use crate::gui::views::types::{ModalContainer, ModalPosition}; +use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions}; use crate::node::NodeConfig; /// Memory pool setup section content. @@ -169,16 +169,8 @@ impl PoolSetup { ui.add_space(8.0); // Draw fee base text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.fee_base_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(84.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let fee_base_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.fee_base_edit, fee_base_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.fee_base_edit.parse::().is_err() { @@ -254,16 +246,8 @@ impl PoolSetup { ui.add_space(8.0); // Draw reorg period text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.reorg_period_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(42.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let reorg_period_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.reorg_period_edit, reorg_period_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.reorg_period_edit.parse::().is_err() { @@ -339,16 +323,8 @@ impl PoolSetup { ui.add_space(8.0); // Draw pool size text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.pool_size_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(72.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let pool_size_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.pool_size_edit, pool_size_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.pool_size_edit.parse::().is_err() { @@ -424,16 +400,8 @@ impl PoolSetup { ui.add_space(8.0); // Draw stempool size text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.stempool_size_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(72.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let stem_pool_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.stempool_size_edit, stem_pool_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.stempool_size_edit.parse::().is_err() { @@ -509,16 +477,8 @@ impl PoolSetup { ui.add_space(8.0); // Draw tx weight text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.max_weight_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(72.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let mac_weight_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.max_weight_edit, mac_weight_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.max_weight_edit.parse::().is_err() { diff --git a/src/gui/views/network/setup/stratum.rs b/src/gui/views/network/setup/stratum.rs index 5a43563..079f14d 100644 --- a/src/gui/views/network/setup/stratum.rs +++ b/src/gui/views/network/setup/stratum.rs @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Id, RichText, TextStyle, Widget}; +use egui::{Id, RichText}; use crate::gui::Colors; use crate::gui::icons::{BARBELL, HARD_DRIVES, PLUG, POWER, TIMER}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, View}; use crate::gui::views::network::settings::NetworkSettings; -use crate::gui::views::types::{ModalContainer, ModalPosition}; +use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions}; use crate::node::{Node, NodeConfig}; /// Stratum server setup section content. @@ -224,16 +224,8 @@ impl StratumSetup { ui.add_space(8.0); // Draw stratum port text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.stratum_port_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(64.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let text_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.stratum_port_edit, text_edit_opts); // Show error when specified port is unavailable. if !self.stratum_port_available_edit { @@ -327,16 +319,8 @@ impl StratumSetup { ui.add_space(8.0); // Draw attempt time text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.attempt_time_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(42.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let text_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.attempt_time_edit, text_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.attempt_time_edit.parse::().is_err() { @@ -413,16 +397,8 @@ impl StratumSetup { ui.add_space(8.0); // Draw share difficulty text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.min_share_diff_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(42.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let text_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.min_share_diff_edit, text_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.min_share_diff_edit.parse::().is_err() { diff --git a/src/gui/views/types.rs b/src/gui/views/types.rs index 9f4c067..202aab4 100644 --- a/src/gui/views/types.rs +++ b/src/gui/views/types.rs @@ -68,4 +68,63 @@ pub trait ModalContainer { }); } } +} + +/// Options for [`egui::TextEdit`] view. +pub struct TextEditOptions { + /// View identifier. + pub id: egui::Id, + /// Flag to check if horizontal centering is needed. + pub h_center: bool, + /// Flag to check if initial focus on field is needed. + pub focus: bool, + /// Flag to hide letters and draw button to show/hide letters. + pub password: bool, + /// Flag to show copy button. + pub copy: bool, + /// Flag to show paste button. + pub paste: bool +} + +impl TextEditOptions { + pub fn new(id: egui::Id) -> Self { + Self { + id, + h_center: false, + focus: true, + password: false, + copy: false, + paste: false, + } + } + + /// Center text horizontally. + pub fn h_center(mut self) -> Self { + self.h_center = true; + self + } + + /// Disable initial focus. + pub fn no_focus(mut self) -> Self { + self.focus = false; + self + } + + /// Hide letters and draw button to show/hide letters. + pub fn password(mut self) -> Self { + self.password = true; + self + } + + /// Show button to copy text. + pub fn copy(mut self) -> Self { + self.copy = true; + self + } + + /// Show button to paste text. + pub fn paste(mut self) -> Self { + self.paste = true; + self + } } \ No newline at end of file diff --git a/src/gui/views/views.rs b/src/gui/views/views.rs index 5785ded..e52962e 100644 --- a/src/gui/views/views.rs +++ b/src/gui/views/views.rs @@ -14,14 +14,16 @@ use std::sync::atomic::{AtomicI32, Ordering}; -use egui::{Button, CursorIcon, PointerState, Rect, Response, RichText, Sense, Spinner, Widget}; +use egui::{Align, Button, CursorIcon, Layout, PointerState, Rect, Response, RichText, Sense, Spinner, TextStyle, Vec2, Widget}; use egui::epaint::{CircleShape, Color32, FontId, RectShape, Rounding, Stroke}; use egui::epaint::text::TextWrapping; use egui::text::{LayoutJob, TextFormat}; use lazy_static::lazy_static; use crate::gui::Colors; -use crate::gui::icons::{CHECK_SQUARE, SQUARE}; +use crate::gui::icons::{CHECK_SQUARE, CLIPBOARD_TEXT, COPY, EYE, EYE_SLASH, SQUARE}; +use crate::gui::platform::PlatformCallbacks; +use crate::gui::views::types::TextEditOptions; pub struct View; @@ -129,8 +131,8 @@ impl View { ui.style_mut().visuals.widgets.hovered.bg_stroke = Self::HOVER_STROKE; ui.style_mut().visuals.widgets.active.bg_stroke = Self::DEFAULT_STROKE; // Disable rounding. - ui.style_mut().visuals.widgets.hovered.rounding = Rounding::none(); - ui.style_mut().visuals.widgets.active.rounding = Rounding::none(); + ui.style_mut().visuals.widgets.hovered.rounding = Rounding::default(); + ui.style_mut().visuals.widgets.active.rounding = Rounding::default(); // Disable expansion. ui.style_mut().visuals.widgets.hovered.expansion = 0.0; ui.style_mut().visuals.widgets.active.expansion = 0.0; @@ -276,6 +278,87 @@ impl View { }); } + /// Default height of [`egui::TextEdit`] view. + const TEXT_EDIT_HEIGHT: f32 = 37.0; + + /// Draw [`egui::TextEdit`] widget. + pub fn text_edit(ui: &mut egui::Ui, + cb: &dyn PlatformCallbacks, + value: &mut String, + options: TextEditOptions) { + let mut layout_rect = ui.available_rect_before_wrap(); + layout_rect.set_height(Self::TEXT_EDIT_HEIGHT); + ui.allocate_ui_with_layout(layout_rect.size(), Layout::right_to_left(Align::Center), |ui| { + // Setup password button. + let mut show_pass = false; + if options.password { + // Set password button state value. + let show_pass_id = egui::Id::new(options.id).with("_show_pass"); + show_pass = ui.data(|data| { + data.get_temp(show_pass_id) + }).unwrap_or(true); + // Draw button to show/hide current password. + let eye_icon = if show_pass { EYE } else { EYE_SLASH }; + let mut changed = false; + View::button(ui, eye_icon.to_string(), Colors::WHITE, || { + show_pass = !show_pass; + changed = true; + }); + // Save state if changed. + if changed { + ui.data_mut(|data| { + data.insert_temp(show_pass_id, show_pass); + }); + } + ui.add_space(8.0); + } + + // Setup copy button. + if options.copy { + let copy_icon = COPY.to_string(); + View::button(ui, copy_icon, Colors::WHITE, || { + cb.copy_string_to_buffer(value.clone()); + }); + ui.add_space(8.0); + } + + // Setup paste button. + if options.paste { + let paste_icon = CLIPBOARD_TEXT.to_string(); + View::button(ui, paste_icon, Colors::WHITE, || { + *value = cb.get_string_from_buffer(); + }); + ui.add_space(8.0); + } + + let layout_size = ui.available_size(); + ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| { + // Setup text edit size. + let mut edit_rect = ui.available_rect_before_wrap(); + edit_rect.set_height(Self::TEXT_EDIT_HEIGHT); + // Show text edit. + let text_edit_resp = egui::TextEdit::singleline(value) + .id(options.id) + .margin(Vec2::new(2.0, 0.0)) + .font(TextStyle::Heading) + .min_size(edit_rect.size()) + .horizontal_align(if options.h_center { Align::Center } else { Align::Min }) + .vertical_align(Align::Center) + .password(show_pass) + .ui(ui); + // Show keyboard on click. + if text_edit_resp.clicked() { + cb.show_keyboard(); + } + // Setup focus on input field. + if options.focus { + text_edit_resp.request_focus(); + cb.show_keyboard(); + } + }); + }); + } + /// Calculate item background/button rounding based on item index. pub fn item_rounding(index: usize, len: usize, is_button: bool) -> Rounding { let corners = if is_button { diff --git a/src/gui/views/wallets/content.rs b/src/gui/views/wallets/content.rs index fd676c7..6c55329 100644 --- a/src/gui/views/wallets/content.rs +++ b/src/gui/views/wallets/content.rs @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Align, Align2, Layout, Margin, RichText, Rounding, ScrollArea, TextStyle, Widget}; -use egui_extras::{Size, StripBuilder}; +use egui::{Align, Align2, Id, Layout, Margin, RichText, Rounding, ScrollArea, Widget}; use crate::AppConfig; use crate::gui::Colors; -use crate::gui::icons::{ARROW_LEFT, CARET_RIGHT, COMPUTER_TOWER, EYE, EYE_SLASH, FOLDER_LOCK, FOLDER_OPEN, GEAR, GLOBE, GLOBE_SIMPLE, LOCK_KEY, PLUS, SIDEBAR_SIMPLE, SPINNER, SUITCASE, WARNING_CIRCLE}; +use crate::gui::icons::{ARROW_LEFT, CARET_RIGHT, COMPUTER_TOWER, FOLDER_LOCK, FOLDER_OPEN, GEAR, GLOBE, GLOBE_SIMPLE, LOCK_KEY, PLUS, SIDEBAR_SIMPLE, SPINNER, SUITCASE, WARNING_CIRCLE}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, Root, TitlePanel, View}; -use crate::gui::views::types::{ModalContainer, ModalPosition, TitleContentType, TitleType}; +use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions, TitleContentType, TitleType}; use crate::gui::views::wallets::creation::WalletCreation; use crate::gui::views::wallets::types::WalletTabType; use crate::gui::views::wallets::WalletContent; @@ -33,8 +32,6 @@ pub struct WalletsContent { /// Password to open wallet for [`Modal`]. pass_edit: String, - /// Flag to show/hide password at [`egui::TextEdit`] field. - hide_pass: bool, /// Flag to check if wrong password was entered. wrong_pass: bool, @@ -58,7 +55,6 @@ impl Default for WalletsContent { Self { wallets: WalletList::default(), pass_edit: "".to_string(), - hide_pass: true, wrong_pass: false, wallet_content: WalletContent::default(), creation_content: WalletCreation::default(), @@ -407,7 +403,7 @@ impl WalletsContent { // Show button to close opened wallet. if !wallet.is_closing() { View::item_button(ui, if !is_selected { - Rounding::none() + Rounding::default() } else { View::item_rounding(0, 1, true) }, LOCK_KEY, None, || { @@ -510,7 +506,6 @@ impl WalletsContent { /// Show [`Modal`] to open selected wallet. pub fn show_open_wallet_modal(&mut self, cb: &dyn PlatformCallbacks) { // Reset modal values. - self.hide_pass = true; self.pass_edit = String::from(""); self.wrong_pass = false; // Show modal. @@ -531,42 +526,11 @@ impl WalletsContent { ui.label(RichText::new(t!("wallets.pass")) .size(17.0) .color(Colors::GRAY)); - ui.add_space(10.0); + ui.add_space(8.0); - StripBuilder::new(ui) - .size(Size::exact(34.0)) - .vertical(|mut strip| { - strip.strip(|builder| { - builder - .size(Size::remainder()) - .size(Size::exact(48.0)) - .horizontal(|mut strip| { - strip.cell(|ui| { - // Draw wallet password text edit. - let pass_resp = egui::TextEdit::singleline(&mut self.pass_edit) - .id(ui.id().with("wallet_pass_edit")) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .password(self.hide_pass) - .ui(ui); - pass_resp.request_focus(); - if pass_resp.clicked() { - cb.show_keyboard(); - } - }); - strip.cell(|ui| { - ui.vertical_centered(|ui| { - // Draw button to show/hide password. - let eye_icon = if self.hide_pass { EYE } else { EYE_SLASH }; - View::button(ui, eye_icon.to_string(), Colors::WHITE, || { - self.hide_pass = !self.hide_pass; - }); - }); - }); - }); - }) - }); + // Show password input. + let pass_edit_opts = TextEditOptions::new(Id::from(modal.id)).password(); + View::text_edit(ui, cb, &mut self.pass_edit, pass_edit_opts); // Show information when password is empty. if self.pass_edit.is_empty() { @@ -607,7 +571,6 @@ impl WalletsContent { // Clear values. self.pass_edit = "".to_string(); self.wrong_pass = false; - self.hide_pass = true; // Close modal. cb.hide_keyboard(); modal.close(); diff --git a/src/gui/views/wallets/creation/creation.rs b/src/gui/views/wallets/creation/creation.rs index 2f6912e..a90f4b4 100644 --- a/src/gui/views/wallets/creation/creation.rs +++ b/src/gui/views/wallets/creation/creation.rs @@ -20,7 +20,7 @@ use crate::gui::Colors; use crate::gui::icons::{CHECK, EYE, EYE_SLASH, FOLDER_PLUS, SHARE_FAT}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, Root, View}; -use crate::gui::views::types::ModalPosition; +use crate::gui::views::types::{ModalPosition, TextEditOptions}; use crate::gui::views::wallets::creation::MnemonicSetup; use crate::gui::views::wallets::creation::types::Step; use crate::gui::views::wallets::setup::ConnectionSetup; @@ -32,14 +32,12 @@ pub struct WalletCreation { /// Wallet creation step. step: Option, - /// Flag to check if [`Modal`] just was opened to focus on first field. + /// Flag to check if wallet creation [`Modal`] was just opened to focus on first field. modal_just_opened: bool, /// Wallet name value. name_edit: String, /// Password to encrypt created wallet. pass_edit: String, - /// Flag to show/hide password at [`egui::TextEdit`] field. - hide_pass: bool, /// Mnemonic phrase setup content. pub(crate) mnemonic_setup: MnemonicSetup, @@ -54,7 +52,6 @@ impl Default for WalletCreation { modal_just_opened: true, name_edit: String::from(""), pass_edit: String::from(""), - hide_pass: true, mnemonic_setup: MnemonicSetup::default(), network_setup: ConnectionSetup::default() } @@ -313,7 +310,6 @@ impl WalletCreation { /// Start wallet creation from showing [`Modal`] to enter name and password. pub fn show_name_pass_modal(&mut self, cb: &dyn PlatformCallbacks) { // Reset modal values. - self.hide_pass = true; self.modal_just_opened = true; self.name_edit = String::from(""); self.pass_edit = String::from(""); @@ -338,68 +334,25 @@ impl WalletCreation { ui.add_space(8.0); // Show wallet name text edit. - let name_resp = egui::TextEdit::singleline(&mut self.name_edit) - .id(Id::from(modal.id).with("wallet_name_edit")) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .ui(ui); - ui.add_space(8.0); - if name_resp.clicked() { - cb.show_keyboard(); - } - - // Check if modal was just opened to show focus on name text input. + let mut name_edit_opts = TextEditOptions::new(Id::from(modal.id).with("name")) + .no_focus(); if self.modal_just_opened { self.modal_just_opened = false; - cb.show_keyboard(); - name_resp.request_focus(); + name_edit_opts.focus = true; } + View::text_edit(ui, cb, &mut self.name_edit, name_edit_opts); + ui.add_space(8.0); ui.label(RichText::new(t!("wallets.pass")) .size(17.0) .color(Colors::GRAY)); ui.add_space(8.0); - StripBuilder::new(ui) - .size(Size::exact(34.0)) - .vertical(|mut strip| { - strip.strip(|builder| { - builder - .size(Size::remainder()) - .size(Size::exact(48.0)) - .horizontal(|mut strip| { - strip.cell(|ui| { - ui.add_space(2.0); - // Draw wallet password text edit. - let pass_resp = egui::TextEdit::singleline(&mut self.pass_edit) - .id(Id::from(modal.id).with("wallet_pass_edit")) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .password(self.hide_pass) - .ui(ui); - if pass_resp.clicked() { - cb.show_keyboard(); - } - - // Hide keyboard if input fields has no focus. - if !pass_resp.has_focus() && !name_resp.has_focus() { - cb.hide_keyboard(); - } - }); - strip.cell(|ui| { - ui.vertical_centered(|ui| { - // Draw button to show/hide password. - let eye_icon = if self.hide_pass { EYE } else { EYE_SLASH }; - View::button(ui, eye_icon.to_string(), Colors::WHITE, || { - self.hide_pass = !self.hide_pass; - }); - }); - }); - }); - }) - }); + // Draw wallet password text edit. + let pass_text_edit_opts = TextEditOptions::new(Id::from(modal.id).with("pass")) + .password() + .no_focus(); + View::text_edit(ui, cb, &mut self.pass_edit, pass_text_edit_opts); ui.add_space(12.0); }); diff --git a/src/gui/views/wallets/creation/mnemonic.rs b/src/gui/views/wallets/creation/mnemonic.rs index 551ada6..689c316 100644 --- a/src/gui/views/wallets/creation/mnemonic.rs +++ b/src/gui/views/wallets/creation/mnemonic.rs @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Id, RichText, TextStyle, Widget}; +use egui::{Id, RichText}; use crate::gui::Colors; use crate::gui::icons::PENCIL; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, Root, View}; -use crate::gui::views::types::{ModalContainer, ModalPosition}; +use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions}; use crate::wallet::Mnemonic; use crate::wallet::types::{PhraseMode, PhraseSize}; @@ -265,16 +265,8 @@ impl MnemonicSetup { ui.add_space(8.0); // Draw word value text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.word_edit) - .id(Id::from(modal.id).with(self.word_num_edit)) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let text_edit_opts = TextEditOptions::new(Id::from(modal.id).with(self.word_num_edit)); + View::text_edit(ui, cb, &mut self.word_edit, text_edit_opts); // Show error when specified word is not valid. if !self.valid_word_edit { diff --git a/src/gui/views/wallets/setup/common.rs b/src/gui/views/wallets/setup/common.rs index f0c7934..91ada28 100644 --- a/src/gui/views/wallets/setup/common.rs +++ b/src/gui/views/wallets/setup/common.rs @@ -18,7 +18,7 @@ use crate::gui::Colors; use crate::gui::icons::{CLOCK_COUNTDOWN, EYE, EYE_SLASH, PASSWORD, PENCIL}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, View}; -use crate::gui::views::types::ModalPosition; +use crate::gui::views::types::{ModalPosition, TextEditOptions}; use crate::wallet::Wallet; /// Common wallet setup content. @@ -31,13 +31,9 @@ pub struct CommonSetup { /// Flag to check if wrong password was entered. wrong_pass: bool, /// Current wallet password [`Modal`] value. - current_pass_edit: String, - /// Flag to show/hide old password at [`egui::TextEdit`] field. - hide_current_pass: bool, + old_pass_edit: String, /// New wallet password [`Modal`] value. new_pass_edit: String, - /// Flag to show/hide new password at [`egui::TextEdit`] field. - hide_new_pass: bool, /// Minimum confirmations number value. min_confirmations_edit: String @@ -56,10 +52,8 @@ impl Default for CommonSetup { name_edit: "".to_string(), first_edit_pass_opening: true, wrong_pass: false, - current_pass_edit: "".to_string(), - hide_current_pass: true, + old_pass_edit: "".to_string(), new_pass_edit: "".to_string(), - hide_new_pass: true, min_confirmations_edit: "".to_string() } } @@ -106,10 +100,8 @@ impl CommonSetup { View::button(ui, pass_text, Colors::BUTTON, || { // Setup modal values. self.first_edit_pass_opening = true; - self.current_pass_edit = "".to_string(); + self.old_pass_edit = "".to_string(); self.new_pass_edit = "".to_string(); - self.hide_current_pass = true; - self.hide_new_pass = true; self.wrong_pass = false; // Show wallet password modal. Modal::new(PASS_EDIT_MODAL) @@ -187,17 +179,10 @@ impl CommonSetup { .color(Colors::GRAY)); ui.add_space(8.0); - // Draw wallet name edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.name_edit) - .id(Id::from(modal.id).with(wallet.get_config().id)) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + // Show wallet name text edit. + let name_edit_id = Id::from(modal.id).with(wallet.get_config().id); + let name_edit_opts = TextEditOptions::new(name_edit_id); + View::text_edit(ui, cb, &mut self.name_edit, name_edit_opts); ui.add_space(12.0); }); @@ -248,83 +233,41 @@ impl CommonSetup { ui.label(RichText::new(t!("wallets.current_pass")) .size(17.0) .color(Colors::GRAY)); - ui.add_space(6.0); + ui.add_space(8.0); - let mut rect = ui.available_rect_before_wrap(); - rect.set_height(34.0); - ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { - // Draw button to show/hide current password. - let eye_icon = if self.hide_current_pass { EYE } else { EYE_SLASH }; - View::button(ui, eye_icon.to_string(), Colors::WHITE, || { - self.hide_current_pass = !self.hide_current_pass; - }); - - let layout_size = ui.available_size(); - ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| { - // Draw current wallet password text edit. - let old_pass_resp = egui::TextEdit::singleline(&mut self.current_pass_edit) - .id(Id::from(modal.id).with(wallet_id).with("old_pass")) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .password(self.hide_current_pass) - .ui(ui); - if old_pass_resp.clicked() { - cb.show_keyboard(); - } - - // Setup focus on input field on first modal opening. - if self.first_edit_pass_opening { - self.first_edit_pass_opening = false; - old_pass_resp.request_focus(); - } - }); - }); - ui.add_space(6.0); + // Draw old password text edit. + let pass_edit_id = Id::from(modal.id).with(wallet_id).with("old_pass"); + let mut pass_edit_opts = TextEditOptions::new(pass_edit_id).password().no_focus(); + if self.first_edit_pass_opening { + self.first_edit_pass_opening = false; + pass_edit_opts.focus = true; + } + View::text_edit(ui, cb, &mut self.old_pass_edit, pass_edit_opts); + ui.add_space(8.0); ui.label(RichText::new(t!("wallets.new_pass")) .size(17.0) .color(Colors::GRAY)); - ui.add_space(6.0); + ui.add_space(8.0); - let mut new_rect = ui.available_rect_before_wrap(); - new_rect.set_height(34.0); - ui.allocate_ui_with_layout(new_rect.size(), Layout::right_to_left(Align::Center), |ui| { - // Draw button to show/hide new password. - let eye_icon = if self.hide_new_pass { EYE } else { EYE_SLASH }; - View::button(ui, eye_icon.to_string(), Colors::WHITE, || { - self.hide_new_pass = !self.hide_new_pass; - }); - - let layout_size = ui.available_size(); - ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| { - // Draw new wallet password text edit. - let new_pass_resp = egui::TextEdit::singleline(&mut self.new_pass_edit) - .id(Id::from(modal.id).with(wallet_id).with("new_pass")) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .password(self.hide_new_pass) - .ui(ui); - if new_pass_resp.clicked() { - cb.show_keyboard(); - } - }); - }); + // Draw new password text edit. + let new_pass_edit_id = Id::from(modal.id).with(wallet_id).with("new_pass"); + let new_pass_edit_opts = TextEditOptions::new(new_pass_edit_id).password().no_focus(); + View::text_edit(ui, cb, &mut self.new_pass_edit, new_pass_edit_opts); // Show information when password is empty. - if self.current_pass_edit.is_empty() || self.new_pass_edit.is_empty() { - ui.add_space(8.0); + if self.old_pass_edit.is_empty() || self.new_pass_edit.is_empty() { + ui.add_space(10.0); ui.label(RichText::new(t!("wallets.pass_empty")) .size(17.0) .color(Colors::INACTIVE_TEXT)); } else if self.wrong_pass { - ui.add_space(8.0); + ui.add_space(10.0); ui.label(RichText::new(t!("wallets.wrong_pass")) .size(17.0) .color(Colors::RED)); } - ui.add_space(10.0); + ui.add_space(12.0); }); // Show modal buttons. @@ -346,17 +289,13 @@ impl CommonSetup { if self.new_pass_edit.is_empty() { return; } - let old_pass = self.current_pass_edit.clone(); + let old_pass = self.old_pass_edit.clone(); let new_pass = self.new_pass_edit.clone(); match wallet.change_password(old_pass, new_pass) { Ok(_) => { - // Clear values. - self.first_edit_pass_opening = true; - self.current_pass_edit = "".to_string(); + // Clear password values. + self.old_pass_edit = "".to_string(); self.new_pass_edit = "".to_string(); - self.hide_current_pass = true; - self.hide_new_pass = true; - self.wrong_pass = false; // Close modal. cb.hide_keyboard(); modal.close(); @@ -391,16 +330,8 @@ impl CommonSetup { ui.add_space(8.0); // Minimum amount of confirmations text edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.min_confirmations_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(48.0) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } + let text_edit_opts = TextEditOptions::new(Id::from(modal.id)).h_center(); + View::text_edit(ui, cb, &mut self.min_confirmations_edit, text_edit_opts); // Show error when specified value is not valid or reminder to restart enabled node. if self.min_confirmations_edit.parse::().is_err() { diff --git a/src/gui/views/wallets/setup/connection.rs b/src/gui/views/wallets/setup/connection.rs index 9ae0b5c..f8c16c8 100644 --- a/src/gui/views/wallets/setup/connection.rs +++ b/src/gui/views/wallets/setup/connection.rs @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Align, Id, Layout, RichText, Rounding, TextStyle, Widget}; +use egui::{Align, Id, Layout, RichText, Rounding, Widget}; use url::Url; use crate::gui::Colors; use crate::gui::icons::{CHECK, CHECK_CIRCLE, CHECK_FAT, COMPUTER_TOWER, DOTS_THREE_CIRCLE, GLOBE, PLUS_CIRCLE, POWER, X_CIRCLE}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, View}; -use crate::gui::views::types::{ModalContainer, ModalPosition}; +use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions}; use crate::node::{Node, NodeConfig}; use crate::wallet::{ConnectionsConfig, ExternalConnection, Wallet}; use crate::wallet::types::ConnectionMethod; @@ -165,7 +165,7 @@ impl ConnectionSetup { // Show button to add new external node connection. let add_node_text = format!("{} {}", PLUS_CIRCLE, t!("wallets.add_node")); - View::button(ui, add_node_text, Colors::GOLD, || { + View::button(ui, add_node_text, Colors::WHITE, || { self.show_add_ext_conn_modal(cb); }); ui.add_space(12.0); @@ -207,7 +207,7 @@ impl ConnectionSetup { if !Node::is_running() { // Draw button to start integrated node. - View::item_button(ui, Rounding::none(), POWER, Some(Colors::GREEN), || { + View::item_button(ui, Rounding::default(), POWER, Some(Colors::GREEN), || { Node::start(); }); } @@ -326,20 +326,14 @@ impl ConnectionSetup { ui.add_space(8.0); // Draw node URL text edit. - let url_edit_resp = egui::TextEdit::singleline(&mut self.ext_node_url_edit) - .id(Id::from(modal.id)) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .ui(ui); - ui.add_space(8.0); + let url_edit_id = Id::from(modal.id).with("node_url_edit"); + let mut url_edit_opts = TextEditOptions::new(url_edit_id).paste().no_focus(); if self.first_modal_launch { self.first_modal_launch = false; - url_edit_resp.request_focus(); - } - if url_edit_resp.clicked() { - cb.show_keyboard(); + url_edit_opts.focus = true; } + View::text_edit(ui, cb, &mut self.ext_node_url_edit, url_edit_opts); + ui.add_space(8.0); ui.label(RichText::new(t!("wallets.node_secret")) .size(17.0) @@ -347,25 +341,18 @@ impl ConnectionSetup { ui.add_space(8.0); // Draw node API secret text edit. - let secret_edit_resp = egui::TextEdit::singleline(&mut self.ext_node_secret_edit) - .id(Id::from(modal.id).with("node_secret_edit")) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .ui(ui); - ui.add_space(8.0); - if secret_edit_resp.clicked() { - cb.show_keyboard(); - } + let secret_edit_id = Id::from(modal.id).with("node_secret_edit"); + let secret_edit_opts = TextEditOptions::new(secret_edit_id).paste().no_focus(); + View::text_edit(ui, cb, &mut self.ext_node_secret_edit, secret_edit_opts); // Show error when specified URL is not valid. if self.ext_node_url_error { - ui.add_space(2.0); + ui.add_space(10.0); ui.label(RichText::new(t!("wallets.invalid_url")) .size(17.0) .color(Colors::RED)); } - ui.add_space(12.0); + ui.add_space(10.0); }); // Show modal buttons. diff --git a/src/gui/views/wallets/setup/recovery.rs b/src/gui/views/wallets/setup/recovery.rs index c84e98c..ddcafeb 100644 --- a/src/gui/views/wallets/setup/recovery.rs +++ b/src/gui/views/wallets/setup/recovery.rs @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -use egui::{Align, Id, Layout, RichText, TextStyle, Widget}; +use egui::{Id, RichText, Widget}; use grin_chain::SyncStatus; use grin_util::ZeroingString; use crate::gui::Colors; -use crate::gui::icons::{EYE, EYE_SLASH, STETHOSCOPE, TRASH, WRENCH}; +use crate::gui::icons::{EYE, STETHOSCOPE, TRASH, WRENCH}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, View}; -use crate::gui::views::types::ModalPosition; +use crate::gui::views::types::{ModalPosition, TextEditOptions}; use crate::node::Node; use crate::wallet::Wallet; @@ -30,8 +30,6 @@ pub struct RecoverySetup { pass_edit: String, /// Flag to check if wrong password was entered. wrong_pass: bool, - /// Flag to show/hide old password at [`egui::TextEdit`] field. - hide_pass: bool, /// Recovery phrase value. recovery_phrase: Option, @@ -46,7 +44,6 @@ impl Default for RecoverySetup { fn default() -> Self { Self { wrong_pass: false, - hide_pass: false, pass_edit: "".to_string(), recovery_phrase: None, } @@ -153,7 +150,6 @@ impl RecoverySetup { // Setup modal values. self.pass_edit = "".to_string(); self.wrong_pass = false; - self.hide_pass = true; self.recovery_phrase = None; // Show recovery phrase modal. Modal::new(RECOVERY_PHRASE_MODAL) @@ -176,7 +172,7 @@ impl RecoverySetup { .size(17.0) .color(Colors::BLACK)); }); - ui.add_space(6.0); + ui.add_space(10.0); ui.vertical_centered_justified(|ui| { View::button(ui, t!("close"), Colors::WHITE, || { self.recovery_phrase = None; @@ -188,50 +184,29 @@ impl RecoverySetup { ui.label(RichText::new(t!("wallets.pass")) .size(17.0) .color(Colors::GRAY)); - ui.add_space(6.0); + ui.add_space(8.0); }); - let mut rect = ui.available_rect_before_wrap(); - rect.set_height(34.0); - ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| { - // Draw button to show/hide current password. - let eye_icon = if self.hide_pass { EYE } else { EYE_SLASH }; - View::button(ui, eye_icon.to_string(), Colors::WHITE, || { - self.hide_pass = !self.hide_pass; - }); - - let layout_size = ui.available_size(); - ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| { - // Draw current wallet password text edit. - let pass_resp = egui::TextEdit::singleline(&mut self.pass_edit) - .id(Id::from(modal.id).with(wallet.get_config().id).with("recovery_phrase")) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .password(self.hide_pass) - .ui(ui); - if pass_resp.clicked() { - cb.show_keyboard(); - } - pass_resp.request_focus(); - }); - }); + // Draw current wallet password text edit. + let pass_edit_id = Id::from(modal.id).with(wallet.get_config().id); + let pass_edit_opts = TextEditOptions::new(pass_edit_id).password(); + View::text_edit(ui, cb, &mut self.pass_edit, pass_edit_opts); // Show information when password is empty. ui.vertical_centered(|ui| { if self.pass_edit.is_empty() { - ui.add_space(8.0); + ui.add_space(10.0); ui.label(RichText::new(t!("wallets.pass_empty")) .size(17.0) .color(Colors::INACTIVE_TEXT)); } else if self.wrong_pass { - ui.add_space(8.0); + ui.add_space(10.0); ui.label(RichText::new(t!("wallets.wrong_pass")) .size(17.0) .color(Colors::RED)); } - ui.add_space(10.0); }); + ui.add_space(12.0); // Show modal buttons. ui.scope(|ui| { @@ -277,7 +252,7 @@ impl RecoverySetup { .size(17.0) .color(Colors::TEXT)); }); - ui.add_space(10.0); + ui.add_space(12.0); // Show modal buttons. ui.scope(|ui| { diff --git a/src/gui/views/wallets/wallet/content.rs b/src/gui/views/wallets/wallet/content.rs index f217f65..1e2f988 100644 --- a/src/gui/views/wallets/wallet/content.rs +++ b/src/gui/views/wallets/wallet/content.rs @@ -14,16 +14,16 @@ use std::time::Duration; -use egui::{Align, Id, Layout, Margin, RichText, Rounding, ScrollArea, TextStyle, Widget}; +use egui::{Align, Id, Layout, Margin, RichText, Rounding, ScrollArea, Widget}; use grin_chain::SyncStatus; use grin_core::core::amount_to_hr_string; use crate::AppConfig; use crate::gui::Colors; -use crate::gui::icons::{CHECK, CHECK_FAT, CREDIT_CARD, DOWNLOAD, FILE_ARCHIVE, GEAR_FINE, LIST, PACKAGE, PLUS, POWER, REPEAT, UPLOAD, WALLET}; +use crate::gui::icons::{CHECK, CHECK_FAT, DOWNLOAD, FILE_ARCHIVE, GEAR_FINE, LIST, PACKAGE, PLUS, POWER, REPEAT, UPLOAD, WALLET}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, Root, View}; -use crate::gui::views::types::ModalPosition; +use crate::gui::views::types::{ModalPosition, TextEditOptions}; use crate::gui::views::wallets::{WalletInfo, WalletReceive, WalletSend, WalletSettings}; use crate::gui::views::wallets::types::{WalletTab, WalletTabType}; use crate::node::Node; @@ -285,29 +285,20 @@ impl WalletContent { ui.add_space(8.0); // Draw account name edit. - let text_edit_resp = egui::TextEdit::singleline(&mut self.account_label_edit) - .id(Id::from(modal.id).with(wallet.get_config().id)) - .font(TextStyle::Heading) - .desired_width(ui.available_width()) - .cursor_at_end(true) - .ui(ui); - text_edit_resp.request_focus(); - if text_edit_resp.clicked() { - cb.show_keyboard(); - } - ui.add_space(8.0); + let text_edit_id = Id::from(modal.id).with(wallet.get_config().id); + let text_edit_opts = TextEditOptions::new(text_edit_id); + View::text_edit(ui, cb, &mut self.account_label_edit, text_edit_opts); // Show error occurred during account creation.. if self.account_creation_error { - ui.add_space(2.0); + ui.add_space(12.0); ui.label(RichText::new(t!("error")) .size(17.0) .color(Colors::RED)); } + ui.add_space(12.0); }); - ui.add_space(12.0); - // Show modal buttons. ui.scope(|ui| { // Setup spacing between buttons. diff --git a/src/gui/views/wallets/wallet/info.rs b/src/gui/views/wallets/wallet/info.rs index c9e8704..b263186 100644 --- a/src/gui/views/wallets/wallet/info.rs +++ b/src/gui/views/wallets/wallet/info.rs @@ -192,7 +192,7 @@ fn tx_item_ui(ui: &mut egui::Ui, if !is_cancelling && !tx.confirmed && tx.tx_type != TxLogEntryType::TxReceivedCancelled && tx.tx_type != TxLogEntryType::TxSentCancelled { - View::item_button(ui, Rounding::none(), PROHIBIT, Some(Colors::RED), || { + View::item_button(ui, Rounding::default(), PROHIBIT, Some(Colors::RED), || { wallet.cancel(tx.id); //TODO: Cancel tx });