callbacks: introduce theming, i18n truning, introduce menu

* global_state: use global "lang", support env
* policycheck_state: use global "lang", new menu function, ron theming

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
This commit is contained in:
2020-07-22 18:11:39 +02:00
parent 276c0fb5f0
commit 65bec5a4a1
2 changed files with 266 additions and 131 deletions

View File

@@ -5,6 +5,8 @@
* SPDX-License-Identifier: (0BSD or MIT) * SPDX-License-Identifier: (0BSD or MIT)
*/ */
use serde::Deserialize;
use orbtk::prelude::*; use orbtk::prelude::*;
use crate::{ use crate::{
@@ -12,6 +14,15 @@ use crate::{
data::structures::PolicyList data::structures::PolicyList
}; };
/// define valid environment variables provided via .env files
/// located in the current call directory
/// this is primarily used in testing scenarios (eg. debugging)
#[derive(Debug, Deserialize)]
struct Environment {
test_lang: String,
rust_log: String,
}
/// Provides generic methods to handle states of datatypes (e.g. used in `PolicyList`). /// Provides generic methods to handle states of datatypes (e.g. used in `PolicyList`).
pub trait GlobalState { pub trait GlobalState {
/// Navigates to the given entity. /// Navigates to the given entity.
@@ -19,7 +30,7 @@ pub trait GlobalState {
if let Some(old_focused_element) = ctx.window().get::<Global>("global").focused_widget { if let Some(old_focused_element) = ctx.window().get::<Global>("global").focused_widget {
let mut old_focused_element = ctx.get_widget(old_focused_element); let mut old_focused_element = ctx.get_widget(old_focused_element);
old_focused_element.set("focused", false); old_focused_element.set("focused", false);
old_focused_element.update_theme_by_state(false); //old_focused_element.update_theme_by_state(false);
} }
ctx.window().get_mut::<Global>("global").focused_widget = None; ctx.window().get_mut::<Global>("global").focused_widget = None;
ctx.widget().set("visibility", Visibility::Collapsed); ctx.widget().set("visibility", Visibility::Collapsed);

View File

@@ -1,8 +1,12 @@
//use chrono::{Local, DateTime, Duration}; //use chrono::{Local, DateTime, Duration};
use dotenv::dotenv; use dotenv::dotenv;
use locales::t; use locales::t;
use orbtk::prelude::*; use orbtk::{
use orbtk::shell::WindowRequest; prelude::*,
shell::WindowRequest,
theme::{COLORS_RON, DARK_THEME_RON, FONTS_RON},
theming::config::ThemeConfig,
};
use serde::Deserialize; use serde::Deserialize;
use std::{env, process}; use std::{env, process};
use std::collections::HashMap; use std::collections::HashMap;
@@ -28,15 +32,20 @@ pub enum Action {
ParseEntry(Entity), ParseEntry(Entity),
AddProgress(f64), AddProgress(f64),
ResetProgress, ResetProgress,
SetMenu(Entity),
SetProgress(f64), SetProgress(f64),
SetProgressPopup(Entity), SetProgressPopup(Entity),
RemoveFocus(Entity), RemoveFocus(Entity),
RemoveProgressPopup(Entity), RemovePopup(Entity),
SetEntry(Entity), SetEntry(Entity),
SetVisibility(Entity), SetVisibility(Entity),
TextChanged(Entity, usize), TextChanged(Entity, usize),
ToggleTheme(Entity),
} }
/// define valid environment variables provided via .env files
/// located in the current call directory
/// this is primarily used in testing scenarios (eg. debugging)
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
struct Environment { struct Environment {
test_lang: String, test_lang: String,
@@ -49,15 +58,20 @@ pub struct PolicyCheckState {
action: Option<Action>, action: Option<Action>,
duration: Duration, duration: Duration,
label_result: Entity, label_result: Entity,
lang: String,
last_focused: Option<Entity>, last_focused: Option<Entity>,
menu_button: Entity, button_menu: Entity,
menu: Entity,
popup_progress: Entity,
policy_data_count: usize, policy_data_count: usize,
policy_numbers: HashMap<usize, PolicyCode>, policy_numbers: HashMap<usize, PolicyCode>,
progress_bar: Entity, progress_bar: Entity,
progress_count: f64, progress_count: f64,
progress_popup: Entity theme: String
} }
static DARK_EXT: &'static str = include_str!("../../resources/stylesheets/advotracker_dark.ron");
impl GlobalState for PolicyCheckState {} impl GlobalState for PolicyCheckState {}
/// method definitions, that react on any given state change inside the view /// method definitions, that react on any given state change inside the view
@@ -71,22 +85,13 @@ impl PolicyCheckState {
pub fn create_hashmap(&mut self, _ctx: &mut Context<'_>) -> Result<(), Box<dyn std::error::Error>> { pub fn create_hashmap(&mut self, _ctx: &mut Context<'_>) -> Result<(), Box<dyn std::error::Error>> {
trace!(target: "advotracker", create_hashmap = "started"); trace!(target: "advotracker", create_hashmap = "started");
// WIP: redundant lang selection (already in main!) let res = t!("policy.string.label_policy_list", self.lang);
let mut lang = env::var("lang").unwrap_or("en".to_string()); let policy_list = PolicyList::new(res);
// testing environment: read from .env file
dotenv().ok();
match envy::from_env::<Environment>() {
Ok(environment) => {
if environment.test_lang != lang { lang = environment.test_lang; }
},
Err(e) => { debug!(target: "advotracker", "{}", e); }
}
let policy_list = PolicyList::new("Allianz Versicherungsnummen-List");
trace!(target: "advotracker", policy_list = ?policy_list); trace!(target: "advotracker", policy_list = ?policy_list);
// create vector to hold imported data // create vector to hold imported data
let mut policy_data = PolicyDataList::new("Allianz-Import latest"); let res = t!("policy.string.label_policy_data", self.lang);
let mut policy_data = PolicyDataList::new(res);
trace!(target: "advotracker", policy_data = ?policy_data); trace!(target: "advotracker", policy_data = ?policy_data);
let mut policy_numbers : HashMap<usize, PolicyCode> = HashMap::new(); let mut policy_numbers : HashMap<usize, PolicyCode> = HashMap::new();
@@ -96,7 +101,7 @@ impl PolicyCheckState {
let mut csv_import_path = String::from("POLLFNR_WOECHENTLICH.txt"); let mut csv_import_path = String::from("POLLFNR_WOECHENTLICH.txt");
match import(&mut csv_import_path, &mut policy_data, match import(&mut csv_import_path, &mut policy_data,
&mut policy_numbers, &mut self.policy_data_count, &mut policy_numbers, &mut self.policy_data_count,
&lang) { &self.lang) {
Ok((count, duration)) => { Ok((count, duration)) => {
self.policy_data_count = count; self.policy_data_count = count;
self.duration = duration; self.duration = duration;
@@ -123,8 +128,24 @@ impl PolicyCheckState {
let _text = text_box.text_mut(); let _text = text_box.text_mut();
} }
/// Get the active language environment.
pub fn get_lang() -> String {
// get system environment
let mut lang = env::var("LANG").unwrap_or("en".to_string());
// testing environment: read from .env file
dotenv().ok();
match envy::from_env::<Environment>() {
Ok(environment) => {
if environment.test_lang != lang { lang = environment.test_lang; }
},
Err(e) => { info!(target: "advotracker", "{}", e) }
}
lang
}
/// Import policy numbers into hashmap /// Import policy numbers into hashmap
fn import_data(&mut self, lang: &String, ctx: &mut Context<'_>) fn import_data(&mut self, ctx: &mut Context<'_>)
-> Result<(), Box<dyn std::error::Error>> { -> Result<(), Box<dyn std::error::Error>> {
// WIP: for now, only import once per session // WIP: for now, only import once per session
if self.policy_data_count == 0 { if self.policy_data_count == 0 {
@@ -134,9 +155,9 @@ impl PolicyCheckState {
if self.policy_numbers.len() == 0 { if self.policy_numbers.len() == 0 {
// initialize popup widget // initialize popup widget
let sender = ctx.window_sender(); let sender = ctx.window_sender();
self.set_progress_popup(&lang, ctx); self.set_popup_progress(ctx);
self.progress_count += 0.33; self.progress_count += 0.33;
self.update_progress_bar(&lang, ctx); self.update_progress_bar(ctx);
sender.send(WindowRequest::Redraw).unwrap(); sender.send(WindowRequest::Redraw).unwrap();
// for _ in 1..4 { // for _ in 1..4 {
@@ -148,27 +169,23 @@ impl PolicyCheckState {
// importing policy code elements from csv-file // importing policy code elements from csv-file
match self.create_hashmap(ctx) { match self.create_hashmap(ctx) {
Ok(()) => { Ok(()) => {
let res = t!("policy.hashmap.success", lang); let res = t!("policy.hashmap.success", self.lang);
info!("hashmap has: {:?} entries", self.policy_data_count); info!("hashmap has: {:?} entries", self.policy_data_count);
trace!(target: "advotracker", trace!(target: "advotracker",
hashmap_status = ?res, hashmap_status = ?res,
hashmap_entries = ?self.policy_data_count); hashmap_entries = ?self.policy_data_count);
self.progress_count = 1.; self.progress_count = 1.;
self.update_progress_bar(&lang, ctx); self.update_progress_bar(ctx);
sender.send(WindowRequest::Redraw).unwrap(); sender.send(WindowRequest::Redraw).unwrap();
} }
_ => { _ => {
let res = t!("policy.hashmap.failed", lang); let res = t!("policy.hashmap.failed", self.lang);
error!("{:?}", res); error!("{:?}", res);
trace!(target: "advotracker", hashmap_status = ?res); trace!(target: "advotracker", hashmap_status = ?res);
} }
} }
// remove popup widget now, that we are done
//self.remove_progress_popup(ctx);
} }
} else { } else {
trace!(target: "advotracker", trace!(target: "advotracker",
@@ -180,8 +197,11 @@ impl PolicyCheckState {
} }
/// Open menu. /// Open menu.
pub fn open_menu(&mut self, text_block: Entity, ctx: &mut Context<'_>) { pub fn open_menu(&mut self, _entity: Entity, ctx: &mut Context<'_>) {
let _menu_string = ctx.get_widget(text_block).get::<String16>("text"); //let menu_string = ctx.get_widget(entity).get::<String16>("text");
//.child(policycheck_menu);
//self.set_popup_menu(ctx);
self.set_menu(ctx);
} }
/// Parse validity of the given policy number. /// Parse validity of the given policy number.
@@ -192,19 +212,19 @@ impl PolicyCheckState {
let policy_number_string = ctx.get_widget(policy_check_policy_number).get::<String16>("text").as_string(); let policy_number_string = ctx.get_widget(policy_check_policy_number).get::<String16>("text").as_string();
let policy_number_length = policy_number_string.len(); let policy_number_length = policy_number_string.len();
// WIP: redundant lang selection (already in main!) // // WIP: redundant lang selection (already in main!)
let mut lang = env::var("lang").unwrap_or("en".to_string()); // let mut lang = env::var("lang").unwrap_or("en".to_string());
// testing environment: read from .env file // // testing environment: read from .env file
dotenv().ok(); // dotenv().ok();
match envy::from_env::<Environment>() { // match envy::from_env::<Environment>() {
Ok(environment) => { // Ok(environment) => {
if environment.test_lang != lang { lang = environment.test_lang; } // if environment.test_lang != lang { lang = environment.test_lang; }
}, // },
Err(e) => { debug!(target: "advotracker", "{}", e); } // Err(e) => { debug!(target: "advotracker", "{}", e); }
} // }
// Load data into hashmap // Load data into hashmap
match self.import_data(&lang, ctx) { match self.import_data(ctx) {
Ok(()) => trace!(target: "advotracker", policycheck_state = "init", import_data = "success"), Ok(()) => trace!(target: "advotracker", policycheck_state = "init", import_data = "success"),
Err(e) => trace!(target: "advotracker", policycheck_state = "init", import_data = ?e), Err(e) => trace!(target: "advotracker", policycheck_state = "init", import_data = ?e),
} }
@@ -236,7 +256,7 @@ impl PolicyCheckState {
result_wrapper.set_text(string_result); result_wrapper.set_text(string_result);
button(ctx.child("policy_check_button_result")).set_icon(material_icons_font::MD_CHECK); button(ctx.child("policy_check_button_result")).set_icon(material_icons_font::MD_CHECK);
button(ctx.child("policy_check_button_result")).set_icon_brush("#008000"); button(ctx.child("policy_check_button_result")).set_icon_brush("#008000");
let res = t!("policy.validation.button_success", lang); let res = t!("policy.validation.button_success", self.lang);
button(ctx.child("policy_check_button_result")).set_text(res); button(ctx.child("policy_check_button_result")).set_text(res);
button(ctx.child("policy_check_button_result")).set_visibility(Visibility::Visible); button(ctx.child("policy_check_button_result")).set_visibility(Visibility::Visible);
button(ctx.child("policy_check_button_result")).set_foreground("#008000"); button(ctx.child("policy_check_button_result")).set_foreground("#008000");
@@ -245,16 +265,16 @@ impl PolicyCheckState {
} }
_ => { _ => {
// no matching key // no matching key
let res = t!("policy.validation.failed", lang); let res = t!("policy.validation.failed", self.lang);
trace!(target: "advotracker", state = ?res, policy_number = ?p); trace!(target: "advotracker", state = ?res, policy_number = ?p);
button(ctx.child("policy_check_button_result")).set_icon(material_icons_font::MD_CLEAR); button(ctx.child("policy_check_button_result")).set_icon(material_icons_font::MD_CLEAR);
button(ctx.child("policy_check_button_result")).set_icon_brush("#FF0000"); button(ctx.child("policy_check_button_result")).set_icon_brush("#FF0000");
let res = t!("policy.validation.button_failed", lang); let res = t!("policy.validation.button_failed", self.lang);
button(ctx.child("policy_check_button_result")).set_text(res); button(ctx.child("policy_check_button_result")).set_text(res);
button(ctx.child("policy_check_button_result")).set_visibility(Visibility::Visible); button(ctx.child("policy_check_button_result")).set_visibility(Visibility::Visible);
button(ctx.child("policy_check_button_result")).set_foreground("#FF0000"); button(ctx.child("policy_check_button_result")).set_foreground("#FF0000");
let mut text_block_wrapper: TextBlockCtx<'_> = text_block(ctx.child("policy_check_result")); let mut text_block_wrapper: TextBlockCtx<'_> = text_block(ctx.child("policy_check_result"));
let res = t!("policy.validation.not_found", lang); let res = t!("policy.validation.not_found", self.lang);
text_block_wrapper.set_text(res); text_block_wrapper.set_text(res);
text_block(ctx.child("policy_check_label_result")).set_visibility(Visibility::Visible); text_block(ctx.child("policy_check_label_result")).set_visibility(Visibility::Visible);
} }
@@ -268,7 +288,7 @@ impl PolicyCheckState {
button(ctx.child("policy_check_button_result")).set_foreground("#FF0000"); button(ctx.child("policy_check_button_result")).set_foreground("#FF0000");
text_block(ctx.child("policy_check_label_result")).set_visibility(Visibility::Visible); text_block(ctx.child("policy_check_label_result")).set_visibility(Visibility::Visible);
let mut text_block_wrapper: TextBlockCtx<'_> = text_block(ctx.child("policy_check_result")); let mut text_block_wrapper: TextBlockCtx<'_> = text_block(ctx.child("policy_check_result"));
let res = t!("policy.validation.invalid_input", lang); let res = t!("policy.validation.invalid_input", self.lang);
text_block_wrapper.set_text(res); text_block_wrapper.set_text(res);
text_block_wrapper.set_enabled(true); text_block_wrapper.set_enabled(true);
} }
@@ -277,7 +297,7 @@ impl PolicyCheckState {
if policy_number_length < 10 { if policy_number_length < 10 {
let mut text_block_wrapper: TextBlockCtx<'_> = text_block(ctx.child("policy_check_result")); let mut text_block_wrapper: TextBlockCtx<'_> = text_block(ctx.child("policy_check_result"));
text_block_wrapper.set_enabled(true); text_block_wrapper.set_enabled(true);
let res = t!("policy.validation.to_short", lang); let res = t!("policy.validation.to_short", self.lang);
text_block_wrapper.set_text(res); text_block_wrapper.set_text(res);
text_block(ctx.child("policy_check_label_result")).set_visibility(Visibility::Visible); text_block(ctx.child("policy_check_label_result")).set_visibility(Visibility::Visible);
//self.set_visibility(policy_check_policy_number, ctx); //self.set_visibility(policy_check_policy_number, ctx);
@@ -285,7 +305,7 @@ impl PolicyCheckState {
if policy_number_length > 10 { if policy_number_length > 10 {
let mut text_block_wrapper: TextBlockCtx<'_> = text_block(ctx.child("policy_check_result")); let mut text_block_wrapper: TextBlockCtx<'_> = text_block(ctx.child("policy_check_result"));
text_block_wrapper.set_enabled(true); text_block_wrapper.set_enabled(true);
let res = t!("policy.validation.to_long", lang); let res = t!("policy.validation.to_long", self.lang);
text_block_wrapper.set_text(res); text_block_wrapper.set_text(res);
text_block(ctx.child("policy_check_label_result")).set_visibility(Visibility::Visible); text_block(ctx.child("policy_check_label_result")).set_visibility(Visibility::Visible);
} }
@@ -293,13 +313,11 @@ impl PolicyCheckState {
trace!(target: "advotracker", parse_entry = "finished"); trace!(target: "advotracker", parse_entry = "finished");
} }
/// Remove a popup box showing the data import status in a progress bar /// Remove the menu popup box
fn remove_progress_popup(&mut self, ctx: &mut Context<'_>) { fn remove_popup(&mut self, id: Entity, ctx: &mut Context<'_>) {
let progress_popup = self.progress_popup; ctx.remove_child(self.menu);
//let sleep = time::Duration::from_secs(3); ctx.remove_child(self.popup_progress);
//thread::sleep(sleep); println!("Popup {:?} removed !", id);
ctx.remove_child(progress_popup);
println!("ProgressPopup {:?} removed !", progress_popup);
} }
// /// If TextBox 'policy_check_policy_number' is empty, disable button "clear" // /// If TextBox 'policy_check_policy_number' is empty, disable button "clear"
@@ -318,11 +336,7 @@ impl PolicyCheckState {
/// Change status of given text box to edit mode. /// Change status of given text box to edit mode.
fn set_entry(&mut self, policy_check_policy_number: Entity, ctx: &mut Context<'_>) { fn set_entry(&mut self, policy_check_policy_number: Entity, ctx: &mut Context<'_>) {
if *ctx.get_widget(policy_check_policy_number).get::<bool>("focused") { if *ctx.get_widget(policy_check_policy_number).get::<bool>("focused") {
//let mut my_ctx: WidgetContainer<'_> = ctx.widget();
//let mut child: WidgetContainer<'_> = ctx.get_widget(policy_check_policy_number);
//ctx.get_widget(policy_check_policy_number).set("enabled", true);
let mut text_box_wrapper: TextBoxCtx<'_> = text_box(ctx.child("policy_check_policy_number")); let mut text_box_wrapper: TextBoxCtx<'_> = text_box(ctx.child("policy_check_policy_number"));
//ctx.push_event_by_window(FocusEvent::RemoveFocus(policy_check_policy_number));
text_box_wrapper.set_visibility( Visibility::Visible); text_box_wrapper.set_visibility( Visibility::Visible);
text_box_wrapper.set_enabled(true); text_box_wrapper.set_enabled(true);
text_box_wrapper.set_text(""); text_box_wrapper.set_text("");
@@ -332,31 +346,46 @@ impl PolicyCheckState {
if let Some(old_focused_element) = ctx.window().get::<Global>("global").focused_widget { if let Some(old_focused_element) = ctx.window().get::<Global>("global").focused_widget {
ctx.push_event_by_window(FocusEvent::RemoveFocus(old_focused_element)); ctx.push_event_by_window(FocusEvent::RemoveFocus(old_focused_element));
} }
} }
/// Set a progress popup that updates the import status in a progress bar /// Set a menu
fn set_progress_popup(&mut self, lang: &String, ctx: &mut Context<'_>) { fn set_menu(&mut self, ctx: &mut Context<'_>) {
//println!("Set up Progress popup: {:?}", text_box);
let stack = ctx
.entity_of_child(ID_POLICY_CHECK_RESULT)
.expect("PolicyCheckState.init: Can't find entity of resource 'ID_POLICY_CHECK_RESULT'.");
let current_entity = ctx.entity; let current_entity = ctx.entity;
let build_context = &mut ctx.build_context(); let build_context = &mut ctx.build_context();
let res = t!("policy.string.progress_text", lang); // create a menu overlay
let progress_popup = create_progress_popup(current_entity, &res, build_context); self.menu = create_menu(current_entity, build_context);
let _menu = build_context.append_child_to_overlay(self.menu)
.expect("PolicyCheckState: Can't create overlay as child of entity");
let label_account = t!("policy.menu.label_account", self.lang);
button(ctx.child(ID_POLICY_CHECK_MENU_LABEL_ACCOUNT)).set_text(label_account);
let label_quit = t!("policy.menu.label_quit", self.lang);
button(ctx.child(ID_POLICY_CHECK_MENU_LABEL_QUIT)).set_text(label_quit);
let label_toggle_theme = t!("policy.menu.label_toggle_theme", self.lang);
button(ctx.child(ID_POLICY_CHECK_MENU_LABEL_TOGGLE_THEME)).set_text(label_toggle_theme);
}
/// Set a progress popup that updates the import status in a progress bar
fn set_popup_progress(&mut self, ctx: &mut Context<'_>) {
//println!("Set up Progress popup: {:?}", text_box);
let stack = ctx
.entity_of_child(ID_POLICY_CHECK_RESULT)
.expect("PolicyCheckState: Can't find entity of resource 'ID_POLICY_CHECK_RESULT'.");
let current_entity = ctx.entity;
let build_context = &mut ctx.build_context();
let res = t!("policy.string.progress_text", self.lang);
self.popup_progress = create_popup_progress(current_entity, &res, build_context);
// create a progress_popup widget as a child of entity "ID_POLICY_CHECK_POLICY_NUMBER" // create a progress_popup widget as a child of entity "ID_POLICY_CHECK_POLICY_NUMBER"
build_context.append_child(stack, progress_popup); build_context.append_child(stack, self.popup_progress);
self.progress_popup = progress_popup;
let progress_bar = ctx self.progress_bar = ctx
.entity_of_child(ID_POLICY_CHECK_PROGRESS_BAR) .entity_of_child(ID_POLICY_CHECK_PROGRESS_BAR)
.expect("PolicyCheckState.init: Can't find entity of resource 'ID_POLICY_CHECK_PROGRESS_BAR'."); .expect("PolicyCheckState.init: Can't find entity of resource 'ID_POLICY_CHECK_PROGRESS_BAR'.");
self.progress_bar = progress_bar;
println!("ProgressPopup created: {:?}", progress_popup); println!("PopupProgress created: {:?}", self.popup_progress);
} }
/// Change visibility of the result label. /// Change visibility of the result label.
@@ -369,7 +398,19 @@ impl PolicyCheckState {
text_block(ctx.child(ID_POLICY_CHECK_BUTTON_RESULT)).set_visibility(Visibility::Visible); text_block(ctx.child(ID_POLICY_CHECK_BUTTON_RESULT)).set_visibility(Visibility::Visible);
} }
ctx.get_widget(self.label_result).update_theme_by_state(true); //ctx.get_widget(self.label_result).update_theme_by_state(true);
}
/// Set and activate the theme attributes.
pub fn theme() -> Theme {
Theme::from_config(
// sourcing: crates/theme/assets/dark/dark.ron
ThemeConfig::from(DARK_THEME_RON)
.extend(ThemeConfig::from(DARK_EXT))
.extend(ThemeConfig::from(COLORS_RON))
.extend(ThemeConfig::from(FONTS_RON)),
)
} }
/// Update count of elements in the policy data list. /// Update count of elements in the policy data list.
@@ -378,8 +419,8 @@ impl PolicyCheckState {
ctx.widget().set(PROP_POLICY_DATA_COUNT, data_list_count); ctx.widget().set(PROP_POLICY_DATA_COUNT, data_list_count);
} }
fn update_progress_bar(&self, lang: &String, ctx: &mut Context<'_>) { fn update_progress_bar(&self, ctx: &mut Context<'_>) {
let res = t!("policy.string.progress_time", lang); let res = t!("policy.string.progress_time", self.lang);
let string_duration = format!("{}: {:?}", res, self.duration); let string_duration = format!("{}: {:?}", res, self.duration);
text_block(ctx.child(ID_POLICY_CHECK_PROGRESS_TIME)).set_text(string_duration); text_block(ctx.child(ID_POLICY_CHECK_PROGRESS_TIME)).set_text(string_duration);
@@ -397,7 +438,7 @@ impl State for PolicyCheckState {
trace!(target: "advotracker", policycheck_state = "init", status = "started"); trace!(target: "advotracker", policycheck_state = "init", status = "started");
// Entities // Entities
self.menu_button = ctx self.button_menu = ctx
.entity_of_child(ID_POLICY_CHECK_BUTTON_MENU) .entity_of_child(ID_POLICY_CHECK_BUTTON_MENU)
.expect("PolicyCheckState.init: Can't find resource entity 'ID_POLICY_CHECK_BUTTON_MENU'."); .expect("PolicyCheckState.init: Can't find resource entity 'ID_POLICY_CHECK_BUTTON_MENU'.");
@@ -405,14 +446,6 @@ impl State for PolicyCheckState {
.entity_of_child(ID_POLICY_CHECK_LABEL_RESULT) .entity_of_child(ID_POLICY_CHECK_LABEL_RESULT)
.expect("PolicyCheckState.init: Can't find resource entity 'ID_POLICY_CHECK_LABEL_RESULT'."); .expect("PolicyCheckState.init: Can't find resource entity 'ID_POLICY_CHECK_LABEL_RESULT'.");
// self.progress_bar = ctx
// .entity_of_child(ID_POLICY_CHECK_PROGRESS_BAR)
// .expect("PolicyCheckState.init: Can't find resource entity 'ID_POLICY_CHECK_PROGRESS_BAR'.");
// self.progress_popup = ctx
// .entity_of_child(ID_POLICY_CHECK_PROGRESS_POPUP)
// .expect("PolicyCheckState.init: Can't find resource entity 'ID_POLICY_CHECK_PROGRESS_POPUP'.");
// WIP: redundant lang selection (already in main!) // WIP: redundant lang selection (already in main!)
let mut lang = env::var("lang").unwrap_or("en".to_string()); let mut lang = env::var("lang").unwrap_or("en".to_string());
// testing environment: read from .env file // testing environment: read from .env file
@@ -423,24 +456,21 @@ impl State for PolicyCheckState {
}, },
Err(e) => { debug!(target: "advotracker", "{}", e); } Err(e) => { debug!(target: "advotracker", "{}", e); }
} }
self.lang = lang;
// Constants // Constants
let res = t!("policy.string.header", lang); let res = t!("policy.string.header", self.lang);
text_block(ctx.child(ID_POLICY_CHECK_HEADER)).set_text(res); text_block(ctx.child(ID_POLICY_CHECK_HEADER)).set_text(res);
let res = t!("policy.string.label_policy_number", lang); let res = t!("policy.string.label_policy_number", self.lang);
let string_label_policy_number = format!("{}:", res); let string_label_policy_number = format!("{}:", res);
text_block(ctx.child(ID_POLICY_CHECK_LABEL_POLICY_NUMBER)).set_text(string_label_policy_number); text_block(ctx.child(ID_POLICY_CHECK_LABEL_POLICY_NUMBER)).set_text(string_label_policy_number);
let res = t!("policy.string.label_result", lang); let res = t!("policy.string.label_result", self.lang);
let string_label_result = format!("{}:", res); let string_label_result = format!("{}:", res);
text_block(ctx.child(ID_POLICY_CHECK_LABEL_RESULT)).set_text(string_label_result); text_block(ctx.child(ID_POLICY_CHECK_LABEL_RESULT)).set_text(string_label_result);
text_block(ctx.child(ID_POLICY_CHECK_LABEL_RESULT)).set_visibility(Visibility::Collapsed); text_block(ctx.child(ID_POLICY_CHECK_LABEL_RESULT)).set_visibility(Visibility::Collapsed);
// self.progress_popup = ctx
// .entity_of_child(ID_POLICY_CHECK_PROGRESS_POPUP)
// .expect("PolicyCheckState.init: Can't find entity of resource 'ID_POLICY_CHECK_PROGRESS_POPUP'.");
// // Load the saved data from a file in 'ron' format into our data structure. // // Load the saved data from a file in 'ron' format into our data structure.
// // The cargo package identifier (default: 'nwx.advotracker') is used as the // // The cargo package identifier (default: 'nwx.advotracker') is used as the
// // app directory name. The directory location is OS dependant // // app directory name. The directory location is OS dependant
@@ -453,10 +483,6 @@ impl State for PolicyCheckState {
// ctx.widget().set(PROP_ADVOTRACKER, policy_data); // ctx.widget().set(PROP_ADVOTRACKER, policy_data);
// } // }
// number of elements in the restored policy data
//policy_data_count = policy_data.len().clone;
//self.update_data_count(ctx);
let time_end = SystemTime::now(); let time_end = SystemTime::now();
let duration = time_end.duration_since(time_start); let duration = time_end.duration_since(time_start);
@@ -482,7 +508,7 @@ impl State for PolicyCheckState {
let new_width = old_width + increment; let new_width = old_width + increment;
// Set the ProgressBar's val property to the calculated percentage // Set the ProgressBar's val property to the calculated percentage
// (whereas 0.0 means 0 %, and 1.0 means 100 %) to increment the progress // (whereas 0.0 means 0 %, and 1.0 means 100 %) to increment the progress
if new_width <= 1.0 { if new_width <= 1. {
progress_bar(ctx.child(ID_POLICY_CHECK_PROGRESS_BAR)).set_val(new_width); progress_bar(ctx.child(ID_POLICY_CHECK_PROGRESS_BAR)).set_val(new_width);
} else { } else {
progress_bar(ctx.child(ID_POLICY_CHECK_PROGRESS_BAR)).set_val(1.); progress_bar(ctx.child(ID_POLICY_CHECK_PROGRESS_BAR)).set_val(1.);
@@ -495,8 +521,7 @@ impl State for PolicyCheckState {
println!("entry changed: {}", text_box(ctx.get_widget(entity)).text()); println!("entry changed: {}", text_box(ctx.get_widget(entity)).text());
} }
Action::ImportData => { Action::ImportData => {
let lang = "en".to_string(); match self.import_data(ctx) {
match self.import_data(&lang, ctx) {
Ok(()) => { Ok(()) => {
trace!(target: "advotracker", import_data = "success"); trace!(target: "advotracker", import_data = "success");
} }
@@ -506,8 +531,8 @@ impl State for PolicyCheckState {
} }
} }
} }
Action::OpenMenu(text_block) => { Action::OpenMenu(entity) => {
self.open_menu(text_block, ctx); self.open_menu(entity, ctx);
} }
Action::ParseEntry(text_box) => { Action::ParseEntry(text_box) => {
self.parse_entry(text_box, ctx); self.parse_entry(text_box, ctx);
@@ -516,8 +541,8 @@ impl State for PolicyCheckState {
ctx.get_widget(policy_check_policy_number).set("enabled", false); ctx.get_widget(policy_check_policy_number).set("enabled", false);
ctx.push_event_by_window(FocusEvent::RemoveFocus(policy_check_policy_number)); ctx.push_event_by_window(FocusEvent::RemoveFocus(policy_check_policy_number));
} }
Action::RemoveProgressPopup(_entity) => { Action::RemovePopup(entity) => {
self.remove_progress_popup(ctx); self.remove_popup(entity, ctx);
} }
Action::ResetProgress => { Action::ResetProgress => {
progress_bar(ctx.child(ID_POLICY_CHECK_PROGRESS_BAR)).set_val(0.); progress_bar(ctx.child(ID_POLICY_CHECK_PROGRESS_BAR)).set_val(0.);
@@ -526,6 +551,9 @@ impl State for PolicyCheckState {
//self.last_focused = Some(); //self.last_focused = Some();
self.set_entry(policy_check_policy_number, ctx); self.set_entry(policy_check_policy_number, ctx);
} }
Action::SetMenu(_entity) => {
self.set_menu(ctx);
}
Action::SetProgress(value) => { Action::SetProgress(value) => {
if value >= 0. || value <= 1. { if value >= 0. || value <= 1. {
progress_bar(ctx.child(ID_POLICY_CHECK_PROGRESS_BAR)).set_val(value); progress_bar(ctx.child(ID_POLICY_CHECK_PROGRESS_BAR)).set_val(value);
@@ -534,8 +562,7 @@ impl State for PolicyCheckState {
} }
} }
Action::SetProgressPopup(_entity) => { Action::SetProgressPopup(_entity) => {
let lang = "en".to_string(); self.set_popup_progress(ctx);
self.set_progress_popup(&lang, ctx);
} }
Action::SetVisibility(_entity) => { Action::SetVisibility(_entity) => {
text_block(ctx.child(ID_POLICY_CHECK_LABEL_RESULT)).set_visibility(Visibility::Collapsed); text_block(ctx.child(ID_POLICY_CHECK_LABEL_RESULT)).set_visibility(Visibility::Collapsed);
@@ -543,6 +570,21 @@ impl State for PolicyCheckState {
Action::TextChanged(entity, _index) => { Action::TextChanged(entity, _index) => {
self.set_entry(entity, ctx); self.set_entry(entity, ctx);
} }
Action::ToggleTheme(_entity) => {
if self.theme == "light" {
self.theme = "dark_theme".to_string();
} else {
self.theme = "light_theme".to_string();
}
//match &self.theme {
// light => { self.theme = "dark_theme".to_string(); }
// dark => { self.theme = "light_theme".to_string(); }
// _ => { debug!(target: "advotracker", "theme not supported!"); }
// }
println!{"Switch theme to {:?}", self.theme}
let theme = dark_theme();
ctx.switch_theme(theme);
}
} }
} }
// Reset action // Reset action
@@ -568,53 +610,135 @@ impl State for PolicyCheckState {
} }
} }
/// Create a progress popup with update status of an onging data import /// Create a menu popup
fn create_progress_popup(popup: Entity, text: &str, ctx: &mut BuildContext<'_>) -> Entity { fn create_menu(menu: Entity, ctx: &mut BuildContext<'_>) -> Entity {
Popup::new() Container::new()
.id(ID_POLICY_CHECK_PROGRESS_POPUP) .style("container_menu")
.target(popup)
.open(true)
.width(280.0) .width(280.0)
.height(140.0) .height(140.0)
.h_align("left") .position((100.0, 100.0))
.child(
Grid::new()
.id(ID_POLICY_CHECK_MENU)
.columns(
Columns::new()
// Menu Button
.add("80")
// Seperator
.add("1")
// Keyboard Shortcut
.add("*")
.build(),
)
.rows(
Rows::new()
.add("auto")
.add("auto")
.add("auto")
.build(),
)
.child(
Button::new()
.id(ID_POLICY_CHECK_MENU_LABEL_ACCOUNT)
.style("button_menu")
.attach(Grid::row(0))
.attach(Grid::column(0))
.attach(Grid::column_span(2))
.icon(material_icons_font::MD_PERSON)
.build(ctx),
)
.child(
Button::new()
.id(ID_POLICY_CHECK_MENU_LABEL_TOGGLE_THEME)
//.style("body")
.style("button_menu")
.attach(Grid::row(1))
.attach(Grid::column(0))
.attach(Grid::column_span(2))
.icon(material_icons_font::MD_EDIT)
.on_click(move |states, _| {
states.get_mut::<PolicyCheckState>(menu)
.action(Action::ToggleTheme(menu));
true
})
.build(ctx),
)
.child(
Button::new()
.id(ID_POLICY_CHECK_MENU_LABEL_QUIT)
//.style("body")
.style("button_menu")
.attach(Grid::row(2))
.attach(Grid::column(0))
.attach(Grid::column_span(2))
.icon(material_icons_font::MD_SETTINGS_POWER)
.on_mouse_down(move |_states, _| {
process::exit(0);
})
// .on_key_down(move | ctx, "Ctlr+Q"| {
// process::exit(0);
// })
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_MENU_SHORTCUT_QUIT)
.style("button_menu")
//.style("body")
.attach(Grid::row(2))
.attach(Grid::column(2))
.margin((0, 0, 16, 0))
.h_align("end")
.v_align("center")
.text("CTRL+Q")
.build(ctx),
)
.build(ctx),
)
.build(ctx)
}
/// Create a progress popup with update status of an onging data import
fn create_popup_progress(target: Entity, text: &str, ctx: &mut BuildContext<'_>) -> Entity {
Popup::new()
.id(ID_POLICY_CHECK_POPUP_PROGRESS)
.target(target)
.open(true)
//.style("popup_progress")
.width(280)
.height(100)
.on_mouse_down(move |ctx, _| { .on_mouse_down(move |ctx, _| {
println!("on_click -> remove_progress_popup()"); println!("on_click -> remove_popup_progress()");
ctx.get_mut::<PolicyCheckState>(popup) ctx.get_mut::<PolicyCheckState>(target)
.action(Action::RemoveProgressPopup(popup)); .action(Action::RemovePopup(target));
true true
}) })
.child( .child(
Container::new() Container::new()
//.background("transparent") .style("container_progress")
.border_radius(3.)
.border_width(2.)
.padding(16.)
.child( Stack::new() .child( Stack::new()
.h_align("center") .style("stack_progress")
.margin((16., 16., 16., 16.))
.spacing(16.)
// default: .orientation("vertical")
.child( .child(
TextBlock::new() TextBlock::new()
.id(ID_POLICY_CHECK_PROGRESS_TEXT) .id(ID_POLICY_CHECK_PROGRESS_TEXT)
.h_align("center") //.style("textblock_progress")
.v_align("top") .font_size(12)
.text(text) .text(text)
.build(ctx) .build(ctx)
) )
.child( .child(
ProgressBar::new() ProgressBar::new()
.id(ID_POLICY_CHECK_PROGRESS_BAR) .id(ID_POLICY_CHECK_PROGRESS_BAR)
.val(0.) .val(0)
.width(250.) //.width(250)
.build(ctx) .build(ctx)
) )
.child( .child(
TextBlock::new() TextBlock::new()
.id(ID_POLICY_CHECK_PROGRESS_TIME) .id(ID_POLICY_CHECK_PROGRESS_TIME)
//.style("textblock_progress")
.h_align("end") .h_align("end")
.v_align("bottom") .font_size(12)
//.text()
.build(ctx) .build(ctx)
) )
.build(ctx) .build(ctx)