wallet + ui: external connection API token support, update translations

This commit is contained in:
ardocrat 2023-08-01 02:13:35 +03:00
parent 08c202519e
commit cf834f86fc
6 changed files with 158 additions and 40 deletions

View file

@ -21,7 +21,9 @@ wallets:
setup_conn_desc: Choose how your wallet connects to the network.
conn_method: Connection method
ext_conn: 'External connections:'
add_node_url: Add node URL
add_node: Add node
node_url: 'Node URL:'
node_secret: 'API Secret (optional):'
invalid_url: Entered URL is invalid
open: Open the wallet
wrong_pass: Entered password is wrong

View file

@ -21,7 +21,9 @@ wallets:
setup_conn_desc: Выберите способ подключения вашего кошелька к сети.
conn_method: Способ подключения
ext_conn: 'Внешние подключения:'
add_node_url: Добавить URL узла
add_node: Добавить узел
node_url: 'URL узла:'
node_secret: 'API токен (необязательно):'
invalid_url: Введенный URL-адрес недействителен
open: Открыть кошелёк
wrong_pass: Введён неправильный пароль

View file

@ -19,16 +19,21 @@ use crate::AppConfig;
use crate::gui::Colors;
use crate::gui::icons::{GLOBE, GLOBE_SIMPLE};
use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, View};
use crate::gui::views::{Modal, ModalPosition, View};
use crate::gui::views::wallets::setup::ConnectionMethod;
use crate::wallet::ExternalConnection;
/// Wallet node connection method setup content.
pub struct ConnectionSetup {
/// Selected connection method.
method: ConnectionMethod,
/// Flag to check if modal was just opened.
first_modal_launch: bool,
/// External node connection URL value for [`Modal`].
ext_node_url_edit: String,
/// External node connection API secret value for [`Modal`].
ext_node_secret_edit: String,
/// Flag to show URL format error.
ext_node_url_error: bool,
}
@ -37,7 +42,9 @@ impl Default for ConnectionSetup {
fn default() -> Self {
Self {
method: ConnectionMethod::Integrated,
first_modal_launch: true,
ext_node_url_edit: "".to_string(),
ext_node_secret_edit: "".to_string(),
ext_node_url_error: false
}
}
@ -82,25 +89,28 @@ impl ConnectionSetup {
ui.add_space(6.0);
// Show button to add new external node connection.
let add_node_text = format!("{} {}", GLOBE_SIMPLE, t!("wallets.add_node_url"));
let add_node_text = format!("{} {}", GLOBE_SIMPLE, t!("wallets.add_node"));
View::button(ui, add_node_text, Colors::GOLD, || {
// Setup values for Modal.
self.first_modal_launch = true;
self.ext_node_url_edit = "".to_string();
self.ext_node_secret_edit = "".to_string();
self.ext_node_url_error = false;
// Show modal.
Modal::new(Self::ADD_CONNECTION_URL_MODAL)
.title(t!("wallets.ext_conn"))
.position(ModalPosition::CenterTop)
.title(t!("wallets.add_node"))
.show();
cb.show_keyboard();
});
ui.add_space(12.0);
// Show external nodes URLs selection.
for conn in AppConfig::external_nodes_urls() {
for conn in AppConfig::external_connections() {
View::radio_value(ui,
&mut self.method,
ConnectionMethod::External(conn.clone()),
conn);
ConnectionMethod::External(conn.url.clone()),
conn.url);
ui.add_space(12.0);
}
});
@ -111,15 +121,41 @@ impl ConnectionSetup {
pub fn modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal, cb: &dyn PlatformCallbacks) {
ui.add_space(6.0);
ui.vertical_centered(|ui| {
// Draw external node URL text edit.
let text_edit_resp = egui::TextEdit::singleline(&mut self.ext_node_url_edit)
.id(Id::from(modal.id))
ui.label(RichText::new(t!("wallets.node_url"))
.size(17.0)
.color(Colors::GRAY));
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("node_url_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() {
ui.add_space(8.0);
if self.first_modal_launch {
self.first_modal_launch = false;
url_edit_resp.request_focus();
}
if url_edit_resp.clicked() {
cb.show_keyboard();
}
ui.label(RichText::new(t!("wallets.node_secret"))
.size(17.0)
.color(Colors::GRAY));
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();
}
@ -138,18 +174,6 @@ impl ConnectionSetup {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
// Add button callback.
let on_add = || {
let error = Url::parse(self.ext_node_url_edit.as_str()).is_err();
self.ext_node_url_error = error;
if !error {
AppConfig::add_external_node_url(self.ext_node_url_edit.clone());
// Close modal.
cb.hide_keyboard();
modal.close();
}
};
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
@ -159,6 +183,35 @@ impl ConnectionSetup {
});
});
columns[1].vertical_centered_justified(|ui| {
// Add connection button callback.
let mut on_add = || {
let error = Url::parse(self.ext_node_url_edit.as_str()).is_err();
self.ext_node_url_error = error;
if !error {
// Save external connection.
let url = self.ext_node_url_edit.to_owned();
let secret = if self.ext_node_secret_edit.is_empty() {
None
} else {
Some(self.ext_node_secret_edit.to_owned())
};
let ext_conn = ExternalConnection::new(url.clone(), secret);
AppConfig::add_external_connection(ext_conn);
// Set added method as current.
self.method = ConnectionMethod::External(url);
// Close modal.
cb.hide_keyboard();
modal.close();
}
};
// Add connection on Enter button press.
View::on_enter_key(ui, || {
(on_add)();
});
View::button(ui, t!("modal.add"), Colors::WHITE, on_add);
});
});

View file

@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize};
use serde::de::DeserializeOwned;
use crate::node::NodeConfig;
use crate::wallet::Wallets;
use crate::wallet::{ExternalConnection, Wallets};
lazy_static! {
/// Static settings state to be accessible globally.
@ -34,9 +34,6 @@ lazy_static! {
/// Application configuration file name.
const APP_CONFIG_FILE_NAME: &'static str = "app.toml";
/// Default external node URL.
const DEFAULT_EXTERNAL_NODE_URL: &'static str = "https://grinnnode.live:3413";
/// Common application settings.
#[derive(Serialize, Deserialize)]
pub struct AppConfig {
@ -44,8 +41,8 @@ pub struct AppConfig {
pub auto_start_node: bool,
/// Chain type for node and wallets.
chain_type: ChainTypes,
/// URLs of external nodes for wallets.
external_nodes_urls: Vec<String>
/// URLs of external connections for wallets.
external_connections: Vec<ExternalConnection>
}
impl Default for AppConfig {
@ -53,8 +50,8 @@ impl Default for AppConfig {
Self {
auto_start_node: false,
chain_type: ChainTypes::default(),
external_nodes_urls: vec![
DEFAULT_EXTERNAL_NODE_URL.to_string()
external_connections: vec![
ExternalConnection::default()
],
}
}
@ -121,19 +118,41 @@ impl AppConfig {
w_app_config.save();
}
/// Get external nodes URLs.
pub fn external_nodes_urls() -> Vec<String> {
/// Get external connections for the wallet.
pub fn external_connections() -> Vec<ExternalConnection> {
let r_config = Settings::app_config_to_read();
r_config.external_nodes_urls.clone()
r_config.external_connections.clone()
}
/// Add external node URL.
pub fn add_external_node_url(address: String) {
/// Save external connection for the wallet in app config.
pub fn add_external_connection(conn: ExternalConnection) {
let mut w_config = Settings::app_config_to_update();
w_config.external_nodes_urls.insert(0, address);
let mut exists = false;
for mut c in w_config.external_connections.iter_mut() {
// Update connection if URL exists.
if c.url == conn.url {
c.secret = conn.secret.clone();
exists = true;
break;
}
}
// Create new connection if URL not exists.
if !exists {
w_config.external_connections.insert(0, conn);
}
w_config.save();
}
/// Get external node connection secret from provided URL.
pub fn get_external_connection_secret(url: String) -> Option<String> {
let r_config = Settings::app_config_to_read();
for c in &r_config.external_connections {
if c.url == url {
return c.secret.clone();
}
}
None
}
}
/// Main application directory name.

View file

@ -21,4 +21,7 @@ mod wallets;
pub use wallets::{Wallet, Wallets};
mod config;
pub use config::*;
pub use config::*;
mod types;
pub use types::*;

39
src/wallet/types.rs Normal file
View file

@ -0,0 +1,39 @@
// Copyright 2023 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 serde_derive::{Deserialize, Serialize};
/// External node connection for the wallet.
#[derive(Serialize, Deserialize, Clone)]
pub struct ExternalConnection {
/// Node URL.
pub url: String,
/// Optional API secret key.
pub secret: Option<String>
}
impl ExternalConnection {
/// Default external node URL.
const DEFAULT_EXTERNAL_NODE_URL: &'static str = "https://grinnnode.live:3413";
pub fn new(url: String, secret: Option<String>) -> Self {
Self { url, secret }
}
}
impl Default for ExternalConnection {
fn default() -> Self {
Self { url: Self::DEFAULT_EXTERNAL_NODE_URL.to_string(), secret: None }
}
}