diff --git a/src/gui/app.rs b/src/gui/app.rs index a4577b7..e527c02 100755 --- a/src/gui/app.rs +++ b/src/gui/app.rs @@ -21,7 +21,7 @@ use crate::AppConfig; use crate::gui::Colors; use crate::gui::icons::{ARROWS_IN, ARROWS_OUT, CARET_DOWN, MOON, SUN, X}; use crate::gui::platform::PlatformCallbacks; -use crate::gui::views::{Content, Modal, TitlePanel, View}; +use crate::gui::views::{Content, KeyboardContent, Modal, TitlePanel, View}; use crate::wallet::ExternalConnection; lazy_static! { @@ -33,8 +33,12 @@ lazy_static! { pub struct App { /// Handles platform-specific functionality. pub platform: Platform, + /// Main content. content: Content, + /// Keyboard content. + keyboard_content: KeyboardContent, + /// Last window resize direction. resize_direction: Option, /// Flag to check if it's first draw. @@ -46,6 +50,7 @@ impl App { Self { platform, content: Content::default(), + keyboard_content: KeyboardContent::default(), resize_direction: None, first_draw: true } @@ -73,7 +78,12 @@ impl App { // Handle Esc keyboard key event and platform Back button key event. let back_pressed = BACK_BUTTON_PRESSED.load(Ordering::Relaxed); if back_pressed || ctx.input_mut(|i| i.consume_key(Modifiers::NONE, egui::Key::Escape)) { - self.content.on_back(&self.platform); + // Hide keyboard or pass event to content. + if KeyboardContent::showing() { + KeyboardContent::hide(); + } else { + self.content.on_back(&self.platform); + } if back_pressed { BACK_BUTTON_PRESSED.store(false, Ordering::Relaxed); } @@ -128,10 +138,13 @@ impl App { self.content.ui(ui, &self.platform); } + // Show soft keyboard content. + self.keyboard_content.ui(ctx); + // Provide incoming data to wallets. if let Some(data) = crate::consume_incoming_data() { if !data.is_empty() { - self.content.wallets.on_data(ui, Some(data), &self.platform); + self.content.wallets.on_data(ui, Some(data)); } } }); diff --git a/src/gui/platform/android/mod.rs b/src/gui/platform/android/mod.rs index 135d010..e5de0a7 100644 --- a/src/gui/platform/android/mod.rs +++ b/src/gui/platform/android/mod.rs @@ -70,20 +70,6 @@ impl PlatformCallbacks for Android { let _ = self.call_java_method("exit", "()V", &[]); } - fn show_keyboard(&self) { - // Disable NDK soft input show call before fix for egui. - // self.android_app.show_soft_input(false); - - let _ = self.call_java_method("showKeyboard", "()V", &[]); - } - - fn hide_keyboard(&self) { - // Disable NDK soft input hide call before fix for egui. - // self.android_app.hide_soft_input(false); - - let _ = self.call_java_method("hideKeyboard", "()V", &[]); - } - fn copy_string_to_buffer(&self, data: String) { let vm = unsafe { jni::JavaVM::from_raw(self.android_app.vm_as_ptr() as _) }.unwrap(); let env = vm.attach_current_thread().unwrap(); diff --git a/src/gui/platform/desktop/mod.rs b/src/gui/platform/desktop/mod.rs index a9bba5a..e78a9e7 100644 --- a/src/gui/platform/desktop/mod.rs +++ b/src/gui/platform/desktop/mod.rs @@ -180,10 +180,6 @@ impl PlatformCallbacks for Desktop { } } - fn show_keyboard(&self) {} - - fn hide_keyboard(&self) {} - fn copy_string_to_buffer(&self, data: String) { let mut clipboard = arboard::Clipboard::new().unwrap(); clipboard.set_text(data).unwrap(); diff --git a/src/gui/platform/mod.rs b/src/gui/platform/mod.rs index cd4ed15..a9e73fa 100644 --- a/src/gui/platform/mod.rs +++ b/src/gui/platform/mod.rs @@ -24,8 +24,6 @@ pub mod platform; pub trait PlatformCallbacks { fn set_context(&mut self, ctx: &egui::Context); fn exit(&self); - fn show_keyboard(&self); - fn hide_keyboard(&self); fn copy_string_to_buffer(&self, data: String); fn get_string_from_buffer(&self) -> String; fn start_camera(&self); diff --git a/src/gui/views/keyboard.rs b/src/gui/views/keyboard.rs new file mode 100644 index 0000000..805a63d --- /dev/null +++ b/src/gui/views/keyboard.rs @@ -0,0 +1,358 @@ +// Copyright 2025 The Grim Developers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use eframe::emath::Align; +use eframe::epaint::{Margin, Shadow}; +use egui::{Align2, Button, Color32, CursorIcon, Layout, Rect, Response, RichText, Stroke, Vec2, Widget}; +use parking_lot::RwLock; +use lazy_static::lazy_static; + +use crate::gui::Colors; +use crate::gui::icons::{ARROW_FAT_UP, BACKSPACE, KEY_RETURN, TRANSLATE}; +use crate::gui::views::View; + +lazy_static! { + /// Last input from software keyboard. + static ref LAST_INPUT: Arc>> = Arc::new(RwLock::new(None)); + /// Flag to show software keyboard. + static ref SHOW_KEYBOARD: AtomicBool = AtomicBool::new(false); + /// Flag to show English layout at keyboard. + static ref ENG_KEYBOARD: AtomicBool = AtomicBool::new(false); +} + +/// Software keyboard input. +#[derive(Clone)] +pub enum KeyboardInput { + TEXT(String), CLEAR, ENTER +} + +/// Software keyboard content. +pub struct KeyboardContent { + /// Flag to check if uppercase text entering is enabled. + uppercase: bool, + /// Flag to show symbols layout. + symbols: bool, +} + +impl Default for KeyboardContent { + fn default() -> Self { + Self { + uppercase: false, + symbols: false, + } + } +} + +impl KeyboardContent { + /// Maximum keyboard content width. + const MAX_WIDTH: f32 = 600.0; + /// Buttons content margin. + const MARGIN: f32 = 5.0; + + /// Draw keyboard content. + pub fn ui(&mut self, ctx: &egui::Context) { + if !KeyboardContent::showing() { + return; + } + let width = ctx.screen_rect().width(); + let layer_id = egui::Window::new("soft_keyboard") + .title_bar(false) + .resizable(false) + .collapsible(false) + .min_width(width) + .default_width(width) + .anchor(Align2::CENTER_BOTTOM, Vec2::new(0.0, 0.0)) + .frame(egui::Frame { + shadow: Shadow { + offset: Default::default(), + blur: 30.0, + spread: 3.0, + color: egui::Color32::from_black_alpha(32), + }, + inner_margin: Margin { + left: View::get_left_inset() + Self::MARGIN, + right: View::get_right_inset() + Self::MARGIN, + top: Self::MARGIN, + bottom: View::get_bottom_inset() + Self::MARGIN, + }, + fill: Colors::fill(), + ..Default::default() + }) + .show(ctx, |ui| { + ui.set_min_width(width); + // Calculate content width. + let side_insets = View::get_left_inset() + View::get_right_inset(); + let available_width = width - (side_insets + Self::MARGIN * 2.0); + let w = f32::min(available_width, Self::MAX_WIDTH); + View::max_width_ui(ui, w, |ui| { + // Setup spacing between buttons. + ui.style_mut().spacing.item_spacing = egui::vec2(Self::MARGIN, 0.0); + // Setup vertical padding inside buttons. + ui.style_mut().spacing.button_padding = egui::vec2(Self::MARGIN, 8.0); + + let button_rect = if self.symbols { + self.symbols_ui(ui) + } else { + self.text_ui(ui) + }; + ui.add_space(View::TAB_ITEMS_PADDING); + + // Draw bottom keyboard buttons. + let bottom_size = { + let mut r = button_rect.clone(); + r.set_width(ui.available_width()); + r.size() + }; + let button_width = button_rect.width(); + ui.allocate_ui_with_layout(bottom_size, Layout::right_to_left(Align::Max), |ui| { + ui.horizontal_centered(|ui| { + ui.set_max_width(button_width * 2.0 + Self::MARGIN); + self.button_ui(KEY_RETURN, + Colors::white_or_black(false), + Some(Colors::green()), + ui, + |_| { + Self::on_input(KeyboardInput::ENTER); + }); + }); + ui.horizontal_centered(|ui| { + ui.set_max_width(button_width * 5.0 + 4.0 * Self::MARGIN); + self.button_ui(" ", Colors::inactive_text(), None, ui, |l| { + Self::on_input(KeyboardInput::TEXT(l)); + }); + }); + ui.horizontal_centered(|ui| { + ui.set_max_width(button_width); + self.button_ui(TRANSLATE, + Colors::text_button(), + Some(Colors::fill_lite()), + ui, + |_| { + let eng_keyboard = ENG_KEYBOARD.load(Ordering::Relaxed); + ENG_KEYBOARD.store(!eng_keyboard, Ordering::Relaxed); + }); + }); + ui.horizontal_centered(|ui| { + let label = if self.symbols { + "ABC" + } else { + "?/ツ" + }; + let mut symbols = self.symbols; + self.button_ui(label, Colors::text_button(), Some(Colors::fill_lite()), ui, |_| { + symbols = !self.symbols; + }); + self.symbols = symbols; + }); + }); + }); + }).unwrap().response.layer_id; + + // Always show keyboard above others windows. + ctx.move_to_top(layer_id); + } + + /// Draw text content returning button [`Rect`]. + fn text_ui(&mut self, ui: &mut egui::Ui) -> Rect { + let mut button_rect = ui.available_rect_before_wrap(); + let tl_0: Vec<&str> = vec!["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]; + ui.columns(tl_0.len(), |columns| { + for (index, s) in tl_0.iter().enumerate() { + button_rect = self.input_button_ui(s, &mut columns[index]); + } + }); + ui.add_space(View::TAB_ITEMS_PADDING); + + let tl_1: Vec<&str> = vec!["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"]; + ui.columns(tl_1.len(), |columns| { + for (index, s) in tl_1.iter().enumerate() { + self.input_button_ui(s, &mut columns[index]); + } + }); + ui.add_space(View::TAB_ITEMS_PADDING); + + let tl_2: Vec<&str> = vec!["a", "s", "d", "f", "g", "h", "j", "k", "l", ":"]; + ui.columns(tl_2.len(), |columns| { + for (index, s) in tl_2.iter().enumerate() { + self.input_button_ui(s, &mut columns[index]); + } + }); + ui.add_space(View::TAB_ITEMS_PADDING); + + let tl_3: Vec<&str> = vec![ARROW_FAT_UP, "z", "x", "c", "v", "b", "n", "m", ".", BACKSPACE]; + ui.columns(tl_3.len(), |columns| { + for (index, s) in tl_3.iter().enumerate() { + if index == 0 { + // Check for shift input. + let color = if self.uppercase { + Colors::yellow_dark() + } else { + Colors::inactive_text() + }; + let mut uppercase = self.uppercase; + self.button_ui(s, color, Some(Colors::fill_lite()), &mut columns[index], |_| { + uppercase = !uppercase; + }); + self.uppercase = uppercase; + } else if index == tl_3.len() - 1 { + // Check for backspace input. + self.button_ui(s, + Colors::red(), + Some(Colors::fill_lite()), + &mut columns[index], + |_| { + Self::on_input(KeyboardInput::CLEAR); + }); + } else { + self.input_button_ui(s, &mut columns[index]); + } + } + }); + button_rect + } + + /// Draw symbols content returning button [`Rect`]. + fn symbols_ui(&mut self, ui: &mut egui::Ui) -> Rect { + let mut button_rect = ui.available_rect_before_wrap(); + let tl_0: Vec<&str> = vec!["[", "]", "{", "}", "#", "%", "^", "*", "+", "="]; + ui.columns(tl_0.len(), |columns| { + for (index, s) in tl_0.iter().enumerate() { + button_rect = self.input_button_ui(s, &mut columns[index]); + } + }); + ui.add_space(View::TAB_ITEMS_PADDING); + + let tl_1: Vec<&str> = vec!["_", "\\", "|", "~", "<", ">", "`", "√", "π", "•"]; + ui.columns(tl_1.len(), |columns| { + for (index, s) in tl_1.iter().enumerate() { + self.input_button_ui(s, &mut columns[index]); + } + }); + ui.add_space(View::TAB_ITEMS_PADDING); + + let tl_2: Vec<&str> = vec!["-", "/", ":", ";", "(", ")", "$", "&", "@", "\""]; + ui.columns(tl_2.len(), |columns| { + for (index, s) in tl_2.iter().enumerate() { + self.input_button_ui(s, &mut columns[index]); + } + }); + ui.add_space(View::TAB_ITEMS_PADDING); + + let tl_3: Vec<&str> = vec![".", ",", "?", "!", "€", "£", "¥", "¢", "ツ", BACKSPACE]; + ui.columns(tl_3.len(), |columns| { + for (index, s) in tl_3.iter().enumerate() { + if index == tl_3.len() - 1 { + // Check for backspace input. + self.button_ui(s, + Colors::red(), + Some(Colors::fill_lite()), + &mut columns[index], |_| { + Self::on_input(KeyboardInput::CLEAR); + }); + } else { + self.input_button_ui(s, &mut columns[index]); + } + } + }); + + button_rect + } + + /// Draw keyboard button. + fn button_ui(&self, + s: &str, + color: Color32, + bg: Option, + ui: &mut egui::Ui, + mut cb: impl FnMut(String)) -> Response { + ui.vertical_centered_justified(|ui| { + // Disable expansion on click/hover. + ui.style_mut().visuals.widgets.hovered.expansion = 0.0; + ui.style_mut().visuals.widgets.active.expansion = 0.0; + // Setup fill colors. + ui.visuals_mut().widgets.inactive.weak_bg_fill = Colors::white_or_black(false); + ui.visuals_mut().widgets.hovered.weak_bg_fill = Colors::fill_lite(); + ui.visuals_mut().widgets.active.weak_bg_fill = Colors::fill(); + // Setup stroke colors. + ui.visuals_mut().widgets.inactive.bg_stroke = View::item_stroke(); + ui.visuals_mut().widgets.hovered.bg_stroke = View::hover_stroke(); + ui.visuals_mut().widgets.active.bg_stroke = Stroke::NONE; + + let label = if self.uppercase { + s.to_uppercase() + } else { + s.to_string() + }; + let mut button = Button::new(RichText::new(label.clone()).size(17.0).color(color)); + if let Some(bg) = bg { + button = button.fill(bg); + } + let resp = button.ui(ui).on_hover_cursor(CursorIcon::PointingHand); + if resp.clicked() { + (cb)(label); + } + }).response + } + + /// Draw input button. + fn input_button_ui(&mut self, s: &str, ui: &mut egui::Ui) -> Rect { + let mut input = false; + let rect = self.button_ui(s, Colors::text_button(), None, ui, |l| { + input = true; + Self::on_input(KeyboardInput::TEXT(l)); + }).rect; + if input { + self.uppercase = false; + } + rect + } + + /// Save keyboard action to consume later. + fn on_input(action: KeyboardInput) { + let mut w_input = LAST_INPUT.write(); + *w_input = Some(action); + } + + /// Check last keyboard input action. + pub fn consume_action() -> Option { + let empty = { + let r_input = LAST_INPUT.read(); + r_input.is_none() + }; + if !empty { + let mut w_input = LAST_INPUT.write(); + let res = w_input.clone(); + *w_input = None; + return res; + } + None + } + + /// Check if keyboard is showing. + pub fn showing() -> bool { + SHOW_KEYBOARD.load(Ordering::Relaxed) + } + + /// Show keyboard. + pub fn show() { + SHOW_KEYBOARD.store(true, Ordering::Relaxed); + } + + /// Hide keyboard. + pub fn hide() { + SHOW_KEYBOARD.store(false, Ordering::Relaxed); + } +} \ No newline at end of file diff --git a/src/gui/views/mod.rs b/src/gui/views/mod.rs index e379459..c54be93 100644 --- a/src/gui/views/mod.rs +++ b/src/gui/views/mod.rs @@ -43,4 +43,7 @@ mod pull_to_refresh; pub use pull_to_refresh::*; mod scan; -pub use scan::*; \ No newline at end of file +pub use scan::*; + +mod keyboard; +pub use keyboard::*; \ No newline at end of file diff --git a/src/gui/views/modal.rs b/src/gui/views/modal.rs index 8a024b1..dd505c6 100755 --- a/src/gui/views/modal.rs +++ b/src/gui/views/modal.rs @@ -21,7 +21,7 @@ use egui::epaint::{RectShape, Shadow}; use egui::os::OperatingSystem; use crate::gui::Colors; -use crate::gui::views::{Content, View}; +use crate::gui::views::{Content, KeyboardContent, View}; use crate::gui::views::types::{ModalPosition, ModalState}; lazy_static! { @@ -70,10 +70,12 @@ impl Modal { w_state.modal.as_mut().unwrap().position = position; } - /// Mark [`Modal`] closed. + /// Close [`Modal`] by clearing its state.. pub fn close(&self) { let mut w_nav = MODAL_STATE.write(); w_nav.modal = None; + // Hide keyboard. + KeyboardContent::hide(); } /// Setup possibility to close [`Modal`]. diff --git a/src/gui/views/network/connections.rs b/src/gui/views/network/connections.rs index 9edbafe..8c8e9ae 100644 --- a/src/gui/views/network/connections.rs +++ b/src/gui/views/network/connections.rs @@ -96,7 +96,7 @@ impl ConnectionsContent { // 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::white_or_black(false), || { - self.show_add_ext_conn_modal(None, cb); + self.show_add_ext_conn_modal(None); }); ui.add_space(4.0); @@ -114,7 +114,7 @@ impl ConnectionsContent { ConnectionsConfig::remove_ext_conn(conn.id); }); View::item_button(ui, Rounding::default(), PENCIL, None, || { - self.show_add_ext_conn_modal(Some(conn.clone()), cb); + self.show_add_ext_conn_modal(Some(conn.clone())); }); }); }); @@ -234,15 +234,12 @@ impl ConnectionsContent { } /// Show [`Modal`] to add external connection. - pub fn show_add_ext_conn_modal(&mut self, - conn: Option, - cb: &dyn PlatformCallbacks) { + pub fn show_add_ext_conn_modal(&mut self, conn: Option) { self.ext_conn_modal = ExternalConnectionModal::new(conn); // Show modal. Modal::new(ExternalConnectionModal::NETWORK_ID) .position(ModalPosition::CenterTop) .title(t!("wallets.add_node")) .show(); - cb.show_keyboard(); } } \ No newline at end of file diff --git a/src/gui/views/network/modals/ext_conn.rs b/src/gui/views/network/modals/ext_conn.rs index 10c3d74..97e0e51 100644 --- a/src/gui/views/network/modals/ext_conn.rs +++ b/src/gui/views/network/modals/ext_conn.rs @@ -113,7 +113,6 @@ impl ExternalConnectionModal { self.ext_node_url_edit = "".to_string(); self.ext_node_secret_edit = "".to_string(); self.ext_node_url_error = false; - cb.hide_keyboard(); modal.close(); }); }); @@ -146,7 +145,6 @@ impl ExternalConnectionModal { self.ext_node_url_edit = "".to_string(); self.ext_node_secret_edit = "".to_string(); self.ext_node_url_error = false; - cb.hide_keyboard(); modal.close(); } }; diff --git a/src/gui/views/network/setup/dandelion.rs b/src/gui/views/network/setup/dandelion.rs index ada33b2..f3c9c9d 100644 --- a/src/gui/views/network/setup/dandelion.rs +++ b/src/gui/views/network/setup/dandelion.rs @@ -96,28 +96,28 @@ impl DandelionSetup { ui.vertical_centered(|ui| { // Show epoch duration setup. - self.epoch_ui(ui, cb); + self.epoch_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show embargo expiration time setup. - self.embargo_ui(ui, cb); + self.embargo_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show aggregation period setup. - self.aggregation_ui(ui, cb); + self.aggregation_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show Stem phase probability setup. - self.stem_prob_ui(ui, cb); + self.stem_prob_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); @@ -133,7 +133,7 @@ impl DandelionSetup { } /// Draw epoch duration setup content. - fn epoch_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn epoch_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.epoch_duration")) .size(16.0) .color(Colors::gray()) @@ -149,7 +149,6 @@ impl DandelionSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -188,7 +187,6 @@ impl DandelionSetup { let on_save = || { if let Ok(epoch) = self.epoch_edit.parse::() { NodeConfig::save_dandelion_epoch(epoch); - cb.hide_keyboard(); modal.close(); } }; @@ -202,7 +200,6 @@ impl DandelionSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -215,7 +212,7 @@ impl DandelionSetup { } /// Draw embargo expiration time setup content. - fn embargo_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn embargo_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.embargo_timer")) .size(16.0) .color(Colors::gray()) @@ -230,7 +227,6 @@ impl DandelionSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -269,7 +265,6 @@ impl DandelionSetup { let on_save = || { if let Ok(embargo) = self.embargo_edit.parse::() { NodeConfig::save_dandelion_embargo(embargo); - cb.hide_keyboard(); modal.close(); } }; @@ -283,7 +278,6 @@ impl DandelionSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -296,7 +290,7 @@ impl DandelionSetup { } /// Draw aggregation period setup content. - fn aggregation_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn aggregation_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.aggregation_period")) .size(16.0) .color(Colors::gray()) @@ -312,7 +306,6 @@ impl DandelionSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -351,7 +344,6 @@ impl DandelionSetup { let on_save = || { if let Ok(embargo) = self.aggregation_edit.parse::() { NodeConfig::save_dandelion_aggregation(embargo); - cb.hide_keyboard(); modal.close(); } }; @@ -365,7 +357,6 @@ impl DandelionSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -378,7 +369,7 @@ impl DandelionSetup { } /// Draw stem phase probability setup content. - fn stem_prob_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn stem_prob_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.stem_probability")) .size(16.0) .color(Colors::gray()) @@ -394,7 +385,6 @@ impl DandelionSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -433,7 +423,6 @@ impl DandelionSetup { let on_save = || { if let Ok(prob) = self.stem_prob_edit.parse::() { NodeConfig::save_stem_probability(prob); - cb.hide_keyboard(); modal.close(); } }; @@ -447,7 +436,6 @@ impl DandelionSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); diff --git a/src/gui/views/network/setup/node.rs b/src/gui/views/network/setup/node.rs index db31668..48a3a09 100644 --- a/src/gui/views/network/setup/node.rs +++ b/src/gui/views/network/setup/node.rs @@ -185,12 +185,12 @@ impl NodeSetup { NodeConfig::save_api_address(selected_ip, &api_port); }); // Show API port setup. - self.api_port_setup_ui(ui, cb); + self.api_port_setup_ui(ui); // Show API secret setup. - self.secret_ui(API_SECRET_MODAL, ui, cb); + self.secret_ui(API_SECRET_MODAL, ui); ui.add_space(12.0); // Show Foreign API secret setup. - self.secret_ui(FOREIGN_API_SECRET_MODAL, ui, cb); + self.secret_ui(FOREIGN_API_SECRET_MODAL, ui); ui.add_space(6.0); }); } @@ -201,7 +201,7 @@ impl NodeSetup { ui.vertical_centered(|ui| { // Show FTL setup. - self.ftl_ui(ui, cb); + self.ftl_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); @@ -250,7 +250,7 @@ impl NodeSetup { } /// Draw API port setup content. - fn api_port_setup_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn api_port_setup_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.api_port")).size(16.0).color(Colors::gray())); ui.add_space(6.0); @@ -265,7 +265,6 @@ impl NodeSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); @@ -325,7 +324,6 @@ impl NodeSetup { } self.is_api_port_available = true; - cb.hide_keyboard(); modal.close(); } }; @@ -338,7 +336,6 @@ impl NodeSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { - cb.hide_keyboard(); modal.close(); }); }); @@ -351,7 +348,7 @@ impl NodeSetup { } /// Draw API secret token setup content. - fn secret_ui(&mut self, modal_id: &'static str, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn secret_ui(&mut self, modal_id: &'static str, ui: &mut egui::Ui) { let secret_title = match modal_id { API_SECRET_MODAL => t!("network_settings.api_secret"), _ => t!("network_settings.foreign_api_secret") @@ -381,7 +378,6 @@ impl NodeSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); } @@ -428,7 +424,6 @@ impl NodeSetup { NodeConfig::save_foreign_api_secret(&secret); } }; - cb.hide_keyboard(); modal.close(); }; @@ -440,7 +435,6 @@ impl NodeSetup { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { - cb.hide_keyboard(); modal.close(); }); }); @@ -453,7 +447,7 @@ impl NodeSetup { } /// Draw FTL setup content. - fn ftl_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn ftl_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.ftl")) .size(16.0) .color(Colors::gray()) @@ -471,7 +465,6 @@ impl NodeSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.ftl_description")) @@ -514,7 +507,6 @@ impl NodeSetup { let on_save = || { if let Ok(ftl) = self.ftl_edit.parse::() { NodeConfig::save_ftl(ftl); - cb.hide_keyboard(); modal.close(); } }; @@ -528,7 +520,6 @@ impl NodeSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); diff --git a/src/gui/views/network/setup/p2p.rs b/src/gui/views/network/setup/p2p.rs index d47da00..04d3a21 100644 --- a/src/gui/views/network/setup/p2p.rs +++ b/src/gui/views/network/setup/p2p.rs @@ -162,14 +162,14 @@ impl P2PSetup { ui.vertical_centered(|ui| { // Show p2p port setup. - self.port_ui(ui, cb); + self.port_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show seeding type setup. - self.seeding_type_ui(ui, cb); + self.seeding_type_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); @@ -180,7 +180,7 @@ impl P2PSetup { .color(Colors::gray())); ui.add_space(6.0); // Show allowed peers setup. - self.peer_list_ui(ui, &PeerType::Allowed, cb); + self.peer_list_ui(ui, &PeerType::Allowed); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); @@ -191,7 +191,7 @@ impl P2PSetup { .color(Colors::gray())); ui.add_space(6.0); // Show denied peers setup. - self.peer_list_ui(ui, &PeerType::Denied, cb); + self.peer_list_ui(ui, &PeerType::Denied); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); @@ -202,7 +202,7 @@ impl P2PSetup { .color(Colors::gray())); ui.add_space(6.0); // Show preferred peers setup. - self.peer_list_ui(ui, &PeerType::Preferred, cb); + self.peer_list_ui(ui, &PeerType::Preferred); ui.add_space(6.0); @@ -210,21 +210,21 @@ impl P2PSetup { ui.add_space(6.0); // Show ban window setup. - self.ban_window_ui(ui, cb); + self.ban_window_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show maximum inbound peers value setup. - self.max_inbound_ui(ui, cb); + self.max_inbound_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show maximum outbound peers value setup. - self.max_outbound_ui(ui, cb); + self.max_outbound_ui(ui); if !Node::is_restarting() && !self.peers_reset { ui.add_space(6.0); @@ -238,7 +238,7 @@ impl P2PSetup { } /// Draw p2p port setup content. - fn port_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn port_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.p2p_port")) .size(16.0) .color(Colors::gray()) @@ -257,7 +257,6 @@ impl P2PSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); @@ -312,7 +311,6 @@ impl P2PSetup { Node::restart(); } self.is_port_available = true; - cb.hide_keyboard(); modal.close(); } }; @@ -326,7 +324,6 @@ impl P2PSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -340,7 +337,7 @@ impl P2PSetup { } /// Draw peer list content based on provided [`PeerType`]. - fn peer_list_ui(&mut self, ui: &mut egui::Ui, peer_type: &PeerType, cb: &dyn PlatformCallbacks) { + fn peer_list_ui(&mut self, ui: &mut egui::Ui, peer_type: &PeerType) { let peers = match peer_type { PeerType::DefaultSeed => { if AppConfig::chain_type() == ChainTypes::Testnet { @@ -409,7 +406,6 @@ impl P2PSetup { .position(ModalPosition::CenterTop) .title(modal_title) .show(); - cb.show_keyboard(); }); } ui.add_space(6.0); @@ -462,7 +458,6 @@ impl P2PSetup { } self.is_port_available = true; - cb.hide_keyboard(); modal.close(); } }; @@ -476,7 +471,6 @@ impl P2PSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -490,7 +484,7 @@ impl P2PSetup { } /// Draw seeding type setup content. - fn seeding_type_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn seeding_type_ui(&mut self, ui: &mut egui::Ui) { let title = Self::DNS_SEEDS_TITLE; ui.label(RichText::new(title).size(16.0).color(Colors::gray())); ui.add_space(2.0); @@ -506,11 +500,11 @@ impl P2PSetup { } else { PeerType::CustomSeed }; - self.peer_list_ui(ui, &peers_type, cb); + self.peer_list_ui(ui, &peers_type); } /// Draw ban window setup content. - fn ban_window_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn ban_window_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.ban_window")) .size(16.0) .color(Colors::gray()) @@ -528,7 +522,6 @@ impl P2PSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.ban_window_desc")) @@ -572,7 +565,6 @@ impl P2PSetup { let on_save = || { if let Ok(ban_window) = self.ban_window_edit.parse::() { NodeConfig::save_p2p_ban_window(ban_window); - cb.hide_keyboard(); modal.close(); } }; @@ -586,7 +578,6 @@ impl P2PSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -599,7 +590,7 @@ impl P2PSetup { } /// Draw maximum number of inbound peers setup content. - fn max_inbound_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn max_inbound_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.max_inbound_count")) .size(16.0) .color(Colors::gray()) @@ -617,7 +608,6 @@ impl P2PSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -656,7 +646,6 @@ impl P2PSetup { let on_save = || { if let Ok(max_inbound) = self.max_inbound_count.parse::() { NodeConfig::save_max_inbound_peers(max_inbound); - cb.hide_keyboard(); modal.close(); } }; @@ -670,7 +659,6 @@ impl P2PSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -683,7 +671,7 @@ impl P2PSetup { } /// Draw maximum number of outbound peers setup content. - fn max_outbound_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn max_outbound_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.max_outbound_count")) .size(16.0) .color(Colors::gray()) @@ -700,7 +688,6 @@ impl P2PSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -739,7 +726,6 @@ impl P2PSetup { let on_save = || { if let Ok(max_outbound) = self.max_outbound_count.parse::() { NodeConfig::save_max_outbound_peers(max_outbound); - cb.hide_keyboard(); modal.close(); } }; @@ -753,7 +739,6 @@ impl P2PSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); diff --git a/src/gui/views/network/setup/pool.rs b/src/gui/views/network/setup/pool.rs index adb6bcd..70b3ac0 100644 --- a/src/gui/views/network/setup/pool.rs +++ b/src/gui/views/network/setup/pool.rs @@ -104,40 +104,40 @@ impl PoolSetup { ui.vertical_centered(|ui| { // Show base fee setup. - self.fee_base_ui(ui, cb); + self.fee_base_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show reorg cache retention period setup. - self.reorg_period_ui(ui, cb); + self.reorg_period_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show pool size setup. - self.pool_size_ui(ui, cb); + self.pool_size_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show stem pool size setup. - self.stem_size_ui(ui, cb); + self.stem_size_ui(ui); ui.add_space(6.0); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show max weight of transactions setup. - self.max_weight_ui(ui, cb); + self.max_weight_ui(ui); }); } /// Draw fee base setup content. - fn fee_base_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn fee_base_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.pool_fee")) .size(16.0) .color(Colors::gray()) @@ -153,7 +153,6 @@ impl PoolSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -191,7 +190,6 @@ impl PoolSetup { let on_save = || { if let Ok(fee) = self.fee_base_edit.parse::() { NodeConfig::save_base_fee(fee); - cb.hide_keyboard(); modal.close(); } }; @@ -205,7 +203,6 @@ impl PoolSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -219,7 +216,7 @@ impl PoolSetup { } /// Draw reorg cache retention period setup content. - fn reorg_period_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn reorg_period_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.reorg_period")) .size(16.0) .color(Colors::gray()) @@ -236,7 +233,6 @@ impl PoolSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -274,7 +270,6 @@ impl PoolSetup { let on_save = || { if let Ok(period) = self.reorg_period_edit.parse::() { NodeConfig::save_reorg_cache_period(period); - cb.hide_keyboard(); modal.close(); } }; @@ -288,7 +283,6 @@ impl PoolSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -302,7 +296,7 @@ impl PoolSetup { } /// Draw maximum number of transactions in the pool setup content. - fn pool_size_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn pool_size_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.max_tx_pool")) .size(16.0) .color(Colors::gray()) @@ -318,7 +312,6 @@ impl PoolSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -356,7 +349,6 @@ impl PoolSetup { let on_save = || { if let Ok(size) = self.pool_size_edit.parse::() { NodeConfig::save_max_pool_size(size); - cb.hide_keyboard(); modal.close(); } }; @@ -370,7 +362,6 @@ impl PoolSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -384,7 +375,7 @@ impl PoolSetup { } /// Draw maximum number of transactions in the stempool setup content. - fn stem_size_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn stem_size_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.max_tx_stempool")) .size(16.0) .color(Colors::gray()) @@ -402,7 +393,6 @@ impl PoolSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -440,7 +430,6 @@ impl PoolSetup { let on_save = || { if let Ok(size) = self.stempool_size_edit.parse::() { NodeConfig::save_max_stempool_size(size); - cb.hide_keyboard(); modal.close(); } }; @@ -454,7 +443,6 @@ impl PoolSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -468,7 +456,7 @@ impl PoolSetup { } /// Draw maximum total weight of transactions setup content. - fn max_weight_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn max_weight_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.max_tx_weight")) .size(16.0) .color(Colors::gray()) @@ -486,7 +474,6 @@ impl PoolSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -524,7 +511,6 @@ impl PoolSetup { let on_save = || { if let Ok(weight) = self.max_weight_edit.parse::() { NodeConfig::save_mineable_max_weight(weight); - cb.hide_keyboard(); modal.close(); } }; @@ -538,7 +524,6 @@ impl PoolSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); diff --git a/src/gui/views/network/setup/stratum.rs b/src/gui/views/network/setup/stratum.rs index 3c98022..a06a4e7 100644 --- a/src/gui/views/network/setup/stratum.rs +++ b/src/gui/views/network/setup/stratum.rs @@ -227,19 +227,19 @@ impl StratumSetup { }); // Show stratum port setup. - self.port_setup_ui(ui, cb); + self.port_setup_ui(ui); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show attempt time setup. - self.attempt_time_ui(ui, cb); + self.attempt_time_ui(ui); View::horizontal_line(ui, Colors::item_stroke()); ui.add_space(6.0); // Show minimum acceptable share difficulty setup. - self.min_diff_ui(ui, cb); + self.min_diff_ui(ui); }); } @@ -254,7 +254,7 @@ impl StratumSetup { } /// Draw stratum port value setup content. - fn port_setup_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn port_setup_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.stratum_port")) .size(16.0) .color(Colors::gray()) @@ -271,7 +271,6 @@ impl StratumSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(12.0); @@ -330,7 +329,6 @@ impl StratumSetup { NodeConfig::save_stratum_address(&stratum_ip, &self.stratum_port_edit); self.is_port_available = true; - cb.hide_keyboard(); modal.close(); } }; @@ -344,7 +342,6 @@ impl StratumSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -358,7 +355,7 @@ impl StratumSetup { } /// Draw attempt time value setup content. - fn attempt_time_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn attempt_time_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.attempt_time")) .size(16.0) .color(Colors::gray()) @@ -375,7 +372,6 @@ impl StratumSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); ui.label(RichText::new(t!("network_settings.attempt_time_desc")) @@ -419,7 +415,6 @@ impl StratumSetup { let on_save = || { if let Ok(time) = self.attempt_time_edit.parse::() { NodeConfig::save_stratum_attempt_time(time); - cb.hide_keyboard(); modal.close(); } }; @@ -433,7 +428,6 @@ impl StratumSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -446,7 +440,7 @@ impl StratumSetup { } /// Draw minimum share difficulty value setup content. - fn min_diff_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn min_diff_ui(&mut self, ui: &mut egui::Ui) { ui.label(RichText::new(t!("network_settings.min_share_diff")) .size(16.0) .color(Colors::gray()) @@ -463,7 +457,6 @@ impl StratumSetup { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(6.0); } @@ -502,7 +495,6 @@ impl StratumSetup { let on_save = || { if let Ok(diff) = self.min_share_diff_edit.parse::() { NodeConfig::save_stratum_min_share_diff(diff); - cb.hide_keyboard(); modal.close(); } }; @@ -516,7 +508,6 @@ impl StratumSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); diff --git a/src/gui/views/types.rs b/src/gui/views/types.rs index 7b4a4b5..afa4d1e 100644 --- a/src/gui/views/types.rs +++ b/src/gui/views/types.rs @@ -94,6 +94,8 @@ pub struct TextEditOptions { pub scan_qr: bool, /// Callback when scan button was pressed. pub scan_pressed: bool, + /// Callback when Enter key was pressed. + pub enter_pressed: bool, } impl TextEditOptions { @@ -107,6 +109,7 @@ impl TextEditOptions { paste: false, scan_qr: false, scan_pressed: false, + enter_pressed: false, } } diff --git a/src/gui/views/views.rs b/src/gui/views/views.rs index 9bc4b79..730132d 100644 --- a/src/gui/views/views.rs +++ b/src/gui/views/views.rs @@ -13,8 +13,6 @@ // limitations under the License. use std::sync::atomic::{AtomicI32, Ordering}; -use std::sync::Arc; -use parking_lot::RwLock; use lazy_static::lazy_static; use egui::{Align, Button, CursorIcon, Layout, lerp, PointerState, Rect, Response, Rgba, RichText, Sense, SizeHint, Spinner, TextBuffer, TextStyle, TextureHandle, TextureOptions, Widget, UiBuilder}; @@ -30,6 +28,7 @@ use crate::AppConfig; use crate::gui::Colors; use crate::gui::icons::{CHECK_SQUARE, CLIPBOARD_TEXT, COPY, EYE, EYE_SLASH, SCAN, SQUARE}; use crate::gui::platform::PlatformCallbacks; +use crate::gui::views::{KeyboardContent, KeyboardInput}; use crate::gui::views::types::{LinePosition, TextEditOptions}; pub struct View; @@ -450,59 +449,80 @@ impl View { .password(show_pass) .cursor_at_end(true) .ui(ui); - // Show keyboard on click. - if text_edit_resp.clicked() { - text_edit_resp.request_focus(); - cb.show_keyboard(); + // Store focusing state on click or from options. + let focus_id = egui::Id::new("focused_input"); + if text_edit_resp.clicked() || options.focus { + ui.data_mut(|data| { + data.insert_temp(focus_id, options.id); + }); } - // Setup focus on input field. - if options.focus { + let focus = ui.data(|data| { + data.get_temp(focus_id) + }).unwrap_or(egui::Id::from("")); + if focus == options.id { text_edit_resp.request_focus(); - cb.show_keyboard(); + KeyboardContent::show(); } - - // Apply text from input on Android as temporary fix for egui. + // Apply text from software input. if text_edit_resp.has_focus() { - Self::on_soft_input(ui, options.id, value); + options.focus = true; + options.enter_pressed = Self::on_soft_input(ui, options.id, false, value); } }); }); } - /// Apply soft keyboard input data to provided String. - pub fn on_soft_input(ui: &mut egui::Ui, id: egui::Id, value: &mut String) { - let os = OperatingSystem::from_target_os(); - if os == OperatingSystem::Android { - let mut w_input = LAST_SOFT_KEYBOARD_INPUT.write(); - - if !w_input.is_empty() { - let mut state = TextEditState::load(ui.ctx(), id).unwrap(); - match state.cursor.char_range() { - None => {} - Some(range) => { - let mut r = range.clone(); - - let mut index = r.primary.index; - - value.insert_text(w_input.as_str(), index); - index = index + 1; - - if index == 0 { - r.primary.index = value.len(); - r.secondary.index = r.primary.index; - } else { - r.primary.index = index; - r.secondary.index = r.primary.index; + /// Apply soft keyboard input data to provided String, returns `true` if Enter was pressed. + fn on_soft_input(ui: &mut egui::Ui, id: egui::Id, multiline: bool, value: &mut String) -> bool { + if let Some(input) = KeyboardContent::consume_action() { + let mut enter_pressed = false; + let mut state = TextEditState::load(ui.ctx(), id).unwrap(); + match state.cursor.char_range() { + None => {} + Some(range) => { + let mut r = range.clone(); + let mut index = r.primary.index; + match input { + KeyboardInput::TEXT(text) => { + value.insert_text(text.as_str(), index); + index = index + 1; + } + KeyboardInput::CLEAR => { + if index != 0 { + *value = { + let part1: String = value.chars() + .skip(0) + .take(index - 1) + .collect(); + let part2: String = value.chars() + .skip(index) + .take(value.len() - index) + .collect(); + format!("{}{}", part1, part2) + }; + index = index - 1; + } + } + KeyboardInput::ENTER => { + if multiline { + value.insert_text("\n", index); + index = index + 1; + } else { + enter_pressed = true; + } } - state.cursor.set_char_range(Some(r)); - TextEditState::store(state, ui.ctx(), id); } + // Setup cursor index. + r.primary.index = index; + r.secondary.index = r.primary.index; + + state.cursor.set_char_range(Some(r)); + TextEditState::store(state, ui.ctx(), id); } } - - *w_input = "".to_string(); - ui.ctx().request_repaint(); + return enter_pressed; } + false } /// Calculate item background/button rounding based on item index. @@ -806,34 +826,4 @@ pub extern "C" fn Java_mw_gri_android_MainActivity_onDisplayInsets( RIGHT_DISPLAY_INSET.store(array[1], Ordering::Relaxed); BOTTOM_DISPLAY_INSET.store(array[2], Ordering::Relaxed); LEFT_DISPLAY_INSET.store(array[3], Ordering::Relaxed); -} - -lazy_static! { - static ref LAST_SOFT_KEYBOARD_INPUT: Arc> = Arc::new(RwLock::new("".into())); -} - -#[allow(dead_code)] -#[cfg(target_os = "android")] -#[allow(non_snake_case)] -#[no_mangle] -/// Callback from Java code with last entered character from soft keyboard. -pub extern "C" fn Java_mw_gri_android_MainActivity_onInput( - _env: jni::JNIEnv, - _class: jni::objects::JObject, - char: jni::sys::jstring -) { - use jni::objects::JString; - use std::ops::Add; - - unsafe { - let j_obj = JString::from_raw(char); - let j_str = _env.get_string_unchecked(j_obj.as_ref()).unwrap(); - match j_str.to_str() { - Ok(str) => { - let mut w_input = LAST_SOFT_KEYBOARD_INPUT.write(); - *w_input = w_input.clone().add(str); - } - Err(_) => {} - } - } } \ No newline at end of file diff --git a/src/gui/views/wallets/content.rs b/src/gui/views/wallets/content.rs index e832f1d..e951420 100644 --- a/src/gui/views/wallets/content.rs +++ b/src/gui/views/wallets/content.rs @@ -202,7 +202,7 @@ impl WalletsContent { ui.vertical_centered(|ui| { let pressed = Modal::opened() == Some(ADD_WALLET_MODAL); View::tab_button(ui, PLUS, pressed, |_| { - self.show_add_wallet_modal(cb); + self.show_add_wallet_modal(); }); }); @@ -239,7 +239,7 @@ impl WalletsContent { ui.ctx().request_repaint_after(Duration::from_millis(1000)); } // Show wallet list. - self.wallet_list_ui(ui, cb); + self.wallet_list_ui(ui); }); } @@ -282,7 +282,7 @@ impl WalletsContent { // Show wallet creation button. let add_text = format!("{} {}", FOLDER_PLUS, t!("wallets.add")); View::button(ui, add_text, Colors::white_or_black(false), || { - self.show_add_wallet_modal(cb); + self.show_add_wallet_modal(); }); }); } else { @@ -307,7 +307,7 @@ impl WalletsContent { } /// Handle data from deeplink or opened file. - pub fn on_data(&mut self, ui: &mut egui::Ui, data: Option, cb: &dyn PlatformCallbacks) { + pub fn on_data(&mut self, ui: &mut egui::Ui, data: Option) { let wallets_size = self.wallets.list().len(); if wallets_size == 0 { return; @@ -322,7 +322,7 @@ impl WalletsContent { if w.is_open() { self.wallet_content = Some(WalletContent::new(w, data)); } else { - self.show_opening_modal(w, data, cb); + self.show_opening_modal(w, data); } } else { self.show_wallet_selection_modal(data); @@ -330,13 +330,12 @@ impl WalletsContent { } /// Show initial wallet creation [`Modal`]. - pub fn show_add_wallet_modal(&mut self, cb: &dyn PlatformCallbacks) { + pub fn show_add_wallet_modal(&mut self) { self.add_wallet_modal_content = Some(AddWalletModal::default()); Modal::new(ADD_WALLET_MODAL) .position(ModalPosition::CenterTop) .title(t!("wallets.add")) .show(); - cb.show_keyboard(); } /// Show wallet selection with provided optional data. @@ -492,9 +491,7 @@ impl WalletsContent { } /// Draw list of wallets. - fn wallet_list_ui(&mut self, - ui: &mut egui::Ui, - cb: &dyn PlatformCallbacks) { + fn wallet_list_ui(&mut self, ui: &mut egui::Ui) { ScrollArea::vertical() .id_salt("wallet_list_scroll") .scroll_bar_visibility(ScrollBarVisibility::AlwaysHidden) @@ -517,9 +514,9 @@ impl WalletsContent { // Check if wallet reopen is needed. if w.reopen_needed() && !w.is_open() { w.set_reopen(false); - self.show_opening_modal(w.clone(), None, cb); + self.show_opening_modal(w.clone(), None); } - self.wallet_item_ui(ui, w, cb); + self.wallet_item_ui(ui, w); ui.add_space(5.0); } }); @@ -527,10 +524,7 @@ impl WalletsContent { } /// Draw wallet list item. - fn wallet_item_ui(&mut self, - ui: &mut egui::Ui, - wallet: &Wallet, - cb: &dyn PlatformCallbacks) { + fn wallet_item_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet) { let config = wallet.get_config(); let current = if let Some(content) = &self.wallet_content { content.wallet.get_config().id == config.id && wallet.is_open() @@ -553,7 +547,7 @@ impl WalletsContent { if !wallet.is_open() { // Show button to open closed wallet. View::item_button(ui, View::item_rounding(0, 1, true), FOLDER_OPEN, None, || { - self.show_opening_modal(wallet.clone(), None, cb); + self.show_opening_modal(wallet.clone(), None); }); if !wallet.syncing() { let mut show_selection = false; @@ -628,17 +622,13 @@ impl WalletsContent { } /// Show [`Modal`] to select and open wallet. - fn show_opening_modal(&mut self, - wallet: Wallet, - data: Option, - cb: &dyn PlatformCallbacks) { + fn show_opening_modal(&mut self, wallet: Wallet, data: Option) { self.wallet_content = Some(WalletContent::new(wallet.clone(), None)); self.open_wallet_content = Some(OpenWalletModal::new(wallet, data)); Modal::new(OPEN_WALLET_MODAL) .position(ModalPosition::CenterTop) .title(t!("wallets.open")) .show(); - cb.show_keyboard(); } /// Check if it's possible to show [`WalletsContent`] and [`WalletContent`] panels at same time. diff --git a/src/gui/views/wallets/creation/mnemonic.rs b/src/gui/views/wallets/creation/mnemonic.rs index 81a2a2d..835bd2e 100644 --- a/src/gui/views/wallets/creation/mnemonic.rs +++ b/src/gui/views/wallets/creation/mnemonic.rs @@ -87,7 +87,7 @@ impl MnemonicSetup { ui.add_space(6.0); // Show words setup. - self.word_list_ui(ui, self.mnemonic.mode() == PhraseMode::Import, cb); + self.word_list_ui(ui, self.mnemonic.mode() == PhraseMode::Import); } /// Draw content for phrase confirmation step. @@ -101,7 +101,7 @@ impl MnemonicSetup { ui.label(RichText::new(text).size(16.0).color(Colors::gray())); }); ui.add_space(4.0); - self.word_list_ui(ui, true, cb); + self.word_list_ui(ui, true); } /// Draw mode and size setup. @@ -149,7 +149,7 @@ impl MnemonicSetup { } /// Draw grid of words for mnemonic phrase. - fn word_list_ui(&mut self, ui: &mut egui::Ui, edit: bool, cb: &dyn PlatformCallbacks) { + fn word_list_ui(&mut self, ui: &mut egui::Ui, edit: bool) { ui.add_space(6.0); ui.scope(|ui| { // Setup spacing between columns. @@ -167,25 +167,25 @@ impl MnemonicSetup { ui.columns(cols, |columns| { columns[0].horizontal(|ui| { let word = chunk.get(0).unwrap(); - self.word_item_ui(ui, word_number, word, edit, cb); + self.word_item_ui(ui, word_number, word, edit); }); columns[1].horizontal(|ui| { word_number += 1; let word = chunk.get(1).unwrap(); - self.word_item_ui(ui, word_number, word, edit, cb); + self.word_item_ui(ui, word_number, word, edit); }); if size > 2 { columns[2].horizontal(|ui| { word_number += 1; let word = chunk.get(2).unwrap(); - self.word_item_ui(ui, word_number, word, edit, cb); + self.word_item_ui(ui, word_number, word, edit); }); } if size > 3 { columns[3].horizontal(|ui| { word_number += 1; let word = chunk.get(3).unwrap(); - self.word_item_ui(ui, word_number, word, edit, cb); + self.word_item_ui(ui, word_number, word, edit); }); } }); @@ -193,7 +193,7 @@ impl MnemonicSetup { ui.columns(cols, |columns| { columns[0].horizontal(|ui| { let word = chunk.get(0).unwrap(); - self.word_item_ui(ui, word_number, word, edit, cb); + self.word_item_ui(ui, word_number, word, edit); }); }); } @@ -207,8 +207,7 @@ impl MnemonicSetup { ui: &mut egui::Ui, num: usize, word: &PhraseWord, - edit: bool, - cb: &dyn PlatformCallbacks) { + edit: bool) { let color = if !word.valid || (word.text.is_empty() && !self.mnemonic.valid()) { Colors::red() } else { @@ -225,7 +224,6 @@ impl MnemonicSetup { .position(ModalPosition::CenterTop) .title(t!("wallets.recovery_phrase")) .show(); - cb.show_keyboard(); }); ui.label(RichText::new(format!("#{} {}", num, word.text)) .size(17.0) @@ -276,7 +274,6 @@ impl MnemonicSetup { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -295,7 +292,6 @@ impl MnemonicSetup { (!next_word.as_ref().unwrap().text.is_empty() && next_word.unwrap().valid); if close_modal { - cb.hide_keyboard(); modal.close(); } else { self.word_index_edit += 1; diff --git a/src/gui/views/wallets/modals/add.rs b/src/gui/views/wallets/modals/add.rs index 4975021..ade55dc 100644 --- a/src/gui/views/wallets/modals/add.rs +++ b/src/gui/views/wallets/modals/add.rs @@ -48,6 +48,8 @@ impl AddWalletModal { cb: &dyn PlatformCallbacks, mut on_input: impl FnMut(String, ZeroingString)) { ui.add_space(6.0); + + let mut enter_pressed = false; ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.name")) .size(17.0) @@ -62,8 +64,11 @@ impl AddWalletModal { name_edit_opts.focus = true; } View::text_edit(ui, cb, &mut self.name_edit, &mut name_edit_opts); - ui.add_space(8.0); + View::on_enter_key(ui, || { + name_edit_opts.enter_pressed = name_edit_opts.focus; + }); + ui.add_space(8.0); ui.label(RichText::new(t!("wallets.pass")) .size(17.0) .color(Colors::gray())); @@ -73,7 +78,12 @@ impl AddWalletModal { let mut pass_text_edit_opts = TextEditOptions::new(Id::from(modal.id).with("pass")) .password() .no_focus(); + if name_edit_opts.enter_pressed { + pass_text_edit_opts.focus = true; + } View::text_edit(ui, cb, &mut self.pass_edit, &mut pass_text_edit_opts); + enter_pressed = pass_text_edit_opts.enter_pressed; + ui.add_space(12.0); }); @@ -86,7 +96,6 @@ impl AddWalletModal { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -97,7 +106,6 @@ impl AddWalletModal { if name.is_empty() || pass.is_empty() { return; } - cb.hide_keyboard(); modal.close(); on_input(name, ZeroingString::from(pass)); }; @@ -106,6 +114,9 @@ impl AddWalletModal { View::on_enter_key(ui, || { (on_next)(); }); + if enter_pressed { + (on_next)(); + } View::button(ui, t!("continue"), Colors::white_or_black(false), on_next); }); diff --git a/src/gui/views/wallets/modals/open.rs b/src/gui/views/wallets/modals/open.rs index 6e8c64b..3f4149c 100644 --- a/src/gui/views/wallets/modals/open.rs +++ b/src/gui/views/wallets/modals/open.rs @@ -52,6 +52,8 @@ impl OpenWalletModal { cb: &dyn PlatformCallbacks, mut on_continue: impl FnMut(Wallet, Option)) { ui.add_space(6.0); + + let mut enter_pressed = false; ui.vertical_centered(|ui| { ui.label(RichText::new(t!("wallets.pass")) .size(17.0) @@ -61,6 +63,7 @@ impl OpenWalletModal { // Show password input. let mut pass_edit_opts = TextEditOptions::new(Id::from(modal.id)).password(); View::text_edit(ui, cb, &mut self.pass_edit, &mut pass_edit_opts); + enter_pressed = pass_edit_opts.enter_pressed; // Show information when password is empty. if self.pass_edit.is_empty() { @@ -87,7 +90,6 @@ impl OpenWalletModal { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -101,7 +103,6 @@ impl OpenWalletModal { match self.wallet.open(ZeroingString::from(pass)) { Ok(_) => { self.pass_edit = "".to_string(); - cb.hide_keyboard(); modal.close(); on_continue(self.wallet.clone(), self.data.clone()); } @@ -113,6 +114,9 @@ impl OpenWalletModal { View::on_enter_key(ui, || { (on_continue)(); }); + if enter_pressed { + (on_continue)(); + } View::button(ui, t!("continue"), Colors::white_or_black(false), on_continue); }); diff --git a/src/gui/views/wallets/wallet/content.rs b/src/gui/views/wallets/wallet/content.rs index 6a82087..15c952e 100644 --- a/src/gui/views/wallets/wallet/content.rs +++ b/src/gui/views/wallets/wallet/content.rs @@ -138,7 +138,7 @@ impl WalletContent { match result { QrScanResult::Address(address) => { self.current_tab = - Box::new(WalletTransport::new(Some(address.to_string()), cb)); + Box::new(WalletTransport::new(Some(address.to_string()))); } _ => { self.current_tab = @@ -409,7 +409,7 @@ impl WalletContent { }); columns[2].vertical_centered_justified(|ui| { View::tab_button(ui, BRIDGE, current_type == WalletTabType::Transport, |_| { - self.current_tab = Box::new(WalletTransport::new(None, cb)); + self.current_tab = Box::new(WalletTransport::new(None)); }); }); columns[3].vertical_centered_justified(|ui| { diff --git a/src/gui/views/wallets/wallet/messages/content.rs b/src/gui/views/wallets/wallet/messages/content.rs index 27670bf..b54df90 100644 --- a/src/gui/views/wallets/wallet/messages/content.rs +++ b/src/gui/views/wallets/wallet/messages/content.rs @@ -107,7 +107,7 @@ impl WalletMessages { ui.add_space(3.0); // Show creation of request to send or receive funds. - self.request_ui(ui, wallet, cb); + self.request_ui(ui, wallet); ui.add_space(12.0); View::horizontal_line(ui, Colors::item_stroke()); @@ -173,10 +173,7 @@ impl WalletMessages { } /// Draw creation of request to send or receive funds. - fn request_ui(&mut self, - ui: &mut egui::Ui, - wallet: &Wallet, - cb: &dyn PlatformCallbacks) { + fn request_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet) { ui.label(RichText::new(t!("wallets.create_request_desc")) .size(16.0) .color(Colors::inactive_text())); @@ -195,31 +192,31 @@ impl WalletMessages { send_text, Colors::red(), Colors::white_or_black(false), || { - self.show_request_modal(false, cb); + self.show_request_modal(false); }); }); columns[1].vertical_centered_justified(|ui| { - self.receive_button_ui(ui, cb); + self.receive_button_ui(ui); }); }); } else { - self.receive_button_ui(ui, cb); + self.receive_button_ui(ui); } } /// Draw invoice request creation button. - fn receive_button_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn receive_button_ui(&mut self, ui: &mut egui::Ui) { let receive_text = format!("{} {}", DOWNLOAD_SIMPLE, t!("wallets.receive")); View::colored_text_button(ui, receive_text, Colors::green(), Colors::white_or_black(false), || { - self.show_request_modal(true, cb); + self.show_request_modal(true); }); } /// Show [`Modal`] to create invoice or sending request. - fn show_request_modal(&mut self, invoice: bool, cb: &dyn PlatformCallbacks) { + fn show_request_modal(&mut self, invoice: bool) { self.request_modal_content = Some(MessageRequestModal::new(invoice)); let title = if invoice { t!("wallets.receive") @@ -230,7 +227,6 @@ impl WalletMessages { .position(ModalPosition::CenterTop) .title(title) .show(); - cb.show_keyboard(); } /// Draw Slatepack message input content. @@ -274,14 +270,8 @@ impl WalletMessages { .desired_width(f32::INFINITY) .show(ui) .response; - // Show soft keyboard on click. if resp.clicked() { resp.request_focus(); - cb.show_keyboard(); - } - if resp.has_focus() { - // Apply text from input on Android as temporary fix for egui. - View::on_soft_input(ui, input_id, &mut self.message_edit); } ui.add_space(6.0); }); diff --git a/src/gui/views/wallets/wallet/messages/request.rs b/src/gui/views/wallets/wallet/messages/request.rs index ce4a8e4..7fcfc60 100644 --- a/src/gui/views/wallets/wallet/messages/request.rs +++ b/src/gui/views/wallets/wallet/messages/request.rs @@ -102,7 +102,6 @@ impl MessageRequestModal { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { self.amount_edit = "".to_string(); self.request_error = None; - cb.hide_keyboard(); modal.close(); }); }); @@ -113,7 +112,6 @@ impl MessageRequestModal { return; } if let Ok(a) = amount_from_hr_string(self.amount_edit.as_str()) { - cb.hide_keyboard(); modal.disable_closing(); // Setup data for request. let wallet = wallet.clone(); diff --git a/src/gui/views/wallets/wallet/modals/accounts.rs b/src/gui/views/wallets/wallet/modals/accounts.rs index de6ffaa..15f52a5 100644 --- a/src/gui/views/wallets/wallet/modals/accounts.rs +++ b/src/gui/views/wallets/wallet/modals/accounts.rs @@ -96,7 +96,6 @@ impl WalletAccountsModal { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -108,7 +107,6 @@ impl WalletAccountsModal { match wallet.create_account(label) { Ok(_) => { let _ = wallet.set_active_account(label); - cb.hide_keyboard(); modal.close(); }, Err(_) => self.account_creation_error = true @@ -165,7 +163,6 @@ impl WalletAccountsModal { columns[1].vertical_centered_justified(|ui| { View::button(ui, t!("create"), Colors::white_or_black(false), || { self.account_creating = true; - cb.show_keyboard(); }); }); }); diff --git a/src/gui/views/wallets/wallet/settings/common.rs b/src/gui/views/wallets/wallet/settings/common.rs index c67599a..1dcd56b 100644 --- a/src/gui/views/wallets/wallet/settings/common.rs +++ b/src/gui/views/wallets/wallet/settings/common.rs @@ -87,7 +87,6 @@ impl CommonSettings { .position(ModalPosition::CenterTop) .title(t!("wallets.wallet")) .show(); - cb.show_keyboard(); }); ui.add_space(12.0); @@ -109,7 +108,6 @@ impl CommonSettings { .position(ModalPosition::CenterTop) .title(t!("wallets.wallet")) .show(); - cb.show_keyboard(); }); ui.add_space(12.0); @@ -127,7 +125,6 @@ impl CommonSettings { .position(ModalPosition::CenterTop) .title(t!("network_settings.change_value")) .show(); - cb.show_keyboard(); }); ui.add_space(12.0); @@ -202,7 +199,6 @@ impl CommonSettings { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -211,7 +207,6 @@ impl CommonSettings { let on_save = || { if !self.name_edit.is_empty() { wallet.change_name(self.name_edit.clone()); - cb.hide_keyboard(); modal.close(); } }; @@ -288,7 +283,6 @@ impl CommonSettings { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -306,7 +300,6 @@ impl CommonSettings { self.old_pass_edit = "".to_string(); self.new_pass_edit = "".to_string(); // Close modal. - cb.hide_keyboard(); modal.close(); } Err(_) => self.wrong_pass = true @@ -361,7 +354,6 @@ impl CommonSettings { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { // Close modal. - cb.hide_keyboard(); modal.close(); }); }); @@ -370,7 +362,6 @@ impl CommonSettings { let on_save = || { if let Ok(min_conf) = self.min_confirmations_edit.parse::() { wallet.update_min_confirmations(min_conf); - cb.hide_keyboard(); modal.close(); } }; diff --git a/src/gui/views/wallets/wallet/settings/connection.rs b/src/gui/views/wallets/wallet/settings/connection.rs index 0e78630..b0a290f 100644 --- a/src/gui/views/wallets/wallet/settings/connection.rs +++ b/src/gui/views/wallets/wallet/settings/connection.rs @@ -129,7 +129,6 @@ impl ConnectionSettings { .position(ModalPosition::CenterTop) .title(t!("wallets.add_node")) .show(); - cb.show_keyboard(); }); ui.add_space(4.0); diff --git a/src/gui/views/wallets/wallet/settings/recovery.rs b/src/gui/views/wallets/wallet/settings/recovery.rs index 5326589..ea08527 100644 --- a/src/gui/views/wallets/wallet/settings/recovery.rs +++ b/src/gui/views/wallets/wallet/settings/recovery.rs @@ -115,7 +115,7 @@ impl RecoverySettings { // Draw button to show recovery phrase. let show_text = format!("{} {}", EYE, t!("show")); View::button(ui, show_text, Colors::white_or_black(false), || { - self.show_recovery_phrase_modal(cb); + self.show_recovery_phrase_modal(); }); ui.add_space(12.0); @@ -164,7 +164,7 @@ impl RecoverySettings { } /// Show recovery phrase [`Modal`]. - fn show_recovery_phrase_modal(&mut self, cb: &dyn PlatformCallbacks) { + fn show_recovery_phrase_modal(&mut self) { // Setup modal values. self.pass_edit = "".to_string(); self.wrong_pass = false; @@ -174,7 +174,6 @@ impl RecoverySettings { .position(ModalPosition::CenterTop) .title(t!("wallets.recovery_phrase")) .show(); - cb.show_keyboard(); } /// Draw recovery phrase [`Modal`] content. @@ -242,7 +241,6 @@ impl RecoverySettings { Ok(phrase) => { self.wrong_pass = false; self.recovery_phrase = Some(phrase); - cb.hide_keyboard(); } Err(_) => { self.wrong_pass = true; diff --git a/src/gui/views/wallets/wallet/transport/content.rs b/src/gui/views/wallets/wallet/transport/content.rs index 6217803..dfebb81 100644 --- a/src/gui/views/wallets/wallet/transport/content.rs +++ b/src/gui/views/wallets/wallet/transport/content.rs @@ -61,14 +61,14 @@ const QR_ADDRESS_MODAL: &'static str = "qr_address_modal"; impl WalletTransport { /// Create new transport content instance, opening sending `Modal` if address was provided. - pub fn new(address: Option, cb: &dyn PlatformCallbacks) -> Self { + pub fn new(address: Option) -> Self { let mut content = Self { send_modal_content: None, qr_address_content: None, settings_modal_content: None, }; if address.is_some() { - content.show_send_tor_modal(cb, address) + content.show_send_tor_modal(address) } content } @@ -135,7 +135,7 @@ impl WalletTransport { let service_id = &wallet.identifier(); if data.info.amount_currently_spendable > 0 && wallet.foreign_api_port().is_some() && !Tor::is_service_starting(service_id) { - self.tor_send_ui(ui, cb); + self.tor_send_ui(ui); } } @@ -330,7 +330,7 @@ impl WalletTransport { } /// Draw Tor send content. - fn tor_send_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + fn tor_send_ui(&mut self, ui: &mut egui::Ui) { // Setup layout size. let mut rect = ui.available_rect_before_wrap(); rect.set_height(55.0); @@ -346,20 +346,19 @@ impl WalletTransport { // Draw button to open sending modal. let send_text = format!("{} {}", EXPORT, t!("wallets.send")); View::button(ui, send_text, Colors::white_or_black(false), || { - self.show_send_tor_modal(cb, None); + self.show_send_tor_modal(None); }); }); }); } /// Show [`Modal`] to send over Tor. - fn show_send_tor_modal(&mut self, cb: &dyn PlatformCallbacks, address: Option) { + fn show_send_tor_modal(&mut self, address: Option) { self.send_modal_content = Some(TransportSendModal::new(address)); // Show modal. Modal::new(SEND_TOR_MODAL) .position(ModalPosition::CenterTop) .title(t!("wallets.send")) .show(); - cb.show_keyboard(); } } \ No newline at end of file diff --git a/src/gui/views/wallets/wallet/transport/send.rs b/src/gui/views/wallets/wallet/transport/send.rs index c1b03a1..a172ee5 100644 --- a/src/gui/views/wallets/wallet/transport/send.rs +++ b/src/gui/views/wallets/wallet/transport/send.rs @@ -85,14 +85,17 @@ impl TransportSendModal { if self.sending { self.progress_ui(ui, wallet); } else if self.error { - self.error_ui(ui, wallet, modal, cb); + self.error_ui(ui, wallet, modal); } else { self.content_ui(ui, wallet, modal, cb); } } /// Draw content to send. - fn content_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, modal: &Modal, + fn content_ui(&mut self, + ui: &mut egui::Ui, + wallet: &Wallet, + modal: &Modal, cb: &dyn PlatformCallbacks) { ui.add_space(6.0); // Draw QR code scanner content if requested. @@ -107,7 +110,6 @@ impl TransportSendModal { self.address_edit = result.text(); on_stop(); self.address_scan_content = None; - cb.show_keyboard(); } else { scanner.ui(ui, cb); ui.add_space(6.0); @@ -128,7 +130,6 @@ impl TransportSendModal { View::button(ui, t!("back"), Colors::white_or_black(false), || { on_stop(); self.address_scan_content = None; - cb.show_keyboard(); }); }); }); @@ -217,7 +218,6 @@ impl TransportSendModal { View::text_edit(ui, cb, &mut self.address_edit, &mut address_edit_opts); // Check if scan button was pressed. if address_edit_opts.scan_pressed { - cb.hide_keyboard(); modal.disable_closing(); address_edit_opts.scan_pressed = false; self.address_scan_content = Some(CameraContent::default()); @@ -235,12 +235,12 @@ impl TransportSendModal { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { - self.close(modal, cb); + self.close(modal); }); }); columns[1].vertical_centered_justified(|ui| { View::button(ui, t!("continue"), Colors::white_or_black(false), || { - self.send(wallet, modal, cb); + self.send(wallet, modal); }); }); }); @@ -248,11 +248,7 @@ impl TransportSendModal { } /// Draw error content. - fn error_ui(&mut self, - ui: &mut egui::Ui, - wallet: &Wallet, - modal: &Modal, - cb: &dyn PlatformCallbacks) { + fn error_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, modal: &Modal) { ui.add_space(6.0); ui.vertical_centered(|ui| { ui.label(RichText::new(t!("transport.tor_send_error")) @@ -267,12 +263,12 @@ impl TransportSendModal { ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || { - self.close(modal, cb); + self.close(modal); }); }); columns[1].vertical_centered_justified(|ui| { View::button(ui, t!("repeat"), Colors::white_or_black(false), || { - self.send(wallet, modal, cb); + self.send(wallet, modal); }); }); }); @@ -280,7 +276,7 @@ impl TransportSendModal { } /// Close modal and clear data. - fn close(&mut self, modal: &Modal, cb: &dyn PlatformCallbacks) { + fn close(&mut self, modal: &Modal) { self.amount_edit = "".to_string(); self.address_edit = "".to_string(); @@ -290,19 +286,17 @@ impl TransportSendModal { self.tx_info_content = None; self.address_scan_content = None; - cb.hide_keyboard(); modal.close(); } /// Send entered amount to address. - fn send(&mut self, wallet: &Wallet, modal: &Modal, cb: &dyn PlatformCallbacks) { + fn send(&mut self, wallet: &Wallet, modal: &Modal) { if self.amount_edit.is_empty() { return; } let addr_str = self.address_edit.as_str(); if let Ok(addr) = SlatepackAddress::try_from(addr_str.trim()) { if let Ok(a) = amount_from_hr_string(self.amount_edit.as_str()) { - cb.hide_keyboard(); modal.disable_closing(); // Send amount over Tor. let mut wallet = wallet.clone(); diff --git a/src/gui/views/wallets/wallet/transport/settings.rs b/src/gui/views/wallets/wallet/transport/settings.rs index 377d2f0..ebf7ae1 100644 --- a/src/gui/views/wallets/wallet/transport/settings.rs +++ b/src/gui/views/wallets/wallet/transport/settings.rs @@ -72,7 +72,6 @@ impl TransportSettingsModal { self.bridge_conn_line_edit = result.text(); on_stop(); self.bridge_qr_scan_content = None; - cb.show_keyboard(); } else { scanner.ui(ui, cb); ui.add_space(12.0); @@ -191,7 +190,6 @@ impl TransportSettingsModal { View::text_edit(ui, cb, &mut self.bridge_conn_line_edit, &mut conn_edit_opts); // Check if scan button was pressed. if conn_edit_opts.scan_pressed { - cb.hide_keyboard(); modal.disable_closing(); conn_edit_opts.scan_pressed = false; self.bridge_qr_scan_content = Some(CameraContent::default()); diff --git a/src/gui/views/wallets/wallet/txs/content.rs b/src/gui/views/wallets/wallet/txs/content.rs index 2d81991..5f40458 100644 --- a/src/gui/views/wallets/wallet/txs/content.rs +++ b/src/gui/views/wallets/wallet/txs/content.rs @@ -61,7 +61,7 @@ impl WalletTab for WalletTransactions { fn ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet, cb: &dyn PlatformCallbacks) { self.modal_content_ui(ui, wallet, cb); - self.txs_ui(ui, wallet, cb); + self.txs_ui(ui, wallet); } } @@ -75,10 +75,7 @@ impl WalletTransactions { pub const TX_ITEM_HEIGHT: f32 = 75.0; /// Draw transactions content. - fn txs_ui(&mut self, - ui: &mut egui::Ui, - wallet: &Wallet, - cb: &dyn PlatformCallbacks) { + fn txs_ui(&mut self, ui: &mut egui::Ui, wallet: &Wallet) { let data = wallet.get_data().unwrap(); if data.txs.is_none() { ui.centered_and_justified(|ui| { @@ -123,7 +120,7 @@ impl WalletTransactions { .show_rows(ui, Self::TX_ITEM_HEIGHT, txs.len(), |ui, row_range| { ui.add_space(1.0); View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH * 1.3, |ui| { - self.tx_list_ui(ui, awaiting_amount, row_range, wallet, txs, cb); + self.tx_list_ui(ui, awaiting_amount, row_range, wallet, txs); }); }) }); @@ -143,8 +140,7 @@ impl WalletTransactions { awaiting: bool, row_range: Range, wallet: &Wallet, - txs: &Vec, - cb: &dyn PlatformCallbacks) { + txs: &Vec) { for index in row_range { let mut rect = if awaiting { let mut rect = ui.available_rect_before_wrap(); @@ -179,7 +175,6 @@ impl WalletTransactions { if wallet_loaded && tx.can_finalize { let (icon, color) = (CHECK, Some(Colors::green())); View::item_button(ui, Rounding::default(), icon, color, || { - cb.hide_keyboard(); self.show_tx_info_modal(wallet, tx, true); }); } diff --git a/src/gui/views/wallets/wallet/txs/tx.rs b/src/gui/views/wallets/wallet/txs/tx.rs index eb77bb4..e06c0b2 100644 --- a/src/gui/views/wallets/wallet/txs/tx.rs +++ b/src/gui/views/wallets/wallet/txs/tx.rs @@ -116,7 +116,6 @@ impl WalletTransactionModal { .filter(|tx| tx.data.id == self.tx_id) .collect::>(); if txs.is_empty() { - cb.hide_keyboard(); modal.close(); return; } @@ -178,7 +177,6 @@ impl WalletTransactionModal { // Show button to close modal. ui.vertical_centered_justified(|ui| { View::button(ui, t!("close"), Colors::white_or_black(false), || { - cb.hide_keyboard(); modal.close(); }); }); @@ -266,7 +264,6 @@ impl WalletTransactionModal { }; let r = View::item_rounding(0, 2, true); View::item_button(ui, r, icon, color, || { - cb.hide_keyboard(); if self.show_finalization { self.show_finalization = false; return; @@ -282,7 +279,6 @@ impl WalletTransactionModal { View::item_rounding(0, 2, true) }; View::item_button(ui, r, PROHIBIT, Some(Colors::red()), || { - cb.hide_keyboard(); wallet.cancel(tx.data.id); }); } @@ -321,7 +317,7 @@ impl WalletTransactionModal { // Setup value to finalization input field. self.finalize_edit = result.text(); - self.on_finalization_input_change(tx, wallet, modal, cb); + self.on_finalization_input_change(tx, wallet, modal); modal.enable_closing(); self.scan_qr_content = None; @@ -409,14 +405,8 @@ impl WalletTransactionModal { .hint_text(SLATEPACK_MESSAGE_HINT) .desired_width(f32::INFINITY) .show(ui).response; - // Show soft keyboard on click. if self.show_finalization && resp.clicked() { resp.request_focus(); - cb.show_keyboard(); - } - if self.show_finalization && resp.has_focus() { - // Apply text from input on Android as temporary fix for egui. - View::on_soft_input(ui, input_id, message_edit); } ui.add_space(6.0); }); @@ -440,7 +430,6 @@ impl WalletTransactionModal { // Draw button to scan Slatepack message QR code. let qr_text = format!("{} {}", SCAN, t!("scan")); View::button(ui, qr_text, Colors::fill_lite(), || { - cb.hide_keyboard(); modal.disable_closing(); cb.start_camera(); self.scan_qr_content = Some(CameraContent::default()); @@ -473,7 +462,7 @@ impl WalletTransactionModal { // Callback on finalization message input change. if message_before != self.finalize_edit { - self.on_finalization_input_change(tx, wallet, modal, cb); + self.on_finalization_input_change(tx, wallet, modal); } } else { ui.columns(2, |columns| { @@ -481,7 +470,6 @@ impl WalletTransactionModal { // Draw button to show Slatepack message as QR code. let qr_text = format!("{} {}", QR_CODE, t!("qr_code")); View::button(ui, qr_text.clone(), Colors::white_or_black(false), || { - cb.hide_keyboard(); let text = self.response_edit.clone(); self.qr_code_content = Some(QrCodeContent::new(text, true)); }); @@ -495,7 +483,6 @@ impl WalletTransactionModal { if tx.can_finalize { self.show_finalization = true; } else { - cb.hide_keyboard(); modal.close(); } }); @@ -521,27 +508,22 @@ impl WalletTransactionModal { } /// Parse Slatepack message on transaction finalization input change. - fn on_finalization_input_change(&mut self, - tx: &WalletTransaction, - wallet: &Wallet, - modal: &Modal, - cb: &dyn PlatformCallbacks) { + fn on_finalization_input_change(&mut self, tx: &WalletTransaction, w: &Wallet, modal: &Modal) { let message = &self.finalize_edit; if message.is_empty() { self.finalize_error = false; } else { // Parse input message to finalize. - if let Ok(slate) = wallet.parse_slatepack(message) { + if let Ok(slate) = w.parse_slatepack(message) { let send = slate.state == SlateState::Standard2 && tx.data.tx_type == TxLogEntryType::TxSent; let receive = slate.state == SlateState::Invoice2 && tx.data.tx_type == TxLogEntryType::TxReceived; if Some(slate.id) == tx.data.tx_slate_id && (send || receive) { let message = message.clone(); - let wallet = wallet.clone(); + let wallet = w.clone(); let final_res = self.final_result.clone(); // Finalize transaction at separate thread. - cb.hide_keyboard(); self.finalizing = true; modal.disable_closing(); thread::spawn(move || {