ui: settings modal, language selection
This commit is contained in:
parent
2c1be806a9
commit
61a963ac2b
6 changed files with 145 additions and 15 deletions
|
@ -35,7 +35,7 @@ grin_wallet_controller = { git = "https://github.com/yeastplume/grin-wallet", br
|
||||||
## ui
|
## ui
|
||||||
egui = { version = "0.27.2", default-features = false }
|
egui = { version = "0.27.2", default-features = false }
|
||||||
egui_extras = { version = "0.27.2", features = ["image"] }
|
egui_extras = { version = "0.27.2", features = ["image"] }
|
||||||
rust-i18n = "2.1.0"
|
rust-i18n = "2.3.1"
|
||||||
|
|
||||||
## other
|
## other
|
||||||
thiserror = "1.0.58"
|
thiserror = "1.0.58"
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
lang_name: English
|
||||||
copy: Copy
|
copy: Copy
|
||||||
paste: Paste
|
paste: Paste
|
||||||
continue: Continue
|
continue: Continue
|
||||||
|
@ -12,6 +13,8 @@ clear: Clear
|
||||||
create: Create
|
create: Create
|
||||||
id: Identifier
|
id: Identifier
|
||||||
kernel: Kernel
|
kernel: Kernel
|
||||||
|
settings: Settings
|
||||||
|
language: Language
|
||||||
wallets:
|
wallets:
|
||||||
await_conf_amount: Awaiting confirmation
|
await_conf_amount: Awaiting confirmation
|
||||||
await_fin_amount: Awaiting finalization
|
await_fin_amount: Awaiting finalization
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
lang_name: Русский
|
||||||
copy: Копировать
|
copy: Копировать
|
||||||
paste: Вставить
|
paste: Вставить
|
||||||
continue: Продолжить
|
continue: Продолжить
|
||||||
|
@ -12,6 +13,8 @@ clear: Очистить
|
||||||
create: Создать
|
create: Создать
|
||||||
id: Идентификатор
|
id: Идентификатор
|
||||||
kernel: Ядро
|
kernel: Ядро
|
||||||
|
settings: Настройки
|
||||||
|
language: Язык
|
||||||
wallets:
|
wallets:
|
||||||
await_conf_amount: Ожидает подтверждения
|
await_conf_amount: Ожидает подтверждения
|
||||||
await_fin_amount: Ожидает завершения
|
await_fin_amount: Ожидает завершения
|
||||||
|
|
|
@ -37,9 +37,14 @@ pub struct AppConfig {
|
||||||
height: f32,
|
height: f32,
|
||||||
|
|
||||||
/// Position of the desktop window.
|
/// Position of the desktop window.
|
||||||
x: Option<f32>, y: Option<f32>
|
x: Option<f32>, y: Option<f32>,
|
||||||
|
|
||||||
|
/// Locale code for i18n.
|
||||||
|
lang: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const DEFAULT_LOCALE: &str = "en";
|
||||||
|
|
||||||
pub const DEFAULT_WIDTH: f32 = 1200.0;
|
pub const DEFAULT_WIDTH: f32 = 1200.0;
|
||||||
pub const DEFAULT_HEIGHT: f32 = 720.0;
|
pub const DEFAULT_HEIGHT: f32 = 720.0;
|
||||||
|
|
||||||
|
@ -54,6 +59,7 @@ impl Default for AppConfig {
|
||||||
height: DEFAULT_HEIGHT,
|
height: DEFAULT_HEIGHT,
|
||||||
x: None,
|
x: None,
|
||||||
y: None,
|
y: None,
|
||||||
|
lang: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,4 +176,20 @@ impl AppConfig {
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save locale code.
|
||||||
|
pub fn save_locale(lang: &str) {
|
||||||
|
let mut w_app_config = Settings::app_config_to_update();
|
||||||
|
w_app_config.lang = Some(lang.to_string());
|
||||||
|
w_app_config.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get current saved locale code.
|
||||||
|
pub fn locale() -> Option<String> {
|
||||||
|
let r_config = Settings::app_config_to_read();
|
||||||
|
if r_config.lang.is_some() {
|
||||||
|
return Some(r_config.lang.clone().unwrap())
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -17,9 +17,9 @@ use egui::{Align, Id, Layout, Margin, RichText, Rounding, ScrollArea, Widget};
|
||||||
|
|
||||||
use crate::AppConfig;
|
use crate::AppConfig;
|
||||||
use crate::gui::Colors;
|
use crate::gui::Colors;
|
||||||
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::icons::{ARROW_LEFT, CARET_RIGHT, CHECK, CHECK_FAT, COMPUTER_TOWER, FLAG, 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::platform::PlatformCallbacks;
|
||||||
use crate::gui::views::{Modal, Root, TitlePanel, View};
|
use crate::gui::views::{Modal, NodeSetup, Root, TitlePanel, View};
|
||||||
use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions, TitleContentType, TitleType};
|
use crate::gui::views::types::{ModalContainer, ModalPosition, TextEditOptions, TitleContentType, TitleType};
|
||||||
use crate::gui::views::wallets::creation::WalletCreation;
|
use crate::gui::views::wallets::creation::WalletCreation;
|
||||||
use crate::gui::views::wallets::types::WalletTabType;
|
use crate::gui::views::wallets::types::WalletTabType;
|
||||||
|
@ -51,6 +51,9 @@ pub struct WalletsContent {
|
||||||
/// Identifier for wallet opening [`Modal`].
|
/// Identifier for wallet opening [`Modal`].
|
||||||
const OPEN_WALLET_MODAL: &'static str = "open_wallet_modal";
|
const OPEN_WALLET_MODAL: &'static str = "open_wallet_modal";
|
||||||
|
|
||||||
|
/// Identifier for wallet opening [`Modal`].
|
||||||
|
const SETTINGS_MODAL: &'static str = "settings_modal";
|
||||||
|
|
||||||
impl Default for WalletsContent {
|
impl Default for WalletsContent {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
@ -62,6 +65,7 @@ impl Default for WalletsContent {
|
||||||
show_wallets_at_dual_panel: AppConfig::show_wallets_at_dual_panel(),
|
show_wallets_at_dual_panel: AppConfig::show_wallets_at_dual_panel(),
|
||||||
modal_ids: vec![
|
modal_ids: vec![
|
||||||
OPEN_WALLET_MODAL,
|
OPEN_WALLET_MODAL,
|
||||||
|
SETTINGS_MODAL,
|
||||||
WalletCreation::NAME_PASS_MODAL
|
WalletCreation::NAME_PASS_MODAL
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -83,6 +87,7 @@ impl ModalContainer for WalletsContent {
|
||||||
WalletCreation::NAME_PASS_MODAL => {
|
WalletCreation::NAME_PASS_MODAL => {
|
||||||
self.creation_content.name_pass_modal_ui(ui, modal, cb)
|
self.creation_content.name_pass_modal_ui(ui, modal, cb)
|
||||||
},
|
},
|
||||||
|
SETTINGS_MODAL => self.settings_modal_ui(ui, modal),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -298,7 +303,11 @@ impl WalletsContent {
|
||||||
};
|
};
|
||||||
}, |ui, frame| {
|
}, |ui, frame| {
|
||||||
View::title_button(ui, GEAR, || {
|
View::title_button(ui, GEAR, || {
|
||||||
//TODO: show settings.
|
// Show settings modal.
|
||||||
|
Modal::new(SETTINGS_MODAL)
|
||||||
|
.position(ModalPosition::CenterTop)
|
||||||
|
.title(t!("settings"))
|
||||||
|
.show();
|
||||||
});
|
});
|
||||||
}, ui, frame);
|
}, ui, frame);
|
||||||
}
|
}
|
||||||
|
@ -586,6 +595,89 @@ impl WalletsContent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Draw creating wallet name/password input [`Modal`] content.
|
||||||
|
pub fn settings_modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal) {
|
||||||
|
ui.add_space(6.0);
|
||||||
|
|
||||||
|
// Draw chain type selection.
|
||||||
|
NodeSetup::chain_type_ui(ui);
|
||||||
|
|
||||||
|
ui.add_space(8.0);
|
||||||
|
View::horizontal_line(ui, Colors::ITEM_STROKE);
|
||||||
|
ui.add_space(6.0);
|
||||||
|
|
||||||
|
ui.vertical_centered(|ui| {
|
||||||
|
ui.label(RichText::new(format!("{} {}", GLOBE_SIMPLE, t!("language")))
|
||||||
|
.size(16.0)
|
||||||
|
.color(Colors::GRAY)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
ui.add_space(6.0);
|
||||||
|
|
||||||
|
// Draw available list of languages to select.
|
||||||
|
let locales = rust_i18n::available_locales!();
|
||||||
|
for (index, locale) in locales.iter().enumerate() {
|
||||||
|
Self::language_item_ui(locale, ui, index, locales.len(), modal);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.add_space(8.0);
|
||||||
|
|
||||||
|
// Show button to close modal.
|
||||||
|
ui.vertical_centered_justified(|ui| {
|
||||||
|
View::button(ui, t!("close"), Colors::WHITE, || {
|
||||||
|
modal.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
ui.add_space(6.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw language selection item content.
|
||||||
|
fn language_item_ui(locale: &str, ui: &mut egui::Ui, index: usize, len: usize, modal: &Modal) {
|
||||||
|
// Setup layout size.
|
||||||
|
let mut rect = ui.available_rect_before_wrap();
|
||||||
|
rect.set_height(50.0);
|
||||||
|
|
||||||
|
// Draw round background.
|
||||||
|
let bg_rect = rect.clone();
|
||||||
|
let item_rounding = View::item_rounding(index, len, false);
|
||||||
|
ui.painter().rect(bg_rect, item_rounding, Colors::FILL, View::ITEM_STROKE);
|
||||||
|
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||||
|
// Draw button to select language.
|
||||||
|
let is_current = if let Some(lang) = AppConfig::locale() {
|
||||||
|
lang == locale
|
||||||
|
} else {
|
||||||
|
rust_i18n::locale() == locale
|
||||||
|
};
|
||||||
|
if !is_current {
|
||||||
|
View::item_button(ui, View::item_rounding(index, len, true), CHECK, None, || {
|
||||||
|
rust_i18n::set_locale(locale);
|
||||||
|
AppConfig::save_locale(locale);
|
||||||
|
modal.close();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
ui.add_space(14.0);
|
||||||
|
ui.label(RichText::new(CHECK_FAT).size(20.0).color(Colors::GREEN));
|
||||||
|
ui.add_space(14.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let layout_size = ui.available_size();
|
||||||
|
ui.allocate_ui_with_layout(layout_size, Layout::left_to_right(Align::Center), |ui| {
|
||||||
|
ui.add_space(12.0);
|
||||||
|
ui.vertical(|ui| {
|
||||||
|
// Draw language name.
|
||||||
|
ui.add_space(12.0);
|
||||||
|
ui.label(RichText::new(t!("lang_name", locale = locale))
|
||||||
|
.size(17.0)
|
||||||
|
.color(Colors::TEXT));
|
||||||
|
ui.add_space(3.0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle Back key event.
|
/// Handle Back key event.
|
||||||
/// Return `false` when event was handled.
|
/// Return `false` when event was handled.
|
||||||
pub fn on_back(&mut self) -> bool {
|
pub fn on_back(&mut self) -> bool {
|
||||||
|
|
30
src/lib.rs
30
src/lib.rs
|
@ -15,14 +15,14 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate rust_i18n;
|
extern crate rust_i18n;
|
||||||
|
|
||||||
use eframe::wgpu;
|
use egui::{Context, Stroke};
|
||||||
use egui::{Context, Stroke, vec2};
|
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
use winit::platform::android::activity::AndroidApp;
|
use winit::platform::android::activity::AndroidApp;
|
||||||
|
|
||||||
pub use config::AppConfig;
|
pub use config::AppConfig;
|
||||||
pub use settings::Settings;
|
pub use settings::Settings;
|
||||||
|
use crate::config::DEFAULT_LOCALE;
|
||||||
|
|
||||||
use crate::gui::{Colors, PlatformApp};
|
use crate::gui::{Colors, PlatformApp};
|
||||||
use crate::gui::platform::PlatformCallbacks;
|
use crate::gui::platform::PlatformCallbacks;
|
||||||
|
@ -206,14 +206,24 @@ pub fn setup_fonts(ctx: &Context) {
|
||||||
|
|
||||||
/// Setup translations.
|
/// Setup translations.
|
||||||
fn setup_i18n() {
|
fn setup_i18n() {
|
||||||
const DEFAULT_LOCALE: &str = "en";
|
// Set saved locale or get from system.
|
||||||
let locale = sys_locale::get_locale().unwrap_or(String::from(DEFAULT_LOCALE));
|
if let Some(lang) = AppConfig::locale() {
|
||||||
let locale_str = if locale.contains("-") {
|
if rust_i18n::available_locales!().contains(&lang.as_str()) {
|
||||||
locale.split("-").next().unwrap_or(DEFAULT_LOCALE)
|
rust_i18n::set_locale(lang.as_str());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
locale.as_str()
|
let locale = sys_locale::get_locale().unwrap_or(String::from(DEFAULT_LOCALE));
|
||||||
};
|
let locale_str = if locale.contains("-") {
|
||||||
if _rust_i18n_available_locales().contains(&locale_str) {
|
locale.split("-").next().unwrap_or(DEFAULT_LOCALE)
|
||||||
rust_i18n::set_locale(locale_str);
|
} else {
|
||||||
|
locale.as_str()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set best possible locale.
|
||||||
|
if rust_i18n::available_locales!().contains(&locale_str) {
|
||||||
|
rust_i18n::set_locale(locale_str);
|
||||||
|
} else {
|
||||||
|
rust_i18n::set_locale(DEFAULT_LOCALE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue