mirror of
https://github.com/jwinterm/grim.git
synced 2026-10-18 06:31:24 +02:00
ui: network and storage settings modules, language selection modal
This commit is contained in:
@@ -110,9 +110,21 @@ impl NetworkContent {
|
||||
.show_inside(ui, |ui| {
|
||||
let rect = ui.available_rect_before_wrap();
|
||||
if let Some(c) = &mut self.settings_content {
|
||||
View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH * 1.3, |ui| {
|
||||
c.ui(ui, cb);
|
||||
});
|
||||
ScrollArea::vertical()
|
||||
.id_salt("app_settings_network")
|
||||
.scroll_bar_visibility(ScrollBarVisibility::AlwaysHidden)
|
||||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
ui.add_space(1.0);
|
||||
ui.vertical_centered(|ui| {
|
||||
// Show application settings content.
|
||||
View::max_width_ui(ui,
|
||||
Content::SIDE_PANEL_WIDTH * 1.3,
|
||||
|ui| {
|
||||
c.ui(ui, cb);
|
||||
});
|
||||
});
|
||||
});
|
||||
} else if self.node_tab_content.get_type() != NodeTabType::Settings {
|
||||
View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH * 1.3, |ui| {
|
||||
let node_err = Node::get_error();
|
||||
|
||||
@@ -12,144 +12,48 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use eframe::emath::Align;
|
||||
use eframe::epaint::StrokeKind;
|
||||
use egui::{Layout, RichText};
|
||||
use crate::AppConfig;
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::icons::{CHECK, CHECK_FAT};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::{Modal, View};
|
||||
use crate::gui::views::settings::interface::InterfaceSettingsContent;
|
||||
use crate::gui::views::settings::network::NetworkSettingsContent;
|
||||
use crate::gui::views::settings::storage::StorageSettingsContent;
|
||||
use crate::gui::views::types::ContentContainer;
|
||||
use crate::gui::views::View;
|
||||
|
||||
/// Application settings content.
|
||||
pub struct SettingsContent {
|
||||
|
||||
/// User interface settings.
|
||||
interface_settings: InterfaceSettingsContent,
|
||||
/// Network communication settings.
|
||||
network_settings: NetworkSettingsContent,
|
||||
/// File storage settings.
|
||||
storage_settings: StorageSettingsContent
|
||||
}
|
||||
|
||||
|
||||
impl Default for SettingsContent {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ContentContainer for SettingsContent {
|
||||
fn modal_ids(&self) -> Vec<&'static str> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal, cb: &dyn PlatformCallbacks) {
|
||||
}
|
||||
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
||||
ui.add_space(6.0);
|
||||
|
||||
// Show theme selection.
|
||||
Self::theme_selection_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!("{}:", t!("language")))
|
||||
.size(16.0)
|
||||
.color(Colors::gray())
|
||||
);
|
||||
});
|
||||
ui.add_space(8.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());
|
||||
interface_settings: InterfaceSettingsContent::default(),
|
||||
network_settings: NetworkSettingsContent::default(),
|
||||
storage_settings: StorageSettingsContent::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SettingsContent {
|
||||
/// Draw theme selection content.
|
||||
fn theme_selection_ui(ui: &mut egui::Ui) {
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.label(RichText::new(t!("theme")).size(16.0).color(Colors::gray()));
|
||||
});
|
||||
|
||||
let saved_use_dark = AppConfig::dark_theme().unwrap_or(false);
|
||||
let mut selected_use_dark = saved_use_dark;
|
||||
/// Draw application settings content.
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
||||
// Show interface settings.
|
||||
self.interface_settings.ui(ui, cb);
|
||||
|
||||
ui.add_space(8.0);
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered(|ui| {
|
||||
View::radio_value(ui, &mut selected_use_dark, false, t!("light"));
|
||||
});
|
||||
columns[1].vertical_centered(|ui| {
|
||||
View::radio_value(ui, &mut selected_use_dark, true, t!("dark"));
|
||||
})
|
||||
});
|
||||
ui.add_space(8.0);
|
||||
|
||||
if saved_use_dark != selected_use_dark {
|
||||
AppConfig::set_dark_theme(selected_use_dark);
|
||||
crate::setup_visuals(ui.ctx());
|
||||
}
|
||||
|
||||
View::horizontal_line(ui, Colors::stroke());
|
||||
ui.add_space(6.0);
|
||||
}
|
||||
|
||||
// Show network settings.
|
||||
//self.network_settings.ui(ui, cb);
|
||||
|
||||
/// Draw language selection item content.
|
||||
fn language_item_ui(locale: &str, ui: &mut egui::Ui, index: usize, len: usize) {
|
||||
// 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(),
|
||||
StrokeKind::Middle);
|
||||
|
||||
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);
|
||||
let color = if is_current {
|
||||
Colors::title(false)
|
||||
} else {
|
||||
Colors::gray()
|
||||
};
|
||||
ui.label(RichText::new(t!("lang_name", locale = locale))
|
||||
.size(17.0)
|
||||
.color(color));
|
||||
ui.add_space(3.0);
|
||||
});
|
||||
});
|
||||
});
|
||||
// Show storage settings.
|
||||
// self.storage_settings.ui(ui, cb);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
// 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 egui::{Align, Layout, RichText, ScrollArea, StrokeKind};
|
||||
use egui::scroll_area::ScrollBarVisibility;
|
||||
use crate::gui::icons::{CHECK, CHECK_FAT, GLOBE_SIMPLE, PENCIL};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::types::{ContentContainer, ModalPosition};
|
||||
use crate::gui::views::{Modal, View};
|
||||
use crate::gui::Colors;
|
||||
use crate::AppConfig;
|
||||
|
||||
/// User interface settings content.
|
||||
pub struct InterfaceSettingsContent {
|
||||
/// Current locale.
|
||||
locale: String,
|
||||
}
|
||||
|
||||
/// Identifier for language selection [`Modal`].
|
||||
const LANGUAGE_SELECTION_MODAL: &'static str = "language_selection_modal";
|
||||
|
||||
impl ContentContainer for InterfaceSettingsContent {
|
||||
fn modal_ids(&self) -> Vec<&'static str> {
|
||||
vec![
|
||||
LANGUAGE_SELECTION_MODAL
|
||||
]
|
||||
}
|
||||
|
||||
fn modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal, _: &dyn PlatformCallbacks) {
|
||||
match modal.id {
|
||||
LANGUAGE_SELECTION_MODAL => self.language_selection_ui(ui),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, _: &dyn PlatformCallbacks) {
|
||||
ui.add_space(5.0);
|
||||
|
||||
// Draw theme selection.
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.label(RichText::new(t!("theme")).size(16.0).color(Colors::gray()));
|
||||
});
|
||||
|
||||
let saved_use_dark = AppConfig::dark_theme().unwrap_or(false);
|
||||
let mut selected_use_dark = saved_use_dark;
|
||||
|
||||
ui.add_space(8.0);
|
||||
ui.columns(2, |columns| {
|
||||
columns[0].vertical_centered(|ui| {
|
||||
View::radio_value(ui, &mut selected_use_dark, false, t!("light"));
|
||||
});
|
||||
columns[1].vertical_centered(|ui| {
|
||||
View::radio_value(ui, &mut selected_use_dark, true, t!("dark"));
|
||||
})
|
||||
});
|
||||
ui.add_space(8.0);
|
||||
if saved_use_dark != selected_use_dark {
|
||||
AppConfig::set_dark_theme(selected_use_dark);
|
||||
crate::setup_visuals(ui.ctx());
|
||||
}
|
||||
|
||||
ui.add_space(6.0);
|
||||
|
||||
// Draw language selection.
|
||||
self.language_item_ui(self.locale.clone().as_str(), ui, true, 0, 1);
|
||||
ui.add_space(4.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for InterfaceSettingsContent {
|
||||
fn default() -> Self {
|
||||
let locale = if let Some(lang) = AppConfig::locale() {
|
||||
lang
|
||||
} else {
|
||||
rust_i18n::locale()
|
||||
};
|
||||
Self {
|
||||
locale,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InterfaceSettingsContent {
|
||||
/// Draw language selection content.
|
||||
fn language_selection_ui(&mut self, ui: &mut egui::Ui) {
|
||||
ui.add_space(4.0);
|
||||
ScrollArea::vertical()
|
||||
.max_height(373.0)
|
||||
.id_salt("select_language_scroll")
|
||||
.scroll_bar_visibility(ScrollBarVisibility::AlwaysHidden)
|
||||
.auto_shrink([true; 2])
|
||||
.show(ui, |ui| {
|
||||
ui.add_space(2.0);
|
||||
ui.vertical_centered(|ui| {
|
||||
let locales = rust_i18n::available_locales!();
|
||||
for (index, locale) in locales.iter().enumerate() {
|
||||
self.language_item_ui(locale, ui, false, index, locales.len());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ui.add_space(6.0);
|
||||
View::horizontal_line(ui, Colors::item_stroke());
|
||||
ui.add_space(6.0);
|
||||
|
||||
// Show button to close modal.
|
||||
ui.vertical_centered_justified(|ui| {
|
||||
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
|
||||
Modal::close();
|
||||
});
|
||||
});
|
||||
ui.add_space(6.0);
|
||||
}
|
||||
|
||||
/// Draw language selection item content.
|
||||
fn language_item_ui(&mut self, locale: &str, ui: &mut egui::Ui, edit: bool, index: usize, len: usize) {
|
||||
// Setup layout size.
|
||||
let mut rect = ui.available_rect_before_wrap();
|
||||
if edit {
|
||||
rect.set_height(56.0);
|
||||
} else {
|
||||
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(),
|
||||
StrokeKind::Middle);
|
||||
|
||||
ui.allocate_ui_with_layout(rect.size(), Layout::right_to_left(Align::Center), |ui| {
|
||||
if edit {
|
||||
View::item_button(ui, View::item_rounding(index, len, true), PENCIL, None, || {
|
||||
// Show language selection modal.
|
||||
Modal::new(LANGUAGE_SELECTION_MODAL)
|
||||
.position(ModalPosition::Center)
|
||||
.title(t!("language"))
|
||||
.show();
|
||||
});
|
||||
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 connections URL.
|
||||
ui.add_space(4.0);
|
||||
View::ellipsize_text(ui,
|
||||
t!("lang_name", locale = locale),
|
||||
18.0,
|
||||
Colors::title(false));
|
||||
ui.add_space(1.0);
|
||||
|
||||
// Setup connection status text.
|
||||
let value = format!("{} {}",
|
||||
GLOBE_SIMPLE,
|
||||
t!("language"));
|
||||
ui.label(RichText::new(value).size(15.0).color(Colors::gray()));
|
||||
ui.add_space(3.0);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
// 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);
|
||||
self.locale = locale.to_string();
|
||||
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);
|
||||
let color = if is_current {
|
||||
Colors::title(false)
|
||||
} else {
|
||||
Colors::gray()
|
||||
};
|
||||
ui.label(RichText::new(t!("lang_name", locale = locale))
|
||||
.size(17.0)
|
||||
.color(color));
|
||||
ui.add_space(3.0);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -13,4 +13,8 @@
|
||||
// limitations under the License.
|
||||
|
||||
mod content;
|
||||
mod interface;
|
||||
mod network;
|
||||
mod storage;
|
||||
|
||||
pub use content::*;
|
||||
@@ -0,0 +1,49 @@
|
||||
// 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 crate::gui::icons::COMPUTER_TOWER;
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::types::ContentContainer;
|
||||
use crate::gui::views::{Modal, View};
|
||||
use crate::gui::Colors;
|
||||
|
||||
/// Network communication settings content.
|
||||
pub struct NetworkSettingsContent {
|
||||
|
||||
}
|
||||
|
||||
impl ContentContainer for NetworkSettingsContent {
|
||||
fn modal_ids(&self) -> Vec<&'static str> {
|
||||
vec![
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
fn modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal, cb: &dyn PlatformCallbacks) {
|
||||
}
|
||||
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
||||
View::sub_title(ui, format!("{} {}", COMPUTER_TOWER, t!("network.self")));
|
||||
View::horizontal_line(ui, Colors::stroke());
|
||||
ui.add_space(6.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for NetworkSettingsContent {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
// 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 crate::gui::icons::DATABASE;
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::types::ContentContainer;
|
||||
use crate::gui::views::{Modal, View};
|
||||
use crate::gui::Colors;
|
||||
|
||||
/// File storage settings content.
|
||||
pub struct StorageSettingsContent {
|
||||
|
||||
}
|
||||
|
||||
impl ContentContainer for StorageSettingsContent {
|
||||
fn modal_ids(&self) -> Vec<&'static str> {
|
||||
vec![
|
||||
|
||||
]
|
||||
}
|
||||
|
||||
fn modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal, cb: &dyn PlatformCallbacks) {
|
||||
}
|
||||
|
||||
fn container_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
|
||||
View::sub_title(ui, format!("{} {}", DATABASE, t!("network_node.data")));
|
||||
View::horizontal_line(ui, Colors::stroke());
|
||||
ui.add_space(6.0);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for StorageSettingsContent {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,9 +241,21 @@ impl ContentContainer for WalletsContent {
|
||||
.show_inside(ui, |ui| {
|
||||
if self.showing_settings() {
|
||||
if let Some(c) = &mut self.settings_content {
|
||||
View::max_width_ui(ui, Content::SIDE_PANEL_WIDTH * 1.3, |ui| {
|
||||
c.ui(ui, cb);
|
||||
});
|
||||
ScrollArea::vertical()
|
||||
.id_salt("app_settings_wallets")
|
||||
.scroll_bar_visibility(ScrollBarVisibility::AlwaysHidden)
|
||||
.auto_shrink([false; 2])
|
||||
.show(ui, |ui| {
|
||||
ui.add_space(1.0);
|
||||
ui.vertical_centered(|ui| {
|
||||
// Show application settings content.
|
||||
View::max_width_ui(ui,
|
||||
Content::SIDE_PANEL_WIDTH * 1.3,
|
||||
|ui| {
|
||||
c.ui(ui, cb);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
} else if self.creating_wallet() {
|
||||
let creation = self.creation_content.as_mut().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user