advotracker: reorganize the project using a crate based structure

* advotracker: the framework project
* crate/advotrackerdb: implementation of the database backend
* crate/advotrackerd: implementation of the backend (daemon)
* crate/adovtracker: implementaton of the application (CLI and GUI)

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
This commit is contained in:
2021-03-07 18:52:14 +01:00
parent 4c88167bef
commit 5a9965751a
252 changed files with 131 additions and 2537479 deletions

8
.gitmodules vendored
View File

@@ -1,6 +1,6 @@
[submodule "advotracker-db"] [submodule "advotrackerdb"]
path = advotracker-db path = crates/advotrackerdb
url = https://gitea.networkx.de:50443/rzerres/advotracker-db url = https://gitea.networkx.de:50443/rzerres/advotrackerdb
[submodule "advotrackerd"] [submodule "advotrackerd"]
path = advotrackerd path = crates/advotrackerd
url = https://gitea.networkx.de:50443/rzerres/advotrackerd url = https://gitea.networkx.de:50443/rzerres/advotrackerd

View File

@@ -1,5 +1,5 @@
[package] [package]
name = "advotracker-framework" name = "advotracker"
version = "0.1.0" version = "0.1.0"
authors = ["Ralf Zerres <ralf.zerres@networkx.de>"] authors = ["Ralf Zerres <ralf.zerres@networkx.de>"]
description = "Supports lawyers to capture relevant data encountered during an online legal advice\n" description = "Supports lawyers to capture relevant data encountered during an online legal advice\n"
@@ -8,8 +8,13 @@ homepage = "https://gitea.networkx.de:50443/rzerres/advotracker"
documentation = "https://docs.rs/advotracker" documentation = "https://docs.rs/advotracker"
readme = "README.md" readme = "README.md"
license = "0BSD OR MIT" license = "0BSD OR MIT"
keywords = [
"advotracker",
"lawyer",
]
edition = "2018" edition = "2018"
publish = false publish = false
#default-run = "crates/advotracker_client"
[profile.release] [profile.release]
panic = "abort" panic = "abort"
@@ -41,10 +46,22 @@ panic = 'unwind'
incremental = true incremental = true
overflow-checks = true overflow-checks = true
[dependencies]
advotrackerdb = { version = "0.1.0-alpha1", path = "crates/advotrackerdb" }
advotrackerd = { version = "0.1.0-alpha1", path = "crates/advotrackerd", default-features = false }
advotracker_client = { version = "0.1.5-alpha1", path = "crates/advotracker_client", default-features = false }
[features]
default = ["sqlite"]
# enable optional db backends
sqlite = []
#sqlite = ["advotrackerdb_sqlite"]
#postgresql = ["advotrackerdb_pstgresql"]
[workspace] [workspace]
members = [ members = [
"advotrackerd", "crates/advotrackerd",
"advotracker-db", "crates/advotrackerdb",
"advotracker", "crates/advotracker_client",
"advotracker_qml",
] ]

View File

@@ -6,14 +6,14 @@
## About ## About
`AdvoTracker` supports lawyers to capture relevant data encountered during an online `advotracker` supports lawyers to capture relevant data encountered during an online
legal advice. legal advice.
The application components are implemented using the programming language *Rust*. The application components are implemented using the programming language *Rust*.
The graphical user interface (GUI) uses the class-lib *OrbTk*, which is natively The graphical user interface (GUI) uses the class-lib *OrbTk*, which is natively
encoded in *Rust* as well. encoded in *Rust* as well.
`AdvoTracker` can be deployed on every target operating system that is officialy `advotracker` can be deployed on every target operating system that is officialy
supported by the `OrbTK` toolkit. Currently included are: supported by the `OrbTK` toolkit. Currently included are:
* macOS * macOS
@@ -36,24 +36,24 @@ as documentation sources.
Dialogs and messages generated inside the application will respect the system language Dialogs and messages generated inside the application will respect the system language
of the active user. This is adaptable via the environment variable of the active user. This is adaptable via the environment variable
(default: LANG = en_US.UTF8 ). (default: LANG = en_US.UTF8 or LANG = C).
Within the source code you can find translated constants in the subdirectory 'locales' Within the source code you can find translated constants in the subdirectory 'locales'
(<src-root>/advotracker/src/locales/advotracker.json). (<crate-root>/src/locales/advotracker.json).
For every supported language-string, you will find a block starting with the For every supported language-string, you will find a block starting with the
generic message code, followed by the target language translation. Translation lines generic message code, followed by the target language translation. Translation lines
are identified by its ISO Code (e.g. de_DE.UTF8, es_ES.UTF8). are identified by its ISO Code (e.g. de_DE.UTF8, es_ES.UTF8).
## Installation from source code ## Installation from source code
You can either download the `Advotracker` source code as a Zip-File or using `git` You can either download the `advotracker` source code as a Zip-File or using `git`
from projects repositoy URL. from projects repositoy URL.
The source code is subdiveded in three submodules: The source code is subdiveded in three crates:
* advotracker * advotracker
* advotrackerd * advotrackerd
* advotracker-db * advotrackerdb
Currently the given WEB-URL certificate is signed by a Microsoft CA. Currently the given WEB-URL certificate is signed by a Microsoft CA.
Since this CA can't be verified from offical CA-lists you have to proceed as follows: Since this CA can't be verified from offical CA-lists you have to proceed as follows:
@@ -149,7 +149,7 @@ This work is licensed under a [Creative Common License 4.0][License-CC_BY]
![Creative Common Logo][Logo-CC_BY] ![Creative Common Logo][Logo-CC_BY]
<EFBFBD> 2020 Ralf Zerres, Networkx GmbH <EFBFBD> 2020-2021 Ralf Zerres, Networkx GmbH
--- ---

Submodule advotracker-db deleted from 51e747ef6d

View File

@@ -1,68 +0,0 @@
[package]
name = "advotracker"
version = "0.1.5"
authors = ["Ralf Zerres <ralf.zerres@networkx.de>"]
description = "Frontend component that supports lawyers to capture relevant data encountered during an online legal advice."
readme = "README.md"
license = "(0BSD OR MIT)"
edition = "2018"
default-run = "advotracker"
[target.x86_64-pc-windows-gnu]
linker = "/usr/bin/x86_64-w64-mingw32-gcc"
ar = "/usr/x86_64-w64-mingw32i/bin/ar"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winuser"] }
#diesel = { version = "1.4", features = [ "postgres", "sqlite" ] }
[dependencies]
async-stream = "~0.2"
chrono = { version = "~0.4.0", features = ["serde"] }
cfg-if = { version = "~1.0" }
clap = { version = "~2.33", features = ["suggestions", "color"] }
csv = { version = "~1.1" }
dotenv = { version = "~0.15.0" }
envy = { version = "~0.4" }
lettre = "0.10.0-beta.1"
lazy_static = { version = "~1.4.0" }
log = { version = "~0.4.8" }
locales = { version = "~0.1" }
maud = { version = "~0.22.1" }
#orbtk = { version = "~0.3.1-alpha4" }
#orbtk = { git = "https://github.com/redox-os/orbtk.git", branch = "develop" }
orbtk = { path = "../../orbtk" }
serde = { version = "~1.0", features = ["derive"] }
substring = { version = "~1" }
#tokio = { version = "~0.2", features = ["macros", "rt-threaded", "stream", "time"] }
tracing = { version = "~0.1" }
tracing-subscriber = { version = "~0.2.0", features = ["tracing-log"] }
viperus = { git = "https://github.com/maurocordioli/viperus", features = ["cache", "fmt-clap", "fmt-env", "global", "watch"] }
[dev-dependencies]
[features]
default = []
debug = ["orbtk/debug"]
light = []
[package.metadata.bundle]
name = "advotracker"
identifier = "nwx.advotracker"
short_description = "Online legal advice helper."
description = "Supports lawyers to capture relevant data encountered during an online legal advice.\n"
[profile.dev]
opt-level = 1
incremental = true
[profile.release]
incremental = true
#[[bin]]
#//name = "policycheck"
#path = "src/bin/policycheck.rs"
[[bin]]
name = "advotracker"
path = "src/main.rs"

View File

@@ -1,59 +0,0 @@
// *
// * advotracker - Hotline tackingtool for Advocats
// *
// * Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
// * SPDX-License-Identifier: (0BSD or MIT)
// */
// the language class
Dictionary (
// the map of active identifiers
// like a struct, but keys are also values instead of just beenig identifiers
words: {
// policycheck_view
"Validation policy number": "Prüfung Versicherungsnummer",
"Policy number": "Versicherungsnummer",
"Policy code": "Vers.-Schein/Schadennummer",
"Policy holder": "Versicherungsnehmer",
"Checklist elements: ": "Prüflistenelemente: ",
"Check result": "Prüfungsergebnis",
"Importing data": "Importiere Datensätze",
"Processing time": "Bearbeitungszeit",
"Error:": "Fehler:",
"Reason": "Grund",
"Policy number is to long": "Die Nummer ist zu lang",
"Policy number is to short": "Die Nummer ist zu kurz",
"The given policy number is invalid": "Die Versicherungsnummer ist ungültig",
"The given policy number is valid": "Die Versicherungsnummer ist gültig",
"Only numbers are valid": "Nur Nummern sind zulässig",
"Account": "Benutzer",
"Toggle theme": "Thema wechseln",
"Quit": "Beenden",
// ticketdata_view
"Callback number": "Rückrufnummer",
"Callback date": "Erreichbarkeit",
"Clear": "Zurücksetzen",
"Deductible": "Selbstbehalt",
"Harm type": "Rechtsproblem",
"IVR comment": "Rechtsrat",
"Policy holder": "Versicherungsnehmer",
"Recipient (To)": "Empfänger (To)",
"Copie (CC)": "Kopie (CC)",
"Send": "Senden",
// localization view
"Language ID": "Sprache ID",
"Localization dialog": "Lokalisierungs-Dialog",
"German": "Deutsch",
"English": "Englisch",
// configuration view
"Configuration settings": "Konfigurationseinstellungen",
"Configuration file": "Konfigurationsdatei",
"Language Id": "Sprach-Id",
"Default theme": "Standard-Thema",
"Load": "Laden",
"Save": "Speichern",
}
)

View File

@@ -1,187 +0,0 @@
Theme (
styles: {
"button_action": (
base: "button",
properties: {
//"background": "transparent",
"border_radius": 3,
"h_align": "center",
"v_align": "center",
},
),
"button_menu": (
base: "button_single_content",
properties: {
"h_align": "end",
//"icon": "material_icons_font::MD_MENU",
},
),
"combo_box_form": (
base: "combo_box",
properties: {
"width": 200,
"height": 28,
},
),
"mail_label": (
base: "base",
properties: {
"h_align": "end",
"v_align": "center",
},
),
"mail_to": (
base: "combo_box_form",
properties: {
"h_align": "end",
},
),
"mail_cc": (
base: "combo_box_form",
properties: {
"h_align": "end",
},
),
"combo_box_popup": (
//base: "popup",
properties: {
//"height": 120,
"width": 240,
},
),
"configuration_form": (
base: "container",
properties: {
"margin": 4,
},
),
"container_action": (
base: "container_form",
properties: {
"border_width": 1,
"padding": {
"left": 14,
"top": 0,
"right": 14,
"bottom": 0,
},
"h_align": "center",
},
),
"container_form": (
base: "container",
properties: {
"padding": 14,
"border_brush": "$CONTAINER_BORDER",
"border_radius": 0,
"border_width": 1,
"min_height": 330,
},
),
"container_mail": (
base: "container_form",
properties: {
"border_width": 0,
"padding": {
"left": 14,
"top": 0,
"right": 14,
"bottom": 14,
}
},
),
"container_progress": (
base: "container",
properties: {
"border_brush": "$CONTAINER_BORDER",
"h_align": "center",
"padding": 14,
"v_align": "center",
},
),
"header_bar": (
base: "header",
properties: {
//"h_align": "center",
//"v_align": "center",
"min_height": 32,
//"padding": 14,
}
),
"header_text": (
base: "header",
properties: {
"h_align": "center",
"v_align": "center",
}
),
"popup_form": (
//base: "popup",
properties: {
"background": "#FFFFFF",
"border_brush": "#0000FF",
"border_radius": 3,
"border_width": 2,
"padding": 4,
},
),
"popup_menu": (
//base: "popup",
properties: {
"width": 300,
"hight": 200,
"border_radius": 0,
"border_width": 1,
"h_align": "center",
},
),
"popup_progress": (
base: "popup",
properties: {
"padding": 4,
},
),
"stack_action": (
//base: "stack",
properties: {
//"min_height": 50,
"orientation": "Horizontal",
"spacing": 50,
},
),
"stack_progress": (
base: "container",
properties: {
"spacing": 10,
},
),
"ticket_data_form_label": (
base: "container_form",
properties: {
"padding": 1,
"h_align": "end",
"v_align": "center",
"margin": {
"left": 0,
"top": 0,
"right": 0,
"bottom": 0,
},
"min_size": 300,
"max_size": 400,
},
),
"ticket_data_form_input": (
base: "ticket_data_form_label",
properties: {
"h_align": "start",
},
),
"text_block_progress": (
base: "small_text",
properties: {
"background": "$PROGRESS_BAR_BACKGROUND",
},
),
}
)

View File

@@ -1,165 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
// Component Values (Properties)
pub static PROP_ADVOTRACKER: &str = "advotracker";
pub static PROP_MAIL_CC_1: &str = "info@hiedemann.de";
pub static PROP_MAIL_CC_2: &str = "service@hiedemann.de";
pub static PROP_MAIL_BCC_1: &str = "Networkx Support <support@networkx.de>";
pub static PROP_MAIL_BCC_2: &str = "knoche@hiedemann.de";
pub static PROP_MAIL_FROM: &str = "Kanzlei Hiedemann <info@heidemann.de>";
pub static PROP_MAIL_REPLY: &str = "Kanzlei Hiedemann <info@heidemann.de>";
pub static PROP_MAIL_SUBJECT: &str = "ZMB Allianz - neues Mandat";
pub static PROP_MAIL_TO_1: &str = "allianz@ponschab-partner.com";
pub static PROP_MAIL_TO_2: &str = "kontakt@chevalier.law";
pub static PROP_MAIL_TO_3: &str = "kontakt@metamedlaw.de";
pub static PROP_MAIL_TO_4: &str = "sekretariat@m2-mediation.de";
pub static PROP_POLICY_CHECK: &str = "policy_check";
pub static PROP_POLICY_PROGRESS_COUNT: &str = "policy_progress_count";
pub static PROP_POLICY_DATA_LIST: &str = "policy_data_list";
pub static PROP_POLICY_DATA_COUNT: &str = "policy_data_count";
pub static PROP_POLICY_LIST: &str = "policy_list";
pub static PROP_POLICY_LIST_COUNT: &str = "policy_list_count";
// Styles (RON based theme system)
pub static STYLE_BOTTOM_BAR: &str = "bottom_bar";
pub static STYLE_BUTTON_MENU: &str = "button_menu";
pub static STYLE_BUTTON_ACTION: &str = "button_action";
pub static STYLE_CONTAINER_ACTION: &str = "container_action";
pub static STYLE_CONTAINER_MAIL: &str = "container_mail";
pub static STYLE_HEADER_BAR: &str = "header_bar";
pub static STYLE_HEADER_TEXT: &str = "header_text";
pub static STYLE_SEPARATOR: &str = "separator";
pub static STYLE_MAIL_LABEL: &str = "mail_label";
pub static STYLE_MAIL_TO: &str = "mail_to";
pub static STYLE_MAIL_CC: &str = "mail_cc";
pub static STYLE_MENU: &str = "menu";
pub static STYLE_STACK_ACTION: &str = "stack_action";
pub static STYLE_STACK_MENU: &str = "stack_menu";
// Widget IDs (DCES: Entity[id] => [Component1, .. , Component<n>] -> data or state)
pub static ID_CONFIGURATION_VIEW: &str = "Configuration";
pub static ID_CONFIGURATION_FORM: &str = "configuration_form";
pub static ID_CONFIGURATION_HEADER: &str = "configuration_header";
pub static ID_CONFIGURATION_LABEL_CONFIG_FILE: &str = "configuration_label_config_file";
pub static ID_CONFIGURATION_CONFIG_FILE: &str = "configuration_config_file";
pub static ID_CONFIGURATION_LABEL_LANGUAGE_ID: &str = "configuration_label_language_id";
pub static ID_CONFIGURATION_LANGUAGE_ID: &str = "configuration_language_id";
pub static ID_LOCALIZATION_VIEW: &str = "Localization";
pub static ID_LOCALIZATION_FORM: &str = "localization_form";
pub static ID_LOCALIZATION_HEADER: &str = "localization_header";
pub static ID_LOCALIZATION_LANGUAGES: &str = "localization_languages";
pub static ID_LOCALIZATION_LABEL_LANGUAGE_NAME: &str = "localization_label_language_name";
pub static ID_LOCALIZATION_LANGUAGE_NAME: &str = "localization_language_name";
pub static ID_MAIN_GRID: &str = "main_grid";
pub static ID_MAIN_TABWIDGET: &str = "main_tabwidget";
pub static ID_MAIN_BUTTON_MENU: &str = "main_button_menu";
pub static ID_MENU_VIEW: &str = "menu_view";
pub static ID_MENU_POPUP: &str = "menu_popup";
pub static ID_MENU_STACK: &str = "menu_stack";
pub static ID_MENU_BOTTOM_BAR: &str = "menu_bottom_bar";
pub static ID_MENU_BUTTON: &str = "menu_button";
pub static ID_MENU_BUTTON_MENU: &str = "menu_button_menu";
pub static ID_MENU_GRID: &str = "menu_grid";
pub static ID_MENU_HEADER: &str = "menu_header";
pub static ID_MENU_HEADER_BAR: &str = "menu_header_bar";
pub static ID_MENU_LABEL_ACCOUNT: &str = "menu_label_account";
pub static ID_MENU_LABEL_QUIT: &str = "menu_label_quit";
pub static ID_MENU_LABEL_TOGGLE_THEME: &str = "menu_label_toggle_theme";
pub static ID_MENU_SHORTCUT_QUIT: &str = "menu_shortcut_quit";
pub static ID_MENU_TOGGLE_THEME: &str = "menu_toggle_theme";
pub static ID_POLICY_CHECK_VIEW: &str = "policy_check_view";
pub static ID_POLICY_CHECK_ACTION_BUTTON_CREATE: &str = "policy_check_action_button_create";
pub static ID_POLICY_CHECK_ACTION_GRID: &str = "policy_check_action_grid";
pub static ID_POLICY_CHECK_BOTTOM_BAR: &str = "policy_check_bottom_bar";
pub static ID_POLICY_CHECK_BUTTON_RESULT: &str = "policy_check_button_result";
pub static ID_POLICY_CHECK_BUTTON_MENU: &str = "policy_check_button_menu";
pub static ID_POLICY_CHECK_DATA_COUNT_BLOCK: &str = "policy_check_data_count_block";
pub static ID_POLICY_CHECK_FORM: &str = "policy_check_form";
pub static ID_POLICY_CHECK_HEADER: &str = "policy_check_header";
pub static ID_POLICY_CHECK_HEADER_BAR: &str = "policy_check_header_bar";
pub static ID_POLICY_CHECK_HINT: &str = "policy_check_hint";
pub static ID_POLICY_CHECK_ITEMS_WIDGET: &str = "policy_check_items_widget";
pub static ID_POLICY_CHECK_LABEL_HINT: &str = "policy_check_label_hint";
pub static ID_POLICY_CHECK_LABEL_MENU: &str = "policy_check_label_menu";
pub static ID_POLICY_CHECK_LABEL_POLICY_NUMBER: &str = "policy_check_label_policy_number";
pub static ID_POLICY_CHECK_LABEL_RESULT: &str = "policy_check_label_result";
pub static ID_POLICY_CHECK_POLICY_CODE: &str = "policy_check_policy_code";
pub static ID_POLICY_CHECK_POLICY_NUMBER: &str = "policy_number";
pub static ID_POLICY_CHECK_POPUP_PROGRESS: &str = "policy_check_popup_progress";
pub static ID_POLICY_CHECK_PROGRESS_BAR: &str = "policy_check_progress_bar";
pub static ID_POLICY_CHECK_PROGRESS_TIME: &str = "policy_check_progress_time";
pub static ID_POLICY_CHECK_PROGRESS_TEXT: &str = "policy_check_progress_text";
pub static ID_POLICY_CHECK_RESULT: &str = "policy_check_result";
pub static ID_POLICY_CHECK_WIDGET: &str = "policy_check_widget";
pub static ID_POLICY_DATA_ADD_BUTTON: &str = "policy_data_add_button";
pub static ID_POLICY_DATA_COUNT: &str = "policy_data_count";
pub static ID_POLICY_DATA_LABEL: &str = "policy_data_label";
pub static ID_POLICY_DATA_ITEMS_WIDGET: &str = "policy_data_items_widget";
pub static ID_POLICY_DATA_DATE_INSERTED: &str = "policy_data_date_inserted";
pub static ID_POLICY_DATA_DION: &str = "policy_data_dion";
pub static ID_POLICY_DATA_POLICY_CODE: &str = "policy_data_policy_code";
pub static ID_POLICY_DATA_POLICY_NUMBER: &str = "policy_data_policy_number";
pub static ID_POLICY_DATA_STACK: &str = "policy_data_stack";
pub static ID_POLICY_DATA_STATUS: &str = "policy_data_status";
pub static ID_POLICY_DATA_LIST_NAME: &str = "policy_data_list_name";
pub static ID_POLICY_LIST_ADD_BUTTON: &str = "policy_list_add_button";
pub static ID_POLICY_LIST_ITEMS_WIDGET: &str = "policy_list_items_widget";
pub static ID_POLICY_LIST_TEXT_BOX: &str = "policy_list_text_box";
pub static ID_TICKET_DATA_ACTION_BUTTON_CLEAR: &str = "ticket_data_action_button_clear";
pub static ID_TICKET_DATA_ACTION_BUTTON_SEND: &str = "ticket_data_action_button_send";
pub static ID_TICKET_DATA_ACTION_GRID: &str = "ticket_data_action_grid";
pub static ID_TICKET_DATA_BOTTOM_BAR: &str = "ticket_data_bottom_bar";
pub static ID_TICKET_DATA_BUTTON_MENU: &str = "ticket_data_button_menu";
pub static ID_TICKET_DATA_BUTTON_RESULT: &str = "ticket_data_button_result";
pub static ID_TICKET_DATA_CALLBACK_DATE: &str = "ticket_data_label_callback_date";
pub static ID_TICKET_DATA_CALLBACK_NUMBER: &str = "ticket_data_label_callback_number";
pub static ID_TICKET_DATA_COMBO_BOX_MAIL_CC: &str = "ticket_data_combo_box_mail_cc";
pub static ID_TICKET_DATA_COMBO_BOX_MAIL_TO: &str = "ticket_data_combo_box_mail_to";
pub static ID_TICKET_DATA_CONTAINER_MAIL: &str = "ticket_data_container_mail";
pub static ID_TICKET_DATA_COUNT_BLOCK: &str = "ticket_data_count_block";
pub static ID_TICKET_DATA_DEDUCTIBLE: &str = "ticket_data_deductible";
pub static ID_TICKET_DATA_FORM: &str = "ticket_data_form";
pub static ID_TICKET_DATA_FORM_GRID: &str = "ticket_data_form_grid";
pub static ID_TICKET_DATA_GRID: &str = "ticket_data_grid";
pub static ID_TICKET_DATA_GRID_MAIL: &str = "ticket_data_grid_mail";
pub static ID_TICKET_DATA_HARM_TYPE: &str = "ticket_data_harm_type";
pub static ID_TICKET_DATA_HEADER_BAR: &str = "ticket_data_header_bar";
pub static ID_TICKET_DATA_HEADER: &str = "ticket_data_header";
pub static ID_TICKET_DATA_HINT: &str = "ticket_data_hint";
pub static ID_TICKET_DATA_ITEMS_WIDGET: &str = "ticket_data_items_widget";
pub static ID_TICKET_DATA_IVR_COMMENT: &str = "ticket_data_ivr_comment";
pub static ID_TICKET_DATA_LABEL_CALLBACK_DATE: &str = "ticket_data_label_callback_data";
pub static ID_TICKET_DATA_LABEL_CALLBACK_NUMBER: &str = "ticket_data_label_callback_number";
pub static ID_TICKET_DATA_LABEL_DEDUCTIBLE: &str = "ticket_data_label_deductible";
pub static ID_TICKET_DATA_LABEL_HARM_TYPE: &str = "ticket_data_label_harm_type";
pub static ID_TICKET_DATA_LABEL_HINT: &str = "ticket_data_label_hint";
pub static ID_TICKET_DATA_LABEL_IVR_COMMENT: &str = "ticket_data_label_ivr_comment";
pub static ID_TICKET_DATA_LABEL_MAIL_CC: &str = "ticket_data_label_mail_cc";
pub static ID_TICKET_DATA_LABEL_MAIL_TO: &str = "ticket_data_label_mail_to";
pub static ID_TICKET_DATA_LABEL_MENU: &str = "ticket_data_label_menu";
pub static ID_TICKET_DATA_LABEL_POLICY_CODE: &str = "ticket_data_label_policy_code";
pub static ID_TICKET_DATA_LABEL_POLICY_HOLDER: &str = "ticket_data_label_policy_holder";
pub static ID_TICKET_DATA_LOGO_BAR: &str = "ticket_data_logo_bar";
pub static ID_TICKET_DATA_MAIL_CC: &str = "ticket_data_mail_cc";
pub static ID_TICKET_DATA_MAIL_TO: &str = "ticket_data_mail_to";
pub static ID_TICKET_DATA_POLICY_CODE: &str = "ticket_data_policy_code";
pub static ID_TICKET_DATA_POLICY_HOLDER: &str = "ticket_data_policy_holder";
pub static ID_TICKET_DATA_RESULT: &str = "ticket_data_result";
pub static ID_TICKET_DATA_VIEW: &str = "ticket_data_view";
pub static ID_TICKET_DATA_WIDGET: &str = "ticket_data_widget";

View File

@@ -1,40 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: 0BSD, MIT
*/
//#![warn(missing_docs, rust_2018_idioms, rust_2018_compatibility)]
#![warn(rust_2018_idioms, rust_2018_compatibility)]
//! advotracker
//! Supports lawyers to capture relevant data encountered during an
//! online legal advice.
//! This is the frontend componet that communicates to the backend `advotrackerd`.
//!
//! The crate is called `advotracker` and you can depend on it via cargo:
//!
//! ```ini
//! [dependencies]
//! advotracker = { version = "~0.1" }
//! ```
//!
//! WIP: provide a workflow image
//!
// /// The client specific services
// pub mod clients;
/// provides data definitions
pub mod data;
/// provides orbtk widgets (handling views and states)
pub mod widgets;
/// provides services
pub mod services;
// /// Provide test data
// #[cfg!Test]
// pub mod data;

View File

@@ -1,668 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use locales::t;
use orbtk::prelude::*;
use serde::Deserialize;
use std::process;
use std::collections::HashMap;
use std::time::{Duration, SystemTime};
use tracing::{error, info, trace};
use crate::{
data::{
structures::{PolicyCode, PolicyDataList, PolicyList},
constants::*,
},
//services::imports::allianzdirectcall::import,
services::imports::allianzdirectcall,
widgets::global_state::GlobalState,
//widgets::menu::menu_view::MenuView,
//widgets::policycheck::policycheck_view::PolicycheckView,
//widgets::ticketdata::ticketdata_state::TicketdataAction,
};
/// Enumeration of valid `action variants` that need to be handled as
/// state changes for the `PolicycheckView` widget.
#[derive(Debug, Clone)]
pub enum PolicycheckAction {
ClearEntry(Entity),
ChangeTheme(),
SendPolicynumber(),
InputTextChanged(Entity),
ImportData,
NewTicket,
ParsePolicyNumber(Entity),
RemoveFocus(Entity),
RemovePopup(Entity),
ResetProgress,
GetProgress,
SetProgress(f64),
SetProgressPopup(Entity),
SetToggleTheme(Entity),
SetEntry(Entity),
SetVisibility(Entity),
TextChanged(Entity, usize),
UpdatePolicyCode,
UpdateProgress(f64)
}
/// 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,
}
/// Valid `structures` that are handled inside the state of the `Policycheck` widget.
#[derive(AsAny, Default)]
pub struct PolicycheckState {
actions: Vec<PolicycheckAction>,
button_menu: Entity,
duration: Duration,
label_result: Entity,
lang: String,
policy_data_count: u64,
//policy_number: Entity,
policy_numbers: HashMap<u64, PolicyCode>,
progress_bar: Entity,
progress_count: f64,
progress_popup: Entity,
// target that recieves messages
target: Entity,
ticketdata: Entity
}
impl GlobalState for PolicycheckState {}
/// Method definitions, that react on any given state change inside the `Policycheck` widget.
impl PolicycheckState {
/// Create a hashmap (key: policy number, value: policy type).
pub fn create_hashmap(&mut self, _ctx: &mut Context<'_>)
-> Result<(), Box<dyn std::error::Error>> {
trace!(target: "advotracker", create_hashmap = "started");
let policy_list = PolicyList::new("policy list");
trace!(target: "advotracker", policy_list = ?policy_list);
// create vector to hold imported data
let res = t!("policy.string.label_policy_data", self.lang);
let mut policy_data = PolicyDataList::new(res);
trace!(target: "advotracker", policy_data = ?policy_data);
let mut policy_numbers : HashMap<u64, PolicyCode> = HashMap::new();
// Wip: use cli parameter stored in viperus ...
//let mut csv_import_path = v.get::<String>("import_file").unwrap();
let mut csv_import_path = String::from("POLLFNR_WOECHENTLICH.txt");
match allianzdirectcall::import(&mut csv_import_path, &mut policy_data,
&mut policy_numbers, &mut self.policy_data_count,
&self.lang) {
Ok((count, duration)) => {
self.policy_data_count = count;
self.duration = duration;
trace!(target: "advotracker", csv_import_path = ?csv_import_path,
policy_data_count = ?&self.policy_data_count,
duration = ?&self.duration);
}
Err(err) => {
error!("error running CSV-Import: {}", err);
process::exit(1);
}
};
self.policy_numbers = policy_numbers;
trace!(target: "advotracker", create_hashmap = "finished");
Ok(())
}
/// Clear text in text box.
pub fn clear_entry(&mut self, _text_box: Entity, ctx: &mut Context<'_>) {
TextBox::text_set(&mut ctx.widget(), String::from(""));
}
/// Import policy numbers into hashmap
fn import_data(&mut self, ctx: &mut Context<'_>)
-> Result<(), Box<dyn std::error::Error>> {
// WIP: for now, only import once per session
if self.policy_data_count == 0 {
TextBlock::enabled_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_CODE), true);
if self.policy_numbers.is_empty() {
// initialize popup widget
self.set_popup_progress(ctx);
self.progress_count += 0.33;
self.update_progress_bar(ctx);
for _ in 1..4 {
self.progress_count += 0.33;
self.update_progress_bar(ctx);
ctx.send_message(PolicycheckAction::UpdateProgress(self.progress_count), self.progress_popup);
}
// importing policy code elements from csv-file
match self.create_hashmap(ctx) {
Ok(()) => {
let res = t!("policy.hashmap.success", self.lang);
info!("hashmap has: {:?} entries", self.policy_data_count);
trace!(target: "advotracker",
hashmap_status = ?res,
hashmap_entries = ?self.policy_data_count);
self.progress_count = 1.;
self.update_progress_bar(ctx);
}
_ => {
let res = t!("policy.hashmap.failed", self.lang);
error!("{:?}", res);
trace!(target: "advotracker", hashmap_status = ?res);
}
}
}
} else {
trace!(target: "advotracker",
hashmap_status = "consume",
hashmap_entries = ?self.policy_data_count);
}
Ok(())
}
/// Create new ticket
pub fn new_ticket(&mut self, ctx: &mut Context<'_>) {
println!("WIP: new ticket.");
self(ticketdata_view.0);
//ctx.widget().get_mut::<TicketdataView>(0).
//ctx.get_widget(self.ticketdata_view);
}
/// Parse validity of the given policy number.
pub fn parse_entry(&mut self, policy_check_policy_number: Entity,
ctx: &mut Context<'_>) {
trace!(target: "advotracker", parse_entry = "started");
let policy_number_string = TextBox::text_clone(&ctx.get_widget(policy_check_policy_number));
let policy_number_length = policy_number_string.len();
if self.policy_data_count == 0 {
// Load data into hashmap
match self.import_data(ctx) {
Ok(()) => {
trace!(target: "advotracker", policycheck_state = "init", import_data = "success");
Stack::visibility_set(&mut ctx.child(ID_POLICY_DATA_STACK), Visibility::Visible);
let policy_data_count_string = format!("{:?}", &self.policy_data_count);
TextBlock::text_set(&mut ctx.child(ID_POLICY_DATA_COUNT), String::from(&policy_data_count_string));
},
Err(e) => trace!(target: "advotracker", policycheck_state = "init", import_data = ?e),
}
}
trace!(target: "advotracker", state = "parsing", policy_number = ?policy_number_string);
// Parse policy code: "AS-123456789"
// DION VERS POLLFNR
// 1 AS 1515735810
Button::background_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), String::from("transparent"));
if policy_number_length == 10 {
// cast policy_number_sting to <u64>
match policy_number_string.parse::<u64>() {
Ok(p) => {
TextBlock::text_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_CODE), String::from(""));
// match hashmap's key
match self.policy_numbers.get(&p) {
Some(policy_code) => {
// matching key, get associated value
trace!(target: "advotracker", state = "success",
policy_number = ?p, policy_code = ?policy_code);
let string_result = format!("1-{:?}-{}",
policy_code, p);
TextBlock::text_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_CODE), string_result);
TextBox::foreground_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_NUMBER), String::from("#008000"));
Button::icon_brush_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), String::from("#008000"));
Button::foreground_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), String::from("#008000"));
Button::icon_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), material_icons_font::MD_CHECK);
Button::visibility_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_RESULT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_CODE), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_HINT), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_HINT), Visibility::Collapsed);
}
_ => {
// no matching key
let res = t!("policy.validation.failed", self.lang);
trace!(target: "advotracker", state = ?res, policy_number = ?p);
TextBox::foreground_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_NUMBER), String::from("#FF0000"));
TextBlock::text_set(&mut ctx.child(ID_POLICY_CHECK_HINT), String::from("The given policy number is invalid"));
Button::icon_brush_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), String::from("#FF0000"));
Button::foreground_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), String::from("#FF0000"));
Button::icon_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), material_icons_font::MD_CLEAR);
Button::visibility_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_RESULT), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_CODE), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_HINT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_HINT), Visibility::Visible);
}
}
},
Err(e) => {
trace!(target: "advotracker", state = "error", error_type = "invalid type", error = ?e);
TextBox::foreground_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_NUMBER), String::from("#FF0000"));
TextBlock::text_set(&mut ctx.child(ID_POLICY_CHECK_HINT), String::from("Only numbers are valid"));
Button::icon_brush_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), String::from("#FF0000"));
Button::foreground_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), String::from("#FF0000"));
Button::icon_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), material_icons_font::MD_CLEAR);
Button::visibility_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_RESULT), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_CODE), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_HINT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_HINT), Visibility::Visible);
}
}
}
if policy_number_length < 10 {
let res = t!("policy.validation.failed", self.lang);
trace!(target: "advotracker", state = ?res, reason = "number to short");
TextBox::foreground_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_NUMBER), String::from("#FF0000"));
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_HINT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_HINT), Visibility::Visible);
TextBlock::text_set(&mut ctx.child(ID_POLICY_CHECK_HINT), String::from("Policy number is to short"));
Button::icon_brush_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), String::from("#FF0000"));
Button::foreground_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), String::from("#FF0000"));
Button::icon_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), material_icons_font::MD_CLEAR);
Button::visibility_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_RESULT), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_CODE), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_HINT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_HINT), Visibility::Visible);
}
if policy_number_length > 10 {
let res = t!("policy.validation.failed", self.lang);
trace!(target: "advotracker", state = ?res, reason = "number to long");
TextBox::foreground_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_NUMBER), String::from("#FF0000"));
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_HINT), Visibility::Visible);
TextBlock::text_set(&mut ctx.child(ID_POLICY_CHECK_HINT), String::from("Policy number is to long"));
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_HINT), Visibility::Visible);
Button::icon_brush_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), String::from("#FF0000"));
Button::foreground_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), String::from("#FF0000"));
Button::icon_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), material_icons_font::MD_CLEAR);
Button::visibility_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_RESULT), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_CODE), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_HINT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_HINT), Visibility::Visible);
}
trace!(target: "advotracker", parse_entry = "finished");
}
/// parse message 'ParseEntry'
pub fn parse_policy_number(&mut self, entity: Entity) {
self.actions.push(PolicycheckAction::ParsePolicyNumber(entity));
}
/// Remove the popup box
fn remove_popup(&mut self, id: Entity, ctx: &mut Context<'_>) {
ctx.remove_child(self.progress_popup);
println!("Popup {:?} removed !", id);
}
// /// If TextBox 'policy_check_policy_number' is empty, disable button "clear"
// /// otherwise enabled it.
// fn set_policy_check_clear(&mut self, policy_check_policy_number: Entity, ctx: &mut Context<'_>) {
// button(&self, policy_check_policy_number: Entity, ctx: &mut Context<' >) {
// if ctx.get_widget(clear_button).get::<String>("policy_check_policy_number").is_empty() {
// ctx.get_widget(self.policy_check_clear_button).set("enabled", false);
// } else {
// ctx.get_widget(self.policy_check_clear_button).set("enabled", true);
// }
// ctx.get_widget(self.policy_check_policy_number).update_theme_by_state(true);
// }
/// Sending message 'UpdatePolicyCode'
pub fn send_message_update_policy_code(&mut self, entity: Entity) {
println!("WIP: send_message_update_policy_code = {:?}", entity);
//self.actions.push(PolicycheckAction::UpdatePolicyNumber("4711".to_string()));
//let policy_number = (ctx.get_child(entity).get::<String>("text"));
//println!("WIP: poliy_number = {:?}", policy_number);
//self.actions.push(PolicycheckAction::UpdatePolicyNumber(self.policy_number));
}
/// Change status of given text box to edit mode.
fn set_entry(&mut self, text_box: Entity, ctx: &mut Context<'_>) {
if ctx.get_widget(text_box).get::<String16>("text").is_empty() {
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_RESULT), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_CODE), Visibility::Collapsed);
} else {
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_RESULT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_CODE), Visibility::Visible);
}
}
/// Set a progress popup that updates the import status in a progress bar
fn set_popup_progress(&mut self, ctx: &mut Context<'_>) {
// create a stack as a child of entity "ID_POLICY_CHECK_POLICY_NUMBER"
let stack = ctx
.entity_of_child(ID_POLICY_CHECK_POLICY_NUMBER)
.expect("PolicycheckState: Can't find entity of resource 'ID_POLICY_CHECK_POLICY_NUMBER'.");
let current_entity = ctx.entity();
let build_context = &mut ctx.build_context();
// create the progress_popup widget
self.progress_popup = create_popup_progress(current_entity, build_context);
info!("set_popup_progress: New entity 'popup_progress' {:?} created", self.progress_popup);
// append the stack inside the progress_popup
build_context.append_child(stack, self.progress_popup);
// make sure we have a progress bar
self.progress_bar = ctx
.entity_of_child(ID_POLICY_CHECK_PROGRESS_BAR)
.expect("PolicycheckState.init: Can't find entity of resource 'ID_POLICY_CHECK_PROGRESS_BAR'.");
info!("set_popup_progress: New entity 'progress_bar' created: {:?}", self.progress_bar);
}
/// Change visibility of the result label.
fn _set_visibility(&self, entity: Entity, ctx: &mut Context<'_>) {
if ctx.get_widget(entity).get::<String16>("text").is_empty() {
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_RESULT), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), Visibility::Collapsed);
} else {
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_RESULT), Visibility::Visible);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_BUTTON_RESULT), Visibility::Visible);
}
}
/// Update count of elements in the policy data list.
fn _update_data_count(&self, ctx: &mut Context<'_>) {
let data_list_count = ctx.widget().get::<PolicyDataList>(PROP_POLICY_DATA_LIST).len();
ctx.widget().set(PROP_POLICY_DATA_COUNT, data_list_count);
}
fn update_progress_bar(&self, ctx: &mut Context<'_>) {
let res = t!("policy.string.progress_time", self.lang);
let string_duration = format!("{}: {:?}", res, self.duration);
TextBlock::text_set(&mut ctx.child(ID_POLICY_CHECK_PROGRESS_TIME), string_duration);
let mut progress_bar = ctx.child(ID_POLICY_CHECK_PROGRESS_BAR);
progress_bar.set::<f64>("val", self.progress_count);
}
/// Update the policy code policy data list.
fn update_policy_code(&self, _ctx: &mut Context<'_>) {
println!("update internal: policy_code");
//let policy_code = ctx.widget().get::<PolicycheckState>(ID_POLICY_CHECK_POLICY_CODE);
//ctx.widget().set(PROP_POLICY_DATA_COUNT, policy_code);
}
}
/// Supported methods handled inside the `PolicycheckState`
impl State for PolicycheckState {
/// Initialize the state of widgets inside `PolicycheckState`
fn init(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
let time_start= SystemTime::now();
trace!(target: "advotracker", policycheck_state = "init", status = "started");
// Get language from environment
self.lang = PolicycheckState::get_lang();
// Initialize required entities
self.button_menu = ctx
.entity_of_child(ID_POLICY_CHECK_BUTTON_MENU)
.expect("PolicycheckState::init: Can't find resource entity 'ID_POLICY_CHECK_BUTTON_MENU'.");
self.label_result = ctx
.entity_of_child(ID_POLICY_CHECK_LABEL_RESULT)
.expect("PolicycheckState::init: Can't find resource entity 'ID_POLICY_CHECK_LABEL_RESULT'.");
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_RESULT), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_POLICY_CODE), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_HINT), Visibility::Collapsed);
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_HINT), Visibility::Collapsed);
//self.policy_number = Entity::from(ctx.widget().try_clone::<u32>(ID_POLICY_CHECK_POLICY_NUMBER)
// .expect("PolicycheckState::init(): Can't find resource entity 'ID_POLICY_CHECK_POLICY_NUMBER'."));
self.target = Entity::from(ctx.widget().try_clone::<u32>("target")
.expect("PolicycheckState::init(): Can't find resource entity 'target'."));
//self.ticketdata_view = (*ctx.widget().get::<u32>("ticketdata_view")).into();
//self.ticketdata = Entity::from(ctx.widget().try_clone::<u32>(ID_TICKET_DATA_VIEW)
// .expect("PolicycheckState::init(): Can't find resource entity 'ticketdata'."));
// // 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
// // app directory name. The directory location is OS dependant
// // (Windows: AppData, Unix: XDG_CONFIG_HOME, MacOS: $HOME/Library/Preferences).
// // The filename is taken from the propertey PROP_ADVOTRACKER (default: 'advotracker'.ron).
// if let Ok(policy_data) = registry
// .get::<Settings>("settings")
// .load::<PolicyDataList>(PROP_ADVOTRACKER)
// {
// ctx.widget().set(PROP_ADVOTRACKER, policy_data);
// }
let time_end = SystemTime::now();
let duration = time_end.duration_since(time_start);
trace!(target: "advotracker", policycheck_state = "init", status = "finished", duration = ?duration);
}
/// Handle messages for `PolicycheckState`.
fn messages(
&mut self,
mut messages: MessageReader,
_registry: &mut Registry,
ctx: &mut Context<'_>,
) {
for message in messages.read::<PolicycheckAction>() {
match message {
PolicycheckAction::UpdateProgress(increment) => {
let old_width = ProgressBar::val_clone(&ctx.child(ID_POLICY_CHECK_PROGRESS_BAR));
let new_width = old_width + increment;
// Set the ProgressBar's val property to the calculated percentage
// (whereas 0.0 means 0%, and 1.0 means 100%)
if new_width <= 1. {
ProgressBar::val_set(&mut ctx.child(ID_POLICY_CHECK_PROGRESS_BAR), new_width);
} else {
ProgressBar::val_set(&mut ctx.child(ID_POLICY_CHECK_PROGRESS_BAR), 1.);
}
}
PolicycheckAction::UpdatePolicyCode => {
self.update_policy_code(ctx);
}
PolicycheckAction::NewTicket => {
self.new_ticket(ctx);
}
_ => { println!("PolicycheckAction: action not implemented!"); }
}
}
}
/// Update the state of widgets inside the `Policycheck` view.
fn update(&mut self, _registry: &mut Registry, ctx: &mut Context<'_>) {
// // clear focus on focus moved
// if self.last_focused != ctx.window().get::<Global>("global").focused_widget {
// if let Some(last_focused) = self.last_focused {
// ctx.get_widget(last_focused).set("focused", false);
// // widget is unvisible, but takes space to be considered
// ctx.get_widget(last_focused)
// .set("visibility", Visibility::Collapsed);
// }
//}
// Create `actions`, a drained iterator (".." => full range that clears the vector)
let actions: Vec<PolicycheckAction> = self.actions.drain(..).collect();
for action in actions {
match action {
PolicycheckAction::ClearEntry(policy_check_policy_number) => {
ctx.get_widget(policy_check_policy_number).set("enabled", false);
}
PolicycheckAction::InputTextChanged(entity) => {
println!("entry changed: {}", TextBox::text_clone(&ctx.get_widget(entity)));
}
PolicycheckAction::ImportData => {
match self.import_data(ctx) {
Ok(()) => {
trace!(target: "advotracker", import_data = "success");
}
_ => {
error!("Importing data failed!");
trace!(target: "advotracker", import_data = "failed");
}
}
}
PolicycheckAction::NewTicket => {
self.new_ticket(ctx);
}
PolicycheckAction::ParsePolicyNumber(text_box) => {
self.parse_entry(text_box, ctx);
}
PolicycheckAction::RemoveFocus(policy_check_policy_number) => {
ctx.get_widget(policy_check_policy_number).set("enabled", false);
//ctx.EventAdapter(FocusEvent::RemoveFocus(policy_check_policy_number));
}
PolicycheckAction::RemovePopup(entity) => {
self.remove_popup(entity, ctx);
}
PolicycheckAction::ResetProgress => {
ProgressBar::val_set(&mut ctx.child(ID_POLICY_CHECK_PROGRESS_BAR), 0.);
}
PolicycheckAction::SetEntry(policy_check_policy_number) => {
//self.last_focused = Some();
self.set_entry(policy_check_policy_number, ctx);
}
PolicycheckAction::SetProgress(value) => {
if value >= 0. || value <= 1. {
ProgressBar::val_set(&mut ctx.child(ID_POLICY_CHECK_PROGRESS_BAR), value);
} else {
ProgressBar::val_set(&mut ctx.child(ID_POLICY_CHECK_PROGRESS_BAR), 0.);
} }
PolicycheckAction::SetProgressPopup(_entity) => {
self.set_popup_progress(ctx);
}
PolicycheckAction::SetVisibility(_entity) => {
TextBlock::visibility_set(&mut ctx.child(ID_POLICY_CHECK_LABEL_RESULT), Visibility::Collapsed);
}
PolicycheckAction::TextChanged(entity, _index) => {
self.set_entry(entity, ctx);
}
PolicycheckAction::UpdatePolicyCode => {
self.update_policy_code(ctx);
//info!("Message send: 'PolicycheckAction::UpdatePolicyNumber({:?}) -> {:?}'", policy_number, self.target);
//let policy_number = (&mut ctx.get_widget(entity).get::<String>("text"));
//let policy_number = ctx.get_widget(ID_POLICY_CHECK_POLICY_NUMBER).get::<text>("text");
//ctx.send_message(PolicycheckAction::UpdatePolicyCode("AS-1-4711".to_string()), self.target);
//ctx.send_message(PolicycheckAction::UpdatePolicyCode, self.target);
//let mut widget_container : WidgetContainer = ctx.widget();
//widget_container.get::<String16>("text");
//let polnum: TextBox = TextBox::get(ctx.child(ID_POLICY_CHECK_POLICY_NUMBER));
//println!("Policy number: {:?}", polnum);
//let policy_number = ctx.get_widget(self.policy_check_policy_number);
//let policy_number2 = TextBox::text_clone(&ctx.get_widget(ID_POLICY_CHECK_POLICY_NUMBER));
//let policy_number_string = ctx.get_widget(entity).get::<String16>("text").is_empty();
//let policy_number = TextBox::text_clone(&mut ctx.child(ID_POLICY_CHECK_POLICY_NUMBER));
//ctx.send_message(PolicycheckAction::UpdatePolicyNumber(policy_check_policy_number), self.target);
//info!("Message send: 'PolicycheckAction::UpdatePolicyNumber({:?}) -> {:?}'", policy_check_policy_number, self.target);
}
_ => (),
}
}
}
// /// Update the view after the layout is rendered.
// fn update_post_layout(&mut self, _: &mut Registry, _ctx: &mut Context<'_>) {
// }
}
/// Create a progress popup with update status of an onging data import
fn create_popup_progress(id: Entity, ctx: &mut BuildContext<'_>) -> Entity {
Popup::new()
.id(ID_POLICY_CHECK_POPUP_PROGRESS)
.target(id.0)
.open(true)
.style("popup_progress")
.width(280)
.height(100)
.visibility(Visibility::Visible)
.on_click(move |_ctx, _| {
println!("create_popup_progress: on_click -> remove_popup(popup_progress)");
//ctx.get_mut::<PolicycheckState>(id)
// .set_action(PolicycheckAction::RemovePopup(id));
true
})
.child(
Container::new()
.style("container_progress")
.child(
Stack::new()
.style("stack_progress")
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_PROGRESS_TEXT)
.style("textblock_progress")
.text("Importing data")
.build(ctx)
)
.child(
ProgressBar::new()
.id(ID_POLICY_CHECK_PROGRESS_BAR)
.style("progress_bar")
.val(0)
//.width(250)
.build(ctx)
)
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_PROGRESS_TIME)
.style("textblock_progress")
.h_align("end")
.text("Processing time")
.build(ctx)
)
.build(ctx)
)
.build(ctx)
)
.build(ctx)
}

View File

@@ -1,328 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use orbtk::shell::event::Key;
use crate::{
data::{
constants::*,
structures::PolicyCheck,
},
//widgets::menu::menu_state::{MenuAction, MenuState},
widgets::policycheck::policycheck_state::{PolicycheckAction, PolicycheckState},
};
// Macro that initializes the widget structures/variables for the policy check view
widget!(
/// Dialog to enter a policy identifier/number.
/// This identifier is checked agains a map of valid policy codes.
// PolicycheckView<PolicycheckState>: KeyDownHandler {
PolicycheckView<PolicycheckState> {
// holds the language code
lang: String,
// provides a struct with `PolicyCheck` members
policy_check: PolicyCheck,
// holds number of imported data
policy_data_count: u32,
// holds the title string
policy_check_title: String,
// widget entity that will receive the message
target: u32
}
);
/// The template implementation of the policy check view
/// All GUI elements are styled using the "style" attribute referencing to a ron based css
impl Template for PolicycheckView {
//fn template(self, policycheck_view: Entity, ctx: &mut BuildContext<'_>) -> Self {
fn template(self, id: Entity, ctx: &mut BuildContext<'_>) -> Self {
let tenent_logo = Container::new()
.margin((16, 16, 0, 0))
.attach(Grid::column(0))
.v_align("center")
.child(
ImageWidget::new()
.image("assets/advotracker/hiedemann_logo.png")
.v_align("center")
.build(ctx),
)
.build(ctx);
let policy_check_bottom_bar = Container::new()
.id(ID_POLICY_CHECK_BOTTOM_BAR)
//.style(STYLE_BOTTOM_BAR)
.padding(14)
.attach(Grid::row(4))
.attach(Grid::column(1))
.attach(Grid::column_span(2))
.v_align("end")
.child(
Container::new()
.attach(Grid::column(1))
.h_align("end")
.v_align("end")
.child(
TextBlock::new()
.margin((0, 9, 48, 0))
.text("©Networkx GmbH")
.build(ctx)
)
.build(ctx),
)
.build(ctx);
let policy_check_button_menu = Button::new()
.id(ID_POLICY_CHECK_BUTTON_MENU)
.style("button_single_content")
.icon(material_icons_font::MD_MENU)
.attach(Grid::column(2))
//.min_size(16, 16)
.h_align("end")
.on_click(move |_ctx, _| {
println!("WIP: open menu popup from MenuView");
// ctx.get_mut::<MenuState>(id)
// .set_action(MenuAction::CreateMenu(ID_MENU_STACK));
true
})
.build(ctx);
let policy_check_button_result = Button::new()
.id(ID_POLICY_CHECK_BUTTON_RESULT)
.style("button_single_content")
.attach(Grid::row(0))
.attach(Grid::column(3))
.h_align("start")
.v_align("center")
.visibility(Visibility::Collapsed)
.enabled(false)
.build(ctx);
let policy_check_header_text = TextBlock::new()
.id(ID_POLICY_CHECK_HEADER)
.attach(Grid::column(0))
.style(STYLE_HEADER_TEXT)
.text("Validation policy number")
.build(ctx);
let policy_check_header_bar = Container::new()
.id(ID_POLICY_CHECK_HEADER_BAR)
.attach(Grid::row(0))
.attach(Grid::column_span(3))
.style(STYLE_HEADER_BAR)
.child(tenent_logo)
.child(policy_check_header_text)
.child(policy_check_button_menu)
.build(ctx);
let policy_check_policy_code = TextBlock::new()
.id(ID_POLICY_CHECK_POLICY_CODE)
.style("body")
.attach(Grid::row(2))
.attach(Grid::column(2))
.build(ctx);
let policy_check_form_action = Container::new()
.id(ID_POLICY_CHECK_ACTION_GRID)
.attach(Grid::row(3))
.attach(Grid::column(1))
//.style(STYLE_CONTAINER_ACTION)
.padding(14)
.h_align("center")
.child(
Stack::new()
//.style(STYLE_STACK_ACTION)
.orientation("horizontal")
.spacing(50)
.child(
Button::new()
.id(ID_POLICY_CHECK_ACTION_BUTTON_CREATE)
.style(STYLE_BUTTON_ACTION)
.text("Create ticket")
.on_click(move |states, _entity| {
//states.get_mut::<PolicycheckState>(id).send_message_update_policynumber(id);
//states.send_message(PolicycheckAction::UpdatePolicyCode, policy_check_policy_code);
states.send_message(PolicycheckAction::UpdatePolicyCode, id);
states.send_message(PolicycheckAction::NewTicket, id);
false
})
.build(ctx),
)
.build(ctx),
)
.build(ctx);
let policy_check_form = Container::new()
.id(ID_POLICY_CHECK_FORM)
.name(ID_POLICY_CHECK_FORM)
.attach(Grid::row(2))
.attach(Grid::column(1))
.style("container_form")
.child(
Grid::new()
.id(ID_POLICY_CHECK_FORM)
.columns(
Columns::create()
.push("auto") // Label
.push("16") // Delimiter
.push("200") // Data
.push("16") // Delimiter
.push("32") // Result-Button
.push("4") // Delimeter
)
.rows(
Rows::create()
.push("auto") // Row 0
.push("14") // Seperator
.push("auto") // Row 2
.push("14") // Seperator
.push("auto") // Row 3
)
//.child(policy_check_form_row_0)
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_LABEL_POLICY_NUMBER)
.style("body")
.attach(Grid::row(0))
.attach(Grid::column(0))
.h_align("end")
.v_align("center")
.text("Policy number")
.build(ctx),
)
.child(
TextBox::new()
.id(ID_POLICY_CHECK_POLICY_NUMBER)
//.style("body")
.attach(Grid::row(0))
.attach(Grid::column(2))
//.lose_focus_on_activation(false)
//WIP: localization for water_mark
.water_mark("10-stellig")
.on_activate(move |states, entity| {
// Entity is entered/activated via Mouse/Keyboard
states.get_mut::<PolicycheckState>(id).parse_policy_number(entity);
})
.on_key_down(move |_, key_event| {
if key_event.key == Key::A(true) {
println!("A key down");
}
// ctx.get_mut::<PolicycheckState>(id)
// .set_action(Action::ImportData);
true
})
.build(ctx)
)
.child(policy_check_button_result)
//.child(policy_check_form_row_2)
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_LABEL_RESULT)
.style("body")
.attach(Grid::row(2))
.attach(Grid::column(0))
.h_align("end")
.v_align("center")
.text("Policy code")
.build(ctx),
)
// .child(
// TextBlock::new()
// .id(ID_POLICY_CHECK_RESULT)
// .style("body")
// .attach(Grid::row(2))
// .attach(Grid::column(2))
// .build(ctx)
//)
.child(policy_check_policy_code)
//.child(policy_check_form_row_2)
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_LABEL_HINT)
.style("hint")
.attach(Grid::row(4))
.attach(Grid::column(0))
//.margin((0, 0, 16, 0))
.h_align("end")
.v_align("center")
.text("Error:")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_HINT)
.style("hint")
.attach(Grid::row(4))
.attach(Grid::column(2))
.build(ctx),
)
.build(ctx),
)
.build(ctx);
// row3: only shown, if we read in `policy numbers` in
// a hashmap as values
let policy_data_stack = Stack::new()
.id(ID_POLICY_DATA_STACK)
.attach(Grid::row(3))
.attach(Grid::column(1))
.h_align("end")
.v_align("top")
.orientation("horizontal")
.visibility(Visibility::Collapsed)
.child(
TextBlock::new()
.id(ID_POLICY_DATA_LABEL)
.margin((0, 4, 0, 0))
.enabled(true)
.text("Checklist elements: ")
.build(ctx)
)
.child(
TextBlock::new()
.id(ID_POLICY_DATA_COUNT)
.margin((0, 4, 0, 0))
.enabled(true)
.text("0")
.build(ctx)
)
.build(ctx);
// Starter page: check policy numbers
self.name("PolicycheckView")
// initialize struct (derived default macro)
.policy_check(PolicyCheck::default())
.child(
Grid::new()
.id(ID_POLICY_CHECK_WIDGET)
.columns(
Columns::create()
.push(50) // Left margin
.push("*") // Content
.push(50) // Right margin
)
.rows(
Rows::create()
.push("auto") // Header_Bar
.push(28) // Seperator
.push("*") // InputForm
.push("auto") // Data_Result
.push("auto") // Bottom_Bar
)
.child(policy_check_header_bar) // row 0
.child(policy_check_form) // row 2
.child(policy_data_stack) // row 3
.child(policy_check_form_action) // row 4
.child(policy_check_bottom_bar) // row 5
.build(ctx),
)
}
}

View File

@@ -1,237 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
//use locales::t;
use orbtk::prelude::*;
use serde::Deserialize;
//use std::process;
//use std::collections::HashMap;
use std::time::SystemTime;
use tracing::{info, trace};
use crate::{
data::{constants::*, structures::Email},
widgets::global_state::GlobalState,
services::exports::send_ticketdata::sendticketdata,
//widgets::ticketdata::ticketdata_view::TicketdataView,
widgets::policycheck::policycheck_state::PolicycheckAction,
};
/// Valid `actions` that are handled as state changes in the `Ticketdata` widget.
#[derive(Debug, Clone)]
pub enum TicketdataAction {
ClearEntry(Entity),
/// Clear text in the form
ClearForm(String),
ChangeTheme(),
//ChangeMailCc(),
//ChangeMailTo(),
InputTextChanged(Entity),
ParseEntry(Entity),
RemoveFocus(Entity),
SendForm(),
SetToggleTheme(Entity),
SetEntry(Entity),
SetVisibility(Entity),
TextChanged(Entity, usize),
UpdatePolicyCode(String)
}
/// 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,
}
/// Valid `structures` that are handled inside the state of the `Ticket` widget.
#[derive(AsAny, Default)]
pub struct TicketdataState {
actions: Vec<TicketdataAction>,
button_menu: Entity,
//duration: Duration,
lang: String,
target: Entity
}
impl GlobalState for TicketdataState {}
/// Method definitions, that react on any given state change inside the `Ticketdata` widget.
impl TicketdataState {
/// Clear the text property of all children of the given form entity
pub fn clear_form(entity: Entity, id: &str, ctx: &mut Context<'_>) {
// form is identified by its id
if ctx.entity_of_child(id).is_some() {
let form_entity = ctx.entity_of_child(ID_TICKET_DATA_FORM_GRID).unwrap();
let form_container: WidgetContainer<'_> = ctx.get_widget(form_entity);
// BUG: Why does name defer from id, they are using the same constant?
info!("Form id: {:?}", form_container.get::<String>("id"));
info!("Form name: {:?}", form_container.get::<String>("name"));
//ctx.clear_children_of(form_entity); // complete form is cleared!
// switch into the context of the form_container
ctx.change_into(form_entity);
if let Some(count) = ctx.widget().children_count() {
for i in 0..count {
// process child
if let Some(child) = &mut ctx.try_child_from_index(i) {
let child_name: &str = child.get::<String>("name");
let child_id: &str = child.get::<String>("id");
info!("child({:?}) name: {:?}",
i, child_name);
// match child_name {
// "TextBox" => TextBox::text_set(child, ""),
// "ticket_data_policy_code" => TextBox::text_set(child, ""),
// _ => info!("don't act on types other than 'TextBox'"),
// }
info!("child({:?}) id: {:?}",
i, child_id);
match child_id {
"ticket_data_policy_code" => TextBox::text_set(child, ""),
"ticket_data_policy_holder" => TextBox::text_set(child, ""),
"ticket_data_policy_deductible" => TextBox::text_set(child, ""),
"ticket_data_policy_callback_number" => TextBox::text_set(child, ""),
"ticket_data_policy_callback_date" => TextBox::text_set(child, ""),
"ticket_data_policy_callback_harm_type" => TextBox::text_set(child, ""),
"ticket_data_policy_callback_ivr_comment" => TextBox::text_set(child, ""),
_ => info!("don't act on child_id '{:?}", child_id),
}
}
}
}
// switch back to parent entity
ctx.change_into(entity);
}
}
pub fn send_form(_entity: Entity, ctx: &mut Context<'_>, lang: &str) {
// type conversion (String -> u64)
//let policy_code = ctx.child(ID_TICKET_DATA_POLICY_CODE).get::<String>("text").unwrap().parse::<u64>().unwrap();
// WIP: get selected items ComboBox'es
//let mail_cc_index = *TicketdataView::selected_index_ref(&ctx.widget()) as usize;
//let mail_cc_selected = TicketdataView::mail_cc_ref(&ctx.widget())[mail_cc_index].clone();
// create Email structures
let email = Email {
// WIP: mail_to -> selected index auslesen
//mail_to: ctx.child(ID_TICKET_DATA_MAIL_TO).get::<String>("text").to_string(),
// WIP: mail_cc -> selected index auslesen
//mail_cc: ctx.child(ID_TICKET_DATA_MAIL_CC).get::<String>("text").to_string(),
mail_to: PROP_MAIL_TO_1.to_string(),
mail_cc: PROP_MAIL_CC_1.to_string(),
mail_bcc: PROP_MAIL_BCC_1.to_string(),
mail_from: PROP_MAIL_FROM.to_string(),
mail_reply: PROP_MAIL_REPLY.to_string(),
subject: PROP_MAIL_SUBJECT.to_string(),
policy_code: ctx.child(ID_TICKET_DATA_POLICY_CODE).get::<String>("text").to_string(),
policy_holder: ctx.child(ID_TICKET_DATA_POLICY_HOLDER).get::<String>("text").to_string(),
deductible: ctx.child(ID_TICKET_DATA_DEDUCTIBLE).get::<String>("text").to_string(),
callback_number: ctx.child(ID_TICKET_DATA_CALLBACK_NUMBER).get::<String>("text").to_string(),
callback_date: ctx.child(ID_TICKET_DATA_CALLBACK_DATE).get::<String>("text").to_string(),
harm_type: ctx.child(ID_TICKET_DATA_HARM_TYPE).get::<String>("text").to_string(),
ivr_comment: ctx.child(ID_TICKET_DATA_IVR_COMMENT).get::<String>("text").to_string(),
};
info!("WIP: Sending form to construct eMail to {:?}", email);
// send email via service
if let Err(_e) = sendticketdata(&email, &lang) {
Button::icon_brush_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), String::from("#FF0000"));
Button::foreground_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), String::from("#FF0000"));
Button::icon_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), material_icons_font::MD_CLEAR);
};
}
}
/// Supported methods handled inside the `TicketState`
impl State for TicketdataState {
/// Initialize the state of widgets inside `TicketState`
fn init(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
let time_start= SystemTime::now();
trace!(target: "advotracker", ticketdata_state = "init", status = "started");
// Initialize required menu button entity
self.button_menu = ctx
.entity_of_child(ID_TICKET_DATA_BUTTON_MENU)
.expect("TicketState.init: Can't find resource entity 'ID_TICKET_DATA_BUTTON_MENU'.");
// initialize the entity object, that will receive messages
self.target = Entity::from(ctx.widget().try_clone::<u32>("target")
.expect("TicketState.init: Can't find resource entity 'target'."));
// Get language from environment
self.lang = TicketdataState::get_lang();
let time_end = SystemTime::now();
let duration = time_end.duration_since(time_start);
trace!(target: "advotracker", ticketdata_state = "init", status = "finished", duration = ?duration);
}
/// The reader component of the message system handing `TicketdataState``
fn messages(
&mut self,
mut messages: MessageReader,
_registry: &mut Registry,
ctx: &mut Context<'_>,
) {
for message in messages.read::<TicketdataAction>() {
match message {
TicketdataAction::ClearForm(id) => {
info!("message: {:?} recieved", id);
// change into the context of the given form
TicketdataState::clear_form(ctx.entity(), &id, ctx);
}
TicketdataAction::SendForm() => {
info!("message: {:?} recieved", message);
TicketdataState::send_form(ctx.entity(), ctx, &self.lang);
}
_ => { println!("messages: action not implemented!"); }
}
}
for message in messages.read::<PolicycheckAction>() {
match message {
PolicycheckAction::UpdatePolicyCode => {
info!("Message received: 'PolicycheckAction::UpdatePolicyCode'");
//TextBlock::text_set(&mut ctx.child(ID_TICKET_DATA_POLICY_CODE), policy_code);
}
_ => { println!("messages: action not implemented!"); }
}
}
}
fn update(&mut self, _registry: &mut Registry, ctx: &mut Context<'_>) {
let actions: Vec<TicketdataAction> = self.actions.drain(..).collect();
for action in actions {
match action {
TicketdataAction::ClearForm(ref id) => {
info!("update: send_message {:?}", action);
ctx.send_message(TicketdataAction::ClearForm(id.to_string()), self.target);
}
TicketdataAction::SendForm() => {
//ctx.send_message(TicketdataAction::SendForm(), self.ID_TICKETDATA_FORM);
info!("update: send_message {:?}", action);
}
_ => { println!("TicketdataAction: action not implemented!"); }
}
}
}
}

Submodule advotrackerd deleted from 409d8d1f1a

6
crates/.gitmodules vendored
View File

@@ -1,6 +0,0 @@
[submodule "advotrackerdb"]
path = advotrackerdb
url = https://gitea.networkx.de:50443/rzerres/advotrackerdb
[submodule "advotrackerd"]
path = advotrackerd
url = https://gitea.networkx.de:50443/rzerres/advotrackerd

View File

@@ -1,8 +0,0 @@
[[apps]]
name = "advotracker"
width = 580
height = 280
assets = "resources/advotracker"
[[apps.fonts]]
font_family = "MaterialIcons-Regular"
src = "resources/fonts/MaterialIcons.ttf"

View File

@@ -1,5 +0,0 @@
[advotracker.conf]
mode = interative

View File

@@ -1,10 +0,0 @@
Theme (
styles: {
"container_form": (
base: "container",
properties: {
"border": 1,
},
),
}
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 289 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 B

View File

@@ -1,152 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="105mm"
height="74mm"
viewBox="0 0 105 74"
version="1.1"
id="svg8"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="Hiedemann_Logo.svg">
<title
id="title850">Hiedemann Rechtsanwälte</title>
<defs
id="defs2" />
<sodipodi:namedview
units="mm"
inkscape:snap-global="true"
inkscape:snap-grids="true"
inkscape:snap-nodes="true"
inkscape:window-maximized="1"
inkscape:window-y="27"
inkscape:window-x="0"
inkscape:window-height="1088"
inkscape:window-width="2048"
showgrid="false"
inkscape:document-rotation="0"
inkscape:current-layer="layer1"
inkscape:document-units="mm"
inkscape:cy="285.11146"
inkscape:cx="343.98278"
inkscape:zoom="1.4564683"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
borderopacity="1.0"
bordercolor="#666666"
pagecolor="#ffffff"
id="base" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Hiedemann Rechtsanwälte</dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Hiedemann Rechtsanwälte</dc:title>
</cc:Agent>
</dc:creator>
<dc:publisher>
<cc:Agent>
<dc:title>Networkx GmbH</dc:title>
</cc:Agent>
</dc:publisher>
</cc:Work>
</rdf:RDF>
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:title>Hiedemann Rechtsanwälte</dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
style="display:inline"
inkscape:label="Rahmen"
id="layer2"
inkscape:groupmode="layer" />
<g
style="display:inline"
id="layer1"
inkscape:groupmode="layer"
inkscape:label="Logo">
<g
inkscape:export-ydpi="96"
inkscape:export-xdpi="96"
inkscape:export-filename="/data/development/advotracker/advotracker/resources/images/hiedemann_logo.png"
transform="matrix(0.5,0,0,0.5,26.483775,16.188821)"
id="g1005">
<g
id="g910"
style="display:inline"
transform="translate(-1.958558,18.772823)"
inkscape:export-filename="/data/development/advotracker/advotracker/resources/images/hiedemann_logo.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<rect
ry="6.2927017"
rx="0.08973857"
y="1.2013354"
x="4.9724188"
height="24.806967"
width="99.907379"
id="rect852"
style="vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.0926207;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g>
<g
id="g1098"
transform="matrix(1.3250965,0,0,1.3250965,-38.983201,-118.19402)"
inkscape:export-filename="/data/development/advotracker/advotracker/resources/images/hiedemann_logo.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<text
transform="scale(0.95388348,1.0483461)"
id="text835"
y="108.37959"
x="36.210163"
style="font-size:8.71712px;line-height:125%;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';letter-spacing:2.60261px;word-spacing:0px;writing-mode:lr-tb;fill:#c46069;fill-opacity:1;stroke:#000000;stroke-width:0.363212px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8.71712px;font-family:'Cyntho Pro';-inkscape-font-specification:'Cyntho Pro, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#c46069;fill-opacity:1;stroke:none;stroke-width:0.363212px"
y="108.37959"
x="36.210163"
id="tspan833"
sodipodi:role="line">HIEDE<tspan
id="tspan889"
style="letter-spacing:1.31762px">M</tspan><tspan
id="tspan883"
style="letter-spacing:1.31762px;stroke-width:0.363212px">A</tspan>NN</tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.58611px;line-height:125%;font-family:FreeSans;-inkscape-font-specification:'FreeSans, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;letter-spacing:3.43958px;word-spacing:0px;writing-mode:lr-tb;fill:#9d9b9b;fill-opacity:1;stroke:none;stroke-width:0.444725px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="40.402027"
y="104.09837"
id="text853"
transform="scale(0.86606999,1.1546411)"><tspan
sodipodi:role="line"
id="tspan851"
x="40.402027"
y="104.09837"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:4.23333px;font-family:'Cyntho Pro';-inkscape-font-specification:'Cyntho Pro';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#9d9b9b;fill-opacity:1;stroke:none;stroke-width:0.444725px"><tspan
id="tspan925"
style="letter-spacing:3.70417px">REC</tspan><tspan
style="letter-spacing:3.33375px"
id="tspan1083">HT</tspan><tspan
style="letter-spacing:2.92894px"
id="tspan1075">S</tspan><tspan
style="letter-spacing:3.23585px"
id="tspan1069">AN</tspan><tspan
id="tspan921"
style="letter-spacing:2.94746px">WÄLTE</tspan></tspan></text>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -1,24 +0,0 @@
[Icon Theme]
Name=AdvoTracker
Comment=AdvoTracker Icon Theme
Directories=20x20,20x20@2,20x20@3,20x20@4
[20x20]
Size=20
Type=Fixed
[20x20@2]
Size=20
Scale=2
Type=Fixed
[20x20@3]
Size=20
Scale=3
Type=Fixed
[20x20@4]
Size=20
Scale=4
Type=Fixed

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 768 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

View File

@@ -1 +0,0 @@
hiedemann_logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,49 +0,0 @@
Target: debug
[ralf@jacara-x1 frontend]$ time ../target/debug/examples/csv-import --importFile /home/ralf/projekte/Hiedemann/Allianz_Vorgaben_Policycheck/ERG.txt -v
Jun 27 02:43:48.886 TRACE csv-import: "Umgebungsvariablen prüfen" state="gestartet"
Jun 27 02:43:48.886 TRACE csv-import: environment="system" lang="de_DE.UTF-8"
Jun 27 02:43:48.887 DEBUG csv-import: missing value for field test_lang
Jun 27 02:43:48.887 TRACE csv-import: environment="envy" lang="de_DE.UTF-8"
Jun 27 02:43:48.887 TRACE csv-import: "Umgebungsvariablen prüfen" state="beendet"
Jun 27 02:43:48.887 TRACE csv-import: process="Programmargumente prüfen" state="gestartet"
RUST_LOG=None
Jun 27 02:43:48.887 TRACE csv_import::parse_args: verbose 1
config_file: "csv_import.ron"
import_file: "/home/ralf/projekte/Hiedemann/Allianz_Vorgaben_Policycheck/ERG.txt"
verbosity level: 1
Jun 27 02:43:48.887 TRACE csv-import: process="Programmargumente prüfen" state="beendet"
Jun 27 02:43:48.887 TRACE csv-import: process="Programmlogik starten" state="gestartet"
Jun 27 02:43:48.887 TRACE csv-import: extension=Some("txt") file=File { fd: 3, path: "/home/ralf/projekte/Hiedemann/Allianz_Vorgaben_Policycheck/ERG.txt", read: true, write: false }
Jun 27 02:43:48.888 TRACE csv-import: header=StringRecord(["DION", "VERS", "POLLFNR"])
Jun 27 02:43:57.513 TRACE csv-import: record_count=2498330
Imported 2498330 records
Jun 27 02:43:57.513 TRACE csv-import: process="Programmlogik beendet" state="beendet"
real 0m8,700s
user 0m8,675s
sys 0m0,017s
Target: release
[ralf@jacara-x1 frontend]$ time ../target/release/examples/csv-import --importFile /home/ralf/projekte/Hiedemann/Allianz_Vorgaben_Policycheck/ERG.txt -v
Jun 27 02:48:13.753 TRACE csv-import: "Umgebungsvariablen prüfen" state="gestartet"
Jun 27 02:48:13.753 TRACE csv-import: environment="system" lang="de_DE.UTF-8"
Jun 27 02:48:13.753 DEBUG csv-import: missing value for field test_lang
Jun 27 02:48:13.753 TRACE csv-import: environment="envy" lang="de_DE.UTF-8"
Jun 27 02:48:13.753 TRACE csv-import: "Umgebungsvariablen prüfen" state="beendet"
Jun 27 02:48:13.753 TRACE csv-import: process="Programmargumente prüfen" state="gestartet"
RUST_LOG=None
Jun 27 02:48:13.753 TRACE csv_import::parse_args: verbose 1
config_file: "csv_import.ron"
import_file: "/home/ralf/projekte/Hiedemann/Allianz_Vorgaben_Policycheck/ERG.txt"
verbosity level: 1
Jun 27 02:48:13.753 TRACE csv-import: process="Programmargumente prüfen" state="beendet"
Jun 27 02:48:13.753 TRACE csv-import: process="Programmlogik starten" state="gestartet"
Jun 27 02:48:13.754 TRACE csv-import: extension=Some("txt") file=File { fd: 3, path: "/home/ralf/projekte/Hiedemann/Allianz_Vorgaben_Policycheck/ERG.txt", read: true, write: false }
Jun 27 02:48:13.754 TRACE csv-import: header=StringRecord(["DION", "VERS", "POLLFNR"])
Jun 27 02:48:14.098 TRACE csv-import: record_count=2498330
Imported 2498330 records
Jun 27 02:48:14.098 TRACE csv-import: process="Programmlogik beendet" state="beendet"
real 0m0,355s
user 0m0,338s
sys 0m0,017s

View File

@@ -1,7 +0,0 @@
# set the language variable used in test-runs
#test lang=it
TEST_LANG=en
#RUST_LOG=csv-import=trace
LOG=debug
USERNAME=ralf
DB_DRIVER=sqlite

View File

@@ -1,502 +0,0 @@
use std::collections::HashSet;
use orbtk::prelude::*;
#[derive(Debug, Copy, Clone)]
enum Action {
AddItem,
ClearText,
EntryActivated(Entity),
EntryChanged(Entity),
ValueChanged(Entity),
IncrementCounter,
RemoveItem,
ToggleTheme(Entity),
}
#[derive(AsAny)]
pub struct MainViewState {
action: Option<Action>,
}
impl Default for MainViewState {
fn default() -> Self {
MainViewState { action: None }
}
}
impl MainViewState {
fn action(&mut self, action: impl Into<Option<Action>>) {
self.action = action.into();
}
}
impl State for MainViewState {
fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
if let Some(action) = self.action {
match action {
Action::AddItem => {
let len = main_view(ctx.widget()).list().len();
if len < 5 {
main_view(ctx.widget())
.list_mut()
.push(format!("Item {}", len + 1));
ctx.child("items").clone_or_default::<usize>("Item");
items_widget(ctx.child("items")).set_count(len + 1);
button(ctx.child("remove-item-button")).set_enabled(true);
button(ctx.child("remove-item-button")).set_visibility(Visibility::Visible);
if len == 4 {
button(ctx.child("add-item-button")).set_enabled(false);
button(ctx.child("add-item-button"))
.set_visibility(Visibility::Collapsed);
}
}
}
Action::RemoveItem => {
let len = main_view(ctx.widget()).list().len();
if len > 0 {
main_view(ctx.widget()).list_mut().remove(len - 1);
items_widget(ctx.child("items")).set_count(len - 1);
button(ctx.child("add-item-button")).set_enabled(true);
button(ctx.child("add-item-button")).set_visibility(Visibility::Visible);
if len == 1 {
button(ctx.child("remove-item-button")).set_enabled(false);
button(ctx.child("remove-item-button"))
.set_visibility(Visibility::Collapsed);
}
}
}
Action::IncrementCounter => {
*main_view(ctx.widget()).counter_mut() += 1;
let counter = *main_view(ctx.widget()).counter();
main_view(ctx.widget())
.set_result(String16::from(format!("Button count: {}", counter)));
}
Action::ClearText => {
main_view(ctx.widget()).set_text_one(String16::default());
main_view(ctx.widget()).set_text_two(String16::default());
}
Action::EntryActivated(entity) => {
let mut text_box = text_box(ctx.get_widget(entity));
let text = text_box.text_mut();
println!("submitting {}", text);
text.clear();
}
Action::EntryChanged(entity) => {
println!("entry changed: {}", text_box(ctx.get_widget(entity)).text());
}
Action::ValueChanged(_entity) => {
//println!("Slider value changed");
}
Action::ToggleTheme(entity) => {
let light = *ctx.get_widget(entity).get::<bool>("selected");
let theme = if light { light_theme() } else { dark_theme() };
ctx.switch_theme(theme);
}
}
self.action = None;
}
}
fn update_post_layout(&mut self, _: &mut Registry, ctx: &mut Context) {
let mut selection_string = "Selected:".to_string();
for index in &main_view(ctx.widget()).selected_indices().0 {
selection_string = format!("{} {}", selection_string, index);
}
text_block(ctx.child("selection")).set_text(selection_string);
}
}
fn create_header(ctx: &mut BuildContext, text: &str) -> Entity {
TextBlock::new().text(text).style("header").build(ctx)
}
type List = Vec<String>;
widget!(
MainView<MainViewState> {
selected_indices: SelectedIndices,
counter: usize,
list_count: usize,
combo_box_list_count: usize,
list: List,
selection_list: List,
combo_box_list: List,
selection_list_count: usize,
text_one: String16,
text_two: String16,
result: String16
}
);
impl Template for MainView {
fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
let slider = Slider::new()
.min(0.0)
.max(1.0)
.on_changed(move |states, entity| {
state(id, states).action(Action::ValueChanged(entity));
})
.build(ctx);
self.name("MainView")
.result("Button count: 0")
.counter(0)
.selected_indices(HashSet::new())
.list(vec![
"Item 1".to_string(),
"Item 2".to_string(),
"Item 3".to_string(),
])
.list_count(3)
.selection_list(vec![
"Select Item 1".to_string(),
"Select Item 2".to_string(),
"Select Item 3".to_string(),
"Select Item 4".to_string(),
"Select Item 5".to_string(),
"Select Item 6".to_string(),
"Select Item 7".to_string(),
"Select Item 8".to_string(),
"Select Item 9".to_string(),
"Select Item 10".to_string(),
])
.combo_box_list(vec![
"CB 1".to_string(),
"CB 2".to_string(),
"CB 3".to_string(),
"CB 4".to_string(),
"CB 5".to_string(),
"CB 6".to_string(),
"CB 7".to_string(),
"CB 8".to_string(),
"CB 9".to_string(),
"CB 10".to_string(),
])
.selection_list_count(10)
.combo_box_list_count(10)
.child(
Grid::new()
.margin(8)
.columns(Columns::new().add(132).add(16).add(132).add(16).add(132))
.rows(Rows::new().add("*").add(32))
.child(
// Row 0
Stack::new()
.attach(Grid::column(0))
.attach(Grid::row(0))
// Column 0
.child(create_header(ctx, "Buttons"))
.child(
Button::new()
.text("Button")
.margin((0, 8, 0, 0))
.icon(material_icons_font::MD_CHECK)
.attach(Grid::column(0))
.attach(Grid::row(1))
.on_click(move |states, _| {
state(id, states).action(Action::IncrementCounter);
true
})
.build(ctx),
)
.child(
Button::new()
.text("Primary")
.style("button_primary")
.margin((0, 8, 0, 0))
.icon(material_icons_font::MD_360)
.attach(Grid::column(0))
.attach(Grid::row(2))
.build(ctx),
)
.child(
ToggleButton::new()
.style("button_single_content")
.text("ToggleButton")
.margin((0, 8, 2, 0))
.icon(material_icons_font::MD_ALARM_ON)
.attach(Grid::column(0))
.attach(Grid::row(3))
.build(ctx),
)
.child(
CheckBox::new()
.text("CheckBox")
.margin((0, 8, 0, 0))
.attach(Grid::column(0))
.attach(Grid::row(4))
.build(ctx),
)
.child(
Switch::new()
.margin((0, 8, 0, 0))
.attach(Grid::column(0))
.attach(Grid::row(5))
.build(ctx),
)
.child(slider)
.child(
ProgressBar::new()
.val(slider)
.margin((0, 8, 0, 0))
.build(ctx),
)
.build(ctx),
)
.child(
Stack::new()
// Column 2
.attach(Grid::column(2))
.attach(Grid::row(0))
.child(create_header(ctx, "Text"))
.child(
TextBlock::new()
.style("body")
.text(("result", id))
.margin((0, 8, 0, 0))
.attach(Grid::column(2))
.attach(Grid::row(1))
.build(ctx),
)
.child(
TextBox::new()
.water_mark("TextBox...")
.text(("text_one", id))
.margin((0, 8, 0, 0))
.attach(Grid::column(2))
.attach(Grid::row(2))
.on_activate(move |states, entity| {
state(id, states).action(Action::EntryActivated(entity));
})
.on_changed(move |states, entity| {
state(id, states).action(Action::EntryChanged(entity));
})
.build(ctx),
)
.child(
TextBox::new()
.water_mark("TextBox...")
.text(("text_two", id))
.margin((0, 8, 0, 0))
.attach(Grid::column(2))
.attach(Grid::row(2))
.on_activate(move |states, entity| {
state(id, states).action(Action::EntryActivated(entity));
})
.on_changed(move |states, entity| {
state(id, states).action(Action::EntryChanged(entity));
})
.build(ctx),
)
.child(
Button::new()
.margin((0, 8, 0, 0))
.style("button_single_content")
.text("clear text")
.icon(material_icons_font::MD_CLEAR)
.on_click(move |states, _| {
state(id, states).action(Action::ClearText);
true
})
.build(ctx),
)
.child(
NumericBox::new()
.margin((0, 8, 0, 0))
.max(123)
.step(0.123)
.val(0.123)
.build(ctx),
)
.build(ctx),
)
.child(
// Column 4
Grid::new()
.rows(
Rows::new()
.add("auto")
.add(32)
.add(16)
.add(204)
.add("auto")
.add(192)
.add("auto"),
)
.columns(Columns::new().add("*").add(4).add("*"))
.attach(Grid::column(4))
.attach(Grid::row(0))
.child(
TextBlock::new()
.text("Items")
.style("header")
.attach(Grid::column(0))
.attach(Grid::column_span(3))
.attach(Grid::row(0))
.build(ctx),
)
.child(
ComboBox::new()
.items_builder(move |bc, index| {
let text = bc
.get_widget(id)
.get::<Vec<String>>("combo_box_list")[index]
.clone();
TextBlock::new()
.style("small_text")
.margin((0, 0, 0, 2))
.v_align("center")
.text(text)
.build(bc)
})
.selected_index(0)
.attach(Grid::column(0))
.attach(Grid::column_span(3))
.attach(Grid::row(1))
.margin((0, 8, 0, 0))
.count(("combo_box_list_count", id))
.build(ctx),
)
.child(
ItemsWidget::new()
.id("items")
.padding((4, 4, 4, 2))
.attach(Grid::column(0))
.attach(Grid::column_span(3))
.attach(Grid::row(3))
.margin((0, 0, 0, 8))
// bc = build-context
.items_builder(move |bc, index| {
let text = bc.get_widget(id).get::<Vec<String>>("list")
[index]
.clone();
Button::new().margin((0, 0, 0, 2)).text(text).build(bc)
})
.count(("list_count", id))
.build(ctx),
)
.child(
Button::new()
.style("button_single_content")
.id("remove-item-button")
.icon(material_icons_font::MD_REMOVE_CIRCLE)
.on_click(move |states, _| {
state(id, states).action(Action::RemoveItem);
true
})
.min_width(0)
.attach(Grid::column(0))
.attach(Grid::row(4))
.build(ctx),
)
.child(
Button::new()
.style("button_single_content")
.id("add-item-button")
.icon(material_icons_font::MD_ADD_CIRCLE)
.on_click(move |states, _| {
state(id, states).action(Action::AddItem);
true
})
.min_width(0)
.attach(Grid::column(2))
.attach(Grid::row(4))
.build(ctx),
)
.child(
ListView::new()
.attach(Grid::column(0))
.attach(Grid::column_span(3))
.attach(Grid::row(5))
.selected_indices(id)
.margin((0, 16, 0, 8))
.items_builder(move |bc, index| {
let text = bc
.get_widget(id)
.get::<Vec<String>>("selection_list")[index]
.clone();
TextBlock::new()
.margin((0, 0, 0, 2))
.v_align("center")
.text(text)
.build(bc)
})
.on_selection_changed(|_, _, _| println!("Selection changed"))
.count(("selection_list_count", id))
.build(ctx),
)
.child(
// todo: wrong text width????
TextBlock::new()
.style("body")
.id("selection")
.max_width(120)
.attach(Grid::column(0))
.attach(Grid::column_span(3))
.attach(Grid::row(6))
.text("Selected:")
.build(ctx),
)
.build(ctx),
)
.child(
// Row 1
Stack::new()
.orientation("horizontal")
.attach(Grid::row(1))
.attach(Grid::column(0))
.child(
TextBlock::new()
.style("body")
.text("Toggle theme: ")
.v_align("center")
.margin((0, 0, 4, 0))
.build(ctx),
)
.child(
Switch::new()
.on_changed(move |states, entity| {
state(id, states).action(Action::ToggleTheme(entity));
})
.v_align("center")
.build(ctx),
)
.build(ctx),
)
.build(ctx),
)
}
}
fn main() {
// use this only if you want to run it as web application.
orbtk::initialize();
Application::new()
.window(|ctx| {
Window::new()
.title("OrbTk - widgets example")
.position((100, 100))
.size(468, 730)
.resizeable(true)
.child(MainView::new().build(ctx))
.build(ctx)
})
.run();
}
// helper to request MainViewState
fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut MainViewState {
states.get_mut(id)
}

View File

@@ -1,7 +0,0 @@
# set the language variable used in test-runs
#test lang=de
TEST_LANG=en
#RUST_LOG=csv-test=trace
RUST_LOG=trace
USERNAME=ralf
DB_DRIVER=sqlite

View File

@@ -1,23 +0,0 @@
DION VERS POLLFNR
1 AS 1
1 AS 11
1 AS 123456789
9 AS 99
9 AS 999
1 AS 1511111111
1 AS 1511111119
1 AS 9000000001
1 AS 9000000002
1 AS 9999999991
1 AS 9999999992
1 AS 9999999999
3 AS 1515735920
3 AS 9999999991
3 AS 9999999992
3 AS 9999999999
9 AS 9927764110
9 AS 9927764251
9 AS 9927764426
9 AS 9999999991
9 AS 9999999992
9 AS 9999999999

File diff suppressed because it is too large Load Diff

View File

@@ -1 +0,0 @@
../../../data/POLLFNR_WOECHENTLICH.txt

View File

@@ -1,409 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use chrono::{Local, DateTime};
use locales::t;
//use serde::{Deserialize, Serialize};
use serde::Deserialize;
use std::{
collections::HashMap,
env,
{error::Error, process},
//path::{Path, PathBuf},
};
use tracing::{debug, trace, Level};
use advotracker::data::structures::{PolicyCode, PolicyList, PolicyDataList, PolicyData};
// include modules
mod parse_args;
/// respect environment variables set in .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,
log: String,
}
/// export as csv format
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
/// https://blog.burntsushi.net/csv/
fn export(p: &mut String, lang: &String) -> Result<u64, Box<dyn Error>> {
use std::fs::File;
use std::path::Path;
//use std::ffi::OsStr;
use std::io::prelude::*;
let mut res = t!("csv.export.started", lang);
let mut state = t!("state.started", lang);
let dt_start: DateTime<Local> = Local::now();
trace!(target: "csv-test",
process = ?res,
state = ?state,
date_start = ?dt_start.to_string());
// Note: slash syntax also works on Windows!
let path = Path::new(p);
// open the file descriptor
let mut file = File::create(path)?;
trace!(target: "csv-export", extension = ?path.extension(), file = ?file);
// Build the CSV writer and push selected records.
//for result in csv_reader.records() {
let mut count = 0;
file.write_all(b"Allianz DirectCall Protokoll!")?;
count += 1;
let dt_end: DateTime<Local> = Local::now();
let duration = dt_end.signed_duration_since(dt_start);
println!("Duration: {:#?}", duration);
trace!(target: "csv-test", record_count = ?count, duration = ?duration);
state = t!("state.finished", lang);
res = t!("csv.import.finished", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
Ok(count)
}
/// import from csv format
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
/// https://blog.burntsushi.net/csv/
fn import(p: &mut String, data_list: &mut PolicyDataList,
policy_numbers: &mut HashMap<u64, PolicyCode>, lang: &String)
-> Result<u64, Box<dyn Error>> {
use std::fs::File;
use std::path::Path;
use std::ffi::OsStr;
let mut res = t!("csv.import.started", lang);
let mut state = t!("state.started", lang);
let dt_start: DateTime<Local> = Local::now();
trace!(target: "csv-test",
process = ?res,
state = ?state,
date_start = ?dt_start.to_string());
// Note: slash syntax also workd on Windows!
let path = Path::new(p);
// must be a readable file
trace!(target: "csv-test", path = ?path);
assert_eq!(path.is_file(), true);
// only accept files with '.txt' extensions
let extension = path.extension();
assert_eq!(extension, Some(OsStr::new("txt")));
// open the file
let file = File::open(path)?;
trace!(target: "csv-test",
extension = ?extension,
file = ?file,
data_list = ?data_list.name);
// Build the CSV reader and iterate over each record.
let mut csv_reader = csv::ReaderBuilder::new()
.has_headers(true)
.delimiter(b' ')
.flexible(true)
//.comment(Some(b'#'))
//.from_reader(io::stdin());
//.from_path(path);
.from_reader(file);
{
// We nest this call in its own scope because of lifetimes.
let headers = csv_reader.headers()?;
trace!(target: "csv-test", header = ?headers);
}
// Deserialize the input data and push result to target vector
let mut count = 0;
for result in csv_reader.deserialize() {
// The iterator yields Result<StringRecord, Error>, so we check the
// error here.
let record: PolicyData = result?;
//println!("{:?}", record);
// WIP: write to redis backend
// append the policy_number to the HashMap
policy_numbers.insert(record.policy_number, record.policy_code);
// push record as new vector elements
data_list.push(record);
count +=1;
}
let dt_end: DateTime<Local> = Local::now();
let duration = dt_end.signed_duration_since(dt_start);
trace!(target: "csv-test", record_count = ?count, duration = ?duration);
state = t!("state.finished", lang);
res = t!("csv.import.finished", lang);
trace!(target: "csv-test",
process = ?res,
state = ?state,
date_stop = ?dt_end.to_string());
Ok(count)
}
#[allow(dead_code)]
/// validate a given policy number
/// result will return true or false
fn is_valid(policy_number: &u64, policy_list: &PolicyDataList,
policy_numbers: &mut HashMap<u64, PolicyCode>, lang: &String)
-> Result<bool, Box<dyn std::error::Error>> {
let mut res = t!("policy.validation.started", lang);
let mut state = t!("state.started", lang);
let dt_start: DateTime<Local> = Local::now();
trace!(target: "csv-test",
process = ?res,
state = ?state,
policy_number = ?policy_number,
policy_list = ?policy_list.name,
elements = ?policy_list.policy_data.len(),
date_start = ?dt_start.to_string());
//println!("Policy_number list: {:?}", policy_list.policy_data);
// WIP: testcode to collect policy_number via iterator
//println!("policy_number: {:?}", policy_list.policy_data[1].policy_number);
//println!("Policy_number list: {:?}", policy_list.policy_data);
// println!("policy_list: {:?} (with {:?} elements)",
// policy_list.name, policy_list.policy_data.len());
// policy_list.into_iter()
// .filter(|num| matches(w, w1))
// .clone
// .collect::<Vec<policy_number>>()
// let my_num = policy_list.policy_data.iter()
// .map(|policy_number| {
// policy_number
// })
// .collect::<Vec<_>>();
//println!("My policy_numbers: {:?}", my_num);
// let mut my_policy_list = [
// [ ("Jack", 20), ("Jane", 23), ("Jill", 18), ("John", 19), ],
// [ ("Bill", 17), ("Brenda", 16), ("Brad", 18), ("Barbara", 17), ]
// ];
// let teams_in_score_order = teams
// .iter_mut()
// .map(|team| {
// team.sort_by(|&a, &b| a.1.cmp(&b.1).reverse());
// team
// })
// .collect::<Vec<_>>();
//println!("Teams: {:?}", teams_in_score_order);
// if policy_list.policy_data.iter().any(|v| v == policy_number) {
// println!("{:?} contains {}", policy_list.name, policy_number);
// } else {
// println!("{:?} doesn't contain {}", policy_list, policy_number);
//}
// let test: Vec<_> = vec!["one", "two", "three"];
// let index: usize = test.iter().enumerate().find(|&r| r.1.to_string() == "two".to_string()).unwrap().0;
// println!("index: {:?} -> {:?}", index, test[index]);
//let index: usize = test.iter().enumerate().find(|&r| r.policy_number == "two".to_string()).unwrap().0;
let mut result = false;
match policy_numbers.get(&policy_number) {
Some(&policy_code) => {
let res = t!("policy.validation.success", lang);
println!("policy_number: {} ({:?})",
policy_number, policy_code);
result = true;
trace!(target: "csv-test",
policy_number = ?policy_number,
validation = ?res,
policy_code = ?policy_code);
},
_ => {
let res = t!("policy.validation.failed", lang);
//println!("Noop! Number isn't valid!");
println!("{:?}", res);
trace!(target: "csv-test",
policy_number = ?policy_number,
validation = ?res);
},
}
let dt_end: DateTime<Local> = Local::now();
let duration = dt_end.signed_duration_since(dt_start);
res = t!("policy.validation.finished", lang);
state = t!("state.finished", lang);
trace!(target: "csv-test",
process = ?res,
state = ?state,
date_stop = ?dt_end.to_string(),
duration = ?duration);
Ok(result)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
use dotenv::dotenv;
use parse_args::parse_args;
//use std::process;
//use std::sync::Arc;
use tracing_subscriber::fmt;
use viperus::Viperus;
//static DEFAULT_FILTER: &str = concat!(module_path!(), "=", "trace");
// initialize the tracing subsystem
// a drop in replacement for classical logging
// reference: https://tokio.rs/blog/2019-08-tracing/
let span = tracing::span!(Level::TRACE, "csv-test");
let _enter = span.enter();
let subscriber = fmt::Subscriber::builder()
.with_env_filter("trace")
//.with_max_level(tracing::Level::DEBUG)
.finish();
tracing::subscriber::with_default(subscriber, || {
// get system environment
let mut lang = env::var("LANG").unwrap_or("en".to_string());
let mut res = t!("parse.environment", lang);
let mut state = t!("state.started", lang);
trace!(target: "csv-test", message = ?res, state = ?state);
//debug!(message = ?res, state = ?state);
trace!(target: "csv-test", environment = "system", lang = ?lang);
// 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: "csv-test", "{}", e); }
}
// how to handle unumplemented lang resources??
res = t!("parse.environment", lang);
trace!(target: "csv-test", environment = "envy", lang = ?lang);
state = t!("state.finished", lang);
trace!(target: "csv-test", message = ?res, state = ?state);
// initialize viperus structure
let mut v = Viperus::new();
// parse commandline arguments
res = t!("parse.arguments", lang);
state = t!("state.started", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
let _ = parse_args(&mut v);
state = t!("state.finished", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
//trace!(target: "Viperus", "Config results: {:?}", v);
// main tasks
res = t!("main.started", lang);
state = t!("state.started", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
// create policy structures
let policy_list = PolicyList::new("Allianz Versicherungsnummen-Liste");
println!("Policy List {:?} ", policy_list.name);
let mut policy_data = PolicyDataList::new("Allianz-Import 20200628");
println!("Policy Data List {:?} ", policy_data.name);
let mut policy_numbers : HashMap<u64, PolicyCode> = HashMap::new();
let mut csv_import_path = v.get::<String>("import_file").unwrap();
match import(&mut csv_import_path, &mut policy_data,
&mut policy_numbers, &lang) {
Ok(count) => {
println!("Imported {:?} records", count);
}
Err(err) => {
println!("error running Csv-Test: {}", err);
process::exit(1);
}
}
// test if policy_number is_valid
// type conversion (viperus String -> u64)
let test_policy_number = v.get::<String>("test_policy_number").unwrap().parse::<u64>().unwrap();
trace!(target: "csv-test", test_policy_number = ?test_policy_number);
//match is_valid(&policy_number, &policy_data, &mut policy_numbers, &lang) {
// Ok(true) => {
// use Hashmap method 'get' to check if we have the given key
match policy_numbers.get(&test_policy_number) {
Some(&policy_code) => {
let res = t!("policy.validation.success", lang);
println!("{:?}", res);
println!("policy_number: {} ({:?})",
test_policy_number, policy_code);
}
_ => {
let res = t!("policy.validation.failed", lang);
println!("{:?}", res);
//println!("Nuup! Number isn't valid!");
},
}
// export policy code elements to csv-file
let mut csv_export_path = v.get::<String>("export_file").unwrap();
match export(&mut csv_export_path, &lang) {
Ok(count) => {
println!("Exported {:?} records", count);
}
Err(err) => {
println!("error running CSV-Export: {}", err);
process::exit(1);
}
}
state = t!("state.finished", lang);
res = t!("main.finished", lang);
trace!(target: "csv-test", process = ?res, state = ?state);
});
Ok(())
}
#[test]
fn test_policy_number() {
// Takes a reference and returns Option<&V>
let my_policy_numbers : [u64; 2] = [1511111111, 9999999993];
assert_eq!(my_policy_numbers, [1511111111, 9999999993]);
//let mut csv_import_path = v.get::<String>("import_file").unwrap();
let mut csv_import_path = String::from("data/POLLFNR_TEST.txt");
let mut policy_data = PolicyDataList::new("PolicyDataList");
let mut policy_numbers : HashMap<u64, PolicyCode> = HashMap::new();
let lang = "en".to_string();
println!("import with Path: {:?} PolicyData: {:?} PolicyNumbers: {:?}, Lang: {:?}",
csv_import_path, policy_data, policy_numbers, lang);
let count = import(&mut csv_import_path, &mut policy_data,
&mut policy_numbers, &lang);
assert_eq!(count.unwrap(), 15498);
}

View File

@@ -1,216 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
// parse CLI commandline arguments with clap
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
//use log::{debug, info, trace, warn};
use std::env;
use tracing::trace;
use viperus::Viperus;
/// Parse the commandline arguments and preset default values
/// Precedence: defaults -> config-file -> environment -> commandline
pub fn parse_args(v: &mut Viperus) -> Result<(), Box<dyn std::error::Error>> {
if cfg!(feature = "fmt-clap") {
trace!(target: "Viperus", "Viperus feature 'fmt-clap' enabled.");
println!("Using feature fmt-clap");
}
// preset default key/value pairs (lowest priority)
v.add_default("config_file", String::from("csv_import.ron"));
v.add_default("import_file", String::from("POLLFNR_WOECHENTLICH.txt"));
v.add_default("export_file", String::from(""));
v.add_default("test_policy_number", String::from("9999999992"));
v.add_default("to_email_address_file", String::from("Allianz RA-Hotline <smr-rahotline@allianz.de>"));
v.add_default("from_email_address_file", String::from("Allianz-Hotline RA-Hiedemann <azhotline@hiedemann.de>"));
//v.add_default("username", String::from("nctalkbot"));
//v.add_default("password", String::from("botpassword"));
v.add_default("verbose", 0);
// CLI arguments are defined inline
let matches = App::new("csv-test")
.name(crate_name!())
.version(crate_version!())
.author(crate_authors!())
.about(crate_description!())
.after_help("
Testprogramm: Allianz Online-Beratung Im/Export CSV-Daten
Direct-Call via IVR-System (Interactive Voice Response)
SMR Deckungssummen-Prüfung: 089 92529 60211
SMR Unerledigt: 089 92529 60222")
.template(
"\
{bin} v{version}
{about}
{all-args}
(C) 2020 {author}
{after-help}",
)
.arg(
Arg::with_name("configFile")
.short("c")
.long("configFile")
.value_name("FILE")
.help("Select a config file")
.default_value("csv_import.ron")
.takes_value(true),
)
.arg(
Arg::with_name("importFile")
.short("i")
.long("importFile")
.help("Select source file for the csv-import")
.default_value("POLLFNR_WOECHENTLICH.txt")
//.default_value("POLLFNR_MINI.txt")
.takes_value(true),
)
.arg(
Arg::with_name("exportFile")
.short("e")
.long("exportFile")
.help("Select target file for the csv-export")
.default_value("RA-Hiedemann_DirectCall.txt")
.takes_value(true),
)
.arg(
Arg::with_name("fromEmailAddress")
.short("f")
.long("fromEmailAddress")
.help("Select the sender email-address (From:)")
.default_value("Allianz-Hotline RA-Hiedemann <azhotline@hiedemann.de>")
.takes_value(true),
)
.arg(
Arg::with_name("toEmailAddress")
.short("t")
.long("toEmailAddress")
.help("Select the target email-address (To:)")
.default_value("Allianz RA-Hotline <smr-rahotline@allianz.de>")
.takes_value(true),
)
.arg(
Arg::with_name("testPolicyNumber")
.short("p")
.long("testPolicyNumber")
.help("Test validity of given policy number")
//.default_value("")
.takes_value(true),
)
// .arg(
// Arg::with_name("username")
// .short("u")
// .long("username")
// .help("Sets username")
// .takes_value(true),
// )
// .arg(
// Arg::with_name("password")
// .short("P")
// .long("password")
// .help("Sets password")
// .takes_value(true),
// )
.arg(
Arg::with_name("verbose")
.short("v")
.long("verbose")
.help("Sets verbosity level")
.multiple(true),
)
.get_matches();
if matches.occurrences_of("verbose") > 0 {
// clap is using i64, viperus i32
let n = matches.occurrences_of("verbose") as i32;
v.add("verbose", n);
}
// preset the prefix for relevant environment variables ("ADVOTRACKER_")
let mut env_prefix: String = crate_name!().to_uppercase();
env_prefix.push_str("_");
v.set_env_prefix(&env_prefix);
// respect dotenv environment (e.g for testing)
// -> overwrites the preset default values
println!(
"RUST_LOG={}",
dotenv::var("RUST_LOG").unwrap_or_else(|_| String::from("None"))
);
// enable caching and automatic update of environment values
v.cache(true);
v.automatic_env(true);
// load user selected call arguments
// -> overwrites values given via environment variables
v.load_clap(matches)?;
// bond the clap names to camel_case rust variable names
v.bond_clap("configFile", "config_file");
v.bond_clap("importFile", "import_file");
v.bond_clap("exportFile", "export_file");
v.bond_clap("toEmailAddress", "to_email_address");
v.bond_clap("fromEmailAddress", "from_email_address");
v.bond_clap("testPolicyNumber", "test_policy_number");
//v.bond_clap("username", "username");
//v.bond_clap("password", "password");
v.bond_clap("verbose", "verbose");
trace!("verbose {:?}", v.get::<i32>("verbose").unwrap());
if v.get::<i32>("verbose").unwrap() > 0 {
println!(
"config_file: {:?}",
v.get::<String>("config_file").unwrap_or_default()
);
println!(
"import_file: {:?}",
v.get::<String>("import_file").unwrap_or_default()
);
println!(
"export_file: {:?}",
v.get::<String>("export_file").unwrap_or_default()
);
println!(
"to_email_address: {:?}",
v.get::<String>("to_email_address").unwrap_or_default()
);
println!(
"from_email_address: {:?}",
v.get::<String>("from_email_address").unwrap_or_default()
);
println!(
"test_policy_number: {:?}",
v.get::<String>("test_policy_number").unwrap_or_default()
);
// println!(
// "username: {:?}",
// v.get::<String>("username").unwrap_or_default()
// );
// println!(
// "password: {:?}",
// v.get::<String>("password").unwrap_or_default()
// ); // only for testing now
println!(
"verbosity level: {:?}",
v.get::<i32>("verbose").unwrap_or_default()
);
}
if v.get::<i32>("verbose").unwrap() > 1 {
println!("\nEnvironment:");
for (key, value) in env::vars() {
println!("{}={}", key, value);
}
}
Ok(())
}

View File

@@ -1,124 +0,0 @@
use std::collections::HashMap;
//use std::sync::mpsc;
use orbtk::prelude::*;
use orbtk::shell::WindowRequest;
static ID_CHECK_POLICY_NUMBER: &'static str = "ID_CHECK_POLICY_NUMBER";
static ID_PROGRESS_BAR: &'static str = "ID_PROGRESS_BAR";
enum Action {
ParsePolicyNumber
}
#[derive(Default, AsAny)]
struct MainViewState {
action: Option<Action>,
progress_bar: Entity,
text_box: Entity,
progress_counter: f64
//records: HashMap::<String, String>,
//record_counter: u64
}
impl State for MainViewState {
fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
self.text_box = ctx.entity_of_child(ID_CHECK_POLICY_NUMBER).expect("Cannot get TextBox!");
self.progress_bar = ctx.entity_of_child(ID_PROGRESS_BAR).expect("Cannot get progress bar !");
}
fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
// if there is an action, process it
if let Some(action) = &self.action {
match action {
Action::ParsePolicyNumber => {
let value_to_parse = ctx.get_widget(self.text_box).get::<String16>("text").clone();
self.parse_policy_number(value_to_parse, ctx);
}
}
// Reset action
self.action = None;
}
}
}
impl MainViewState {
fn action(&mut self, action: Action) {
self.action = Some(action);
}
fn parse_policy_number(&mut self, _value: String16, ctx: &mut Context) {
self.import_csv(ctx);
}
fn import_csv(&mut self, ctx: &mut Context) {
// code to import csv file into a hashmap
// will read in number_of_records = 100%
// progress_counter should be incremented, if
// read_in_loop will reach next 10% -> self.progress_counter += 0.1
// now fire an event to update the widget
// question: how to fire up the event inside import_csv function,
// without the need to mute "ID_CHECK_POLICY_NUMBER" ?
// given code just increments, if you change "ID_CHECK_POLICY_NUMBER"
self.progress_counter += 0.1;
self.update_progress(ctx);
}
fn update_progress(&self, ctx: &mut Context) {
// create a mpsc::Sender<WindowRequest> object
let sender = ctx.window_sender();
let mut pgbar = ctx.get_widget(self.progress_bar);
pgbar.set::<f64>("val", self.progress_counter);
// redraw screen if sender has changed
// only way to trigger a redraw: create an event
sender.send(WindowRequest::Redraw).unwrap()
}
}
widget!(MainView<MainViewState>);
impl Template for MainView {
fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
self
.margin(32.0)
.child(
Stack::new()
.orientation("vertical")
.h_align("center")
.v_align("top")
.spacing(8.0)
.child(
TextBox::new()
.id(ID_CHECK_POLICY_NUMBER)
.water_mark("Mut value and type <Return>")
.on_activate(move |states, _entity| {
// you have to fire a new event to be able to get in the update() with access to Context
states.get_mut::<MainViewState>(id).action(Action::ParsePolicyNumber);
})
.build(ctx)
)
.child(
ProgressBar::new()
.id(ID_PROGRESS_BAR)
.build(ctx)
)
.build(ctx)
)
}
}
fn main() {
Application::new()
.window(|ctx| {
Window::new()
.title("incroment_progress_bar skeleton")
.position((100.0, 100.0))
.size(420.0, 730.0)
.resizeable(true)
.child(MainView::new().build(ctx))
.build(ctx)
})
.run();
}

View File

@@ -1,32 +0,0 @@
/*
* OrbTK - The Orbital Widget Toolkit
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
mod main_view;
mod receiver;
mod sender;
fn main() -> Result<(), Box<dyn std::error::Error>> {
// use this only if you want to run it as web application.
orbtk::initialize();
Application::new()
.window(|ctx| {
Window::new()
.name("Main")
.title("OrbTK: example send/receive messages")
.position((100.0, 100.0))
.resizeable(true)
.size(450.0, 500.0)
.child(main_view::MainView::new().build(ctx))
.build(ctx)
})
.run();
Ok(())
}

View File

@@ -1,48 +0,0 @@
/*
* OrbTK - The Orbital Widget Toolkit
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use crate::{
receiver::receiver_view::ReceiverView,
sender::sender_view::SenderView,
};
// constants
pub static ID_SENDER_VIEW: &str = "sender_view";
pub static ID_RECEIVER_VIEW: &str = "receiver_view";
widget!(MainView {
//sender_view: ,
//receiver_view:
});
impl Template for MainView {
fn template(self, _id: Entity, ctx: &mut BuildContext<'_>) -> Self {
let receiver_view = ReceiverView::new()
.build(ctx);
let sender_view = SenderView::new()
.target(receiver_view.0) // entity of the target
.build(ctx);
self.name("MainView")
.child(
Stack::new()
.orientation("vertical")
.child(sender_view)
.child(receiver_view)
.build(ctx)
)
// .child(
// TabWidget::new()
// .tab(ID_SENDER_VIEW, SenderView::new().build(ctx))
// .tab(ID_RECEIVER_VIEW, ReceiverView::new().build(ctx))
// .build(ctx),
// )
}
}

View File

@@ -1,8 +0,0 @@
// The starting point (Main View).
pub mod main_view;
/// Receiver widget
pub mod receiver;
/// Sender widget.
pub mod sender;

View File

@@ -1,5 +0,0 @@
/// The reciever state
pub mod receiver_state;
/// The receiver view
pub mod receiver_view;

View File

@@ -1,70 +0,0 @@
/*
* OrbTK - The Orbital Widget Toolkit
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use crate::sender::sender_state::{SenderAction, SenderState};
/// Enumeration of valid `action variants` that need to be handled as
/// state changes for the `SenderView` widget.
pub enum TestMessageAction {
// Toggle visibility of a message TextBox.
ToggleMessageBox
}
/// Valid `structure members` of the `ReceiverState` used to react on
/// state changes inside the `ReceiverView` widget.
#[derive(Default, AsAny)]
pub struct ReceiverState {
message_box: Option<Entity>,
progress_bar: Entity
}
/// Method definitions, we provide inside the `ReceiverState`.
impl ReceiverState {
fn toggle_message_box(&self, ctx: &mut Context) {
if let Some(message_box) = self.message_box {
ctx.get_widget(message_box)
.set("visibility", Visibility::Visible);
}
}
}
/// Trait methods provided for the `SenderState`
impl State for ReceiverState {
// initialize the view entities
fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
self.progress_bar = ctx.entity_of_child("progress_bar")
.expect("Cannot find ProgressBar!");
}
// handle messages targeting the view
fn messages(
&mut self,
mut messages: MessageReader,
_registry: &mut Registry,
ctx: &mut Context
) {
for message in messages.read::<SenderAction>() {
match message {
SenderAction::UpdateProgress(amount) => {
println!("Message received");
let mut progress_bar = ctx.get_widget(self.progress_bar);
let current_progress = progress_bar.clone::<f64>("val");
progress_bar.set::<f64>("val", current_progress + amount);
}
}
}
for action in messages.read::<TestMessageAction>() {
match action {
TestMessageAction::ToggleMessageBox => {
self.toggle_message_box(ctx);
}
}
}
}
}

View File

@@ -1,37 +0,0 @@
/*
* OrbTK - The Orbital Widget Toolkit
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use crate::receiver::receiver_state::{TestMessageAction, ReceiverState};
widget!(ReceiverView<ReceiverState>);
impl Template for ReceiverView {
fn template(self, _id: Entity, bc: &mut BuildContext) -> Self {
self.name("ReceiverView")
.child(
Stack::new()
.orientation("vertical")
.spacing(16)
.child(
ProgressBar::new()
.id("progress_bar")
.build(bc)
)
.child(
TextBox::new()
.id("message_box")
.h_align("center")
.text("message received. Box toggled!")
.visibility("hidden")
.build(bc)
)
.build(bc)
)
}
}

View File

@@ -1,5 +0,0 @@
/// The sender state
pub mod sender_state;
/// The sender view
pub mod sender_view;

View File

@@ -1,58 +0,0 @@
/*
* OrbTK - The Orbital Widget Toolkit
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
/// Enumeration of valid `action variants` that need to be handled as
/// state changes for the `SenderView` widget.
#[derive(Clone, Debug)]
pub enum SenderAction {
UpdateProgress(f64),
}
/// Valid `structure members` of the `SenderState` used to react on
/// state changes inside the `SenderView` widget.
#[derive(AsAny, Default)]
pub struct SenderState {
// actions
actions: Vec<SenderAction>,
// entity that will receive the message
target: Entity
}
/// Method definitions, we provide inside the `SenderState`.
impl SenderState {
/// Sending message 'UpdateProgress'
pub fn send_message(&mut self) {
println!("Sender: push 'UpdateProgress' action");
self.actions.push(SenderAction::UpdateProgress(0.1));
}
}
/// Trait methods provided for the `SenderState`
impl State for SenderState {
// initialize the view entities
fn init(&mut self, _registry: &mut Registry, ctx: &mut Context) {
// create the target entity, that receives the Sender messages
self.target = Entity::from(ctx.widget().try_clone::<u32>("target")
.expect("ERROR: SenderState::init(): target entity not found!"));
}
// update entities, before we render the view
fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
let actions: Vec<SenderAction> = self.actions.drain(..).collect();
for action in actions {
match action {
SenderAction::UpdateProgress(amount) => {
ctx.send_message(SenderAction::UpdateProgress(amount), self.target);
println!("Sender: send message 'SenderAction::UpdateProgress'");
}
}
}
}
}

View File

@@ -1,34 +0,0 @@
/*
* OrbTK - The Orbital Widget Toolkit
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use crate::sender::sender_state::{SenderAction, SenderState};
widget!(SenderView<SenderState> {
// the Entity of the widget that will receive the messages
target: u32
});
impl Template for SenderView {
fn template(self, id: Entity, bc: &mut BuildContext) -> Self {
self.name("SenderView")
.child(
Button::new()
.text("Click me to send a message!")
.v_align("center")
.h_align("center")
.on_click(move |states, _entity| {
states.get_mut::<SenderState>(id).send_message();
//states.send_message(SenderAction::UpdateProgress, id);
//ctx.send_message(TestMessageAction::ToggleMessageBox, id);
false
})
.build(bc)
)
}
}

View File

@@ -1,206 +0,0 @@
use orbtk::prelude::*;
// fn get_theme() -> ThemeValue {
// //ThemeValue::create_from_css(LIGHT_THEME_EXTENSION_CSS)
// ThemeValue::create_from_css(DEFAULT_THEME_CSS)
// .extension_css(WIDGET_EXT)
// .build()
// }
#[derive(Debug, Copy, Clone)]
enum Action {
EntryActivated(Entity),
EntryChanged(Entity)
}
#[derive(AsAny)]
pub struct MainViewState {
action: Option<Action>,
}
impl Default for MainViewState {
fn default() -> Self {
MainViewState { action: None }
}
}
impl MainViewState {
fn action(&mut self, action: impl Into<Option<Action>>) {
self.action = action.into();
}
}
impl State for MainViewState {
fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
if let Some(action) = self.action {
match action {
// Action::ClearText => {
// ctx.widget().set("policynumber", String16::from(""));
// }
// Action::ValueOk => {
// //let mut text_box = TextBox::get(ctx.get_widget(entity));
// //let text = text_box.text_mut();
// //ctx.widget().set("policynumber", background("#4d4c4c"));
// }
// Action::ValueNone => {
// //let mut text_box = TextBox::get(ctx.get_widget(entity));
// //let text = text_box.text_mut();
// //ctx.widget().set("policynumber", background("#5b0f22"));
//}
Action::EntryActivated(entity) => {
//let text = ctx.get_widget(entity).clone::<String>("text");
let widget = ctx.get_widget(entity);
let text = widget.get::<String>("text");
println!("got value policynumber: {}", text);
}
Action::EntryChanged(entity) => {
let widget = ctx.get_widget(entity);
let text = widget.get::<String>("text");
println!("entry changed: {}", text);
}
}
self.action = None;
}
}
}
fn create_header(ctx: &mut BuildContext, text: &str) -> Entity {
TextBlock::new()
.text(text)
.style("header")
.build(ctx)
}
widget!(
MainView<MainViewState> {
sum_policynumbers: usize,
policynumber: String16,
result: String16
}
);
impl Template for MainView {
fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
self.name("MainView").child(
Grid::new()
.background("#fafafa")
.columns(
Columns::create()
.push(150.0)
.push("*")
.push(150.0)
.build(),
)
.rows(
Rows::create()
.push("*")
.push("*")
.build(),
)
.child(
Grid::new()
//.element("policyholder_check")
.margin((4.0, 24.0, 24.0, 4.0))
.min_width(180.0)
.min_height(80.0)
.attach(Grid::column(1))
.attach(Grid::row(0))
.child(
Stack::new()
.spacing(8.0)
.orientation("vertical")
.h_align("center")
//.child(create_header(ctx, "Validation number policyholder"))
.child(create_header(ctx, "Validierung Versicherungsnummer"))
.child(
TextBox::new()
.foreground("#9dafbf")
.background("#fafafa")
.border_brush("#5b0f22")
.border_width(5)
.border_radius(15)
//.name("policynumber")
.focused(true)
.water_mark("Versicherungs-Nr...")
.text(("policynumber", id))
.font_size(24.0)
.h_align("stretch")
.on_activate(move |ctx, entity| {
state(id, ctx).action(Action::EntryActivated(entity));
})
.on_changed("text", move |ctx, entity| {
state(id, ctx).action(Action::EntryChanged(entity));
})
.build(ctx),
)
.child(
TextBlock::new()
//.element("text-block")
.id("result")
.min_width(80.0)
.max_width(180.0)
//.text("Result:")
.text("Ergebnis:")
.build(ctx),
)
.build(ctx),
)
.build(ctx)
)
.child(
Grid::new()
//.class("logo_customer")
.margin((9.0, 16.0, 16.0, 9.0))
.attach(Grid::column(0))
.attach(Grid::row(1))
.v_align("end")
.child(
ImageWidget::new()
.image("assets/images/customer_logo.png")
.build(ctx),
)
.build(ctx),
)
.child(
Grid::new()
//.class("logo_vendor")
.margin((9.0, 16.0, 16.0, 9.0))
.attach(Grid::column(2))
.attach(Grid::row(1))
.v_align("end")
.child(
ImageWidget::new()
.image("assets/images/networkx_logo.png")
.build(ctx),
)
.build(ctx),
)
.build(ctx),
) // MainView
}
}
fn main() {
Application::new()
.window(|ctx| {
Window::new()
//.title("OrbTk - Policyholder checker example")
.name("MainWindow")
.title("AdvoTracker - Versicherungsnummern")
.position((-500.0, -100.0))
.size(480.0, 260.0)
.min_width(460.0)
.min_height(180.0)
.resizeable(true)
//.theme(get_theme())
.child(MainView::new().build(ctx))
.build(ctx)
})
.run();
}
// helper to request MainViewState
fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut MainViewState {
states.get_mut(id)
}

View File

@@ -1 +0,0 @@
../../resources

View File

@@ -1,13 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// provides orbtk widgets constants
pub mod constants;
/// structures with implementations
pub mod structures;

View File

@@ -1,364 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use chrono::NaiveDateTime;
use orbtk::prelude::*;
use serde::{Deserialize, Serialize};
/// An enumeration of valid policy codes.
/// right now, only "AS" is used.
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
pub enum PolicyCode {
/// Allianz Sachversicherung
AS
}
impl Default for PolicyCode {
fn default() -> Self { PolicyCode::AS }
}
/// Classifier of the Allinaz DirectCall communication type.
pub enum CommunicationType {
/// Anhörung
A,
/// Bußgeldbescheid
BU,
/// Gdb
Gdb,
/// Geburt
GE,
/// Hochzeit
HO,
/// Kündigung
KD,
/// Kaufvertrag
KV,
/// Lohn
LO,
/// Nachbar
NA,
/// Rente
RE,
/// Unfallflucht
UF,
/// Unterhalt
UH,
/// Unfall
UN,
/// Vodafone
VF,
/// Vermieter
VM,
/// Verwaltungsrecht
VW,
/// Zeugins
ZE,
/// Typ is unspecified
XX
}
impl Default for CommunicationType {
fn default() -> Self { CommunicationType::XX }
}
/// Status of a given policy data element.
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
pub enum Status {
/// Active -> the policy is active an supported
Active,
/// Inactive -> the policy is inactive or resigned
Inactive
}
impl Default for Status {
fn default() -> Self { Status::Active }
}
/// A communication type describes possible classifications of customer calls.
/// If the type isn't selected, the default will be 'unclassified -> XX'.
#[derive(Default, Deserialize, Serialize)]
pub struct CommunicationData {
/// pub communication_type: CommunicationType,
pub communication_type: String,
/// A literal name describing the selected communication type
pub communication_name: String
}
/// CSV Export
/// The structure elements are required for an export to a comma seperated text list.
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct CsvExportRecord {
/// Versicherungsschein Code
pub policy_code: String,
/// Versicherungsscheinnummer (10-stellig, numerisch)
pub policy_number: u64,
/// Anrufer: "Vorname, Nachname"
pub policy_holder: String,
/// Sachverhalt: "Kurzschilderung"
pub facts: String,
/// Schadensart: "harm_name (harm_id)"
pub harm_type: String,
/// communication_type => Kommunikationszeichen: "(communication_name)"
pub communication_name: String,
/// ra_hotline => RA_Hotline: Kanzlei Laqua, Kanzlei Buschbell, Kanzlei DAH, Kanzlei Hiedemann
pub ra_hotline: String, // const "Kanzlei Hiedemann",
/// ivr_comment => Haftungs-/Deckungskommentar; #IVR (ggf. ergänzt um das Beratungsergebnis)
pub ivr_comment: String,
}
/// Handel fields of an Email (header, body)
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct Email {
/// Recipient address
pub mail_to: String,
/// Carbon Copy recipient address
pub mail_cc: String,
/// Blind Carbon Copy recipient address
pub mail_bcc: String,
/// Sender address
pub mail_from: String,
/// Replay to given address
pub mail_reply: String,
/// Mail subject
pub subject: String,
/// Body policy code
pub policy_code: String,
/// Body type policy holder
pub policy_holder: String,
/// Body type deductible
pub deductible: String,
/// Body callback number
pub callback_number: String,
/// Body type callback date
pub callback_date: String,
/// Body type harm type
pub harm_type: String,
/// Body type ivr comment
pub ivr_comment: String
}
impl Email {}
/// Harm data are list/collections of harm types. You may toggle them to an unselected state.
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct HarmData {
/// Liste der Schadensdaten
pub harm_data: Vec<HarmType>,
/// Status der Schadenliste
//pub name: String,
pub selected: bool
}
/// Harm types are destincted by a type code.
/// The type code represents the unique harm identifier, bound with a literal name.
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct HarmType {
/// Kennzeichen des Schadenstyps
// Schadenersatz-RS im Verkehrsbereich (RS112)
// Ordnungswidrigkeits-RS im Verkehrsbereich (RS122)
// Straf-RS im Verkehrsbereich (RS121)
// Vertrags-RS im Verkehrsbereich (RS118)
// Vertrags-RS im Privatbereich (RS218)
// Arbeits-RS im Berufsbereich (RS315)
// WuG-RS im Privatbereich (RS220)
// Sozialgerichts-RS im Privatbereich (RS216)
// Rechtsschutz im Familien- und Erbrecht (RS217)
// Wagnis nicht versicherbar / versichert (RS999)
pub harm_type: String,
/// Beschreibung des Schadenstyps
pub harm_name: String,
}
/// Structure used to verify a policy data element.
#[derive(Default, Debug, Clone, Deserialize, PartialEq, Serialize)]
pub struct PolicyCheck {
/// Versicherungsschein-Prüfnummer
pub policy_check_number: String,
/// Referenz zum Versicherungsschein-Typ
pub dion: u8,
/// Referenz zum Versicherungsschein-Typ
pub policy_code: PolicyCode,
/// Referenz zur Versicherungsschein-Nummer
pub policy_number: u64,
/// Validitätsergebnis
pub policy_number_status: Status
}
impl PolicyCheck {}
/// Structure collecting policy data elements
#[derive(Default, Clone, Debug, Serialize, Deserialize)]
pub struct PolicyList {
/// Bescheibung der Versicherungsdatenliste
pub name: String,
/// Listenelemente der Versicherungsdatendaten
pub policy_list: Vec<PolicyDataList>,
}
/// implements helper methods, that manage lists of policy data collections
impl PolicyList {
/// Index auf Versicherungsliste zurückgeben (unveränderbar)
pub fn get(&self, index: usize) -> Option<&PolicyDataList> {
self.policy_list.get(index)
}
/// Index auf Versicherungsliste zurückgeben (veränderbar)
pub fn get_mut(&mut self, index: usize) -> Option<&mut PolicyDataList> {
self.policy_list.get_mut(index)
}
/// Neuer Eintrag am Anfang der Liste einfügen.
pub fn insert_front(&mut self, policy_list: PolicyDataList) {
self.policy_list.insert(0, policy_list);
}
/// Prüfung ob Versicherungsliste keine Elemente enthält.
pub fn is_empty(&self) -> bool {
self.policy_list.is_empty()
}
/// Berechnet die Anzahl der Versicherungslisten Elemente.
pub fn len(&self) -> usize {
self.policy_list.len()
}
/// Neuen Versicherungslisten-Namen erzeugen
pub fn new(name: impl Into<String>) -> Self {
PolicyList {
name: name.into(),
..Default::default()
}
}
/// Element der Versicherungsliste anfügen
pub fn push(&mut self, policy_list: PolicyDataList) {
self.policy_list.push(policy_list);
}
/// Element der Versicherungsliste löschen
pub fn remove(&mut self, index: usize) -> PolicyDataList {
self.policy_list.remove(index)
}
}
/// Structure collects policy data elements.
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct PolicyDataList {
/// Verfalldatum des Versicherungslisten Elements
pub date_valid_until: Option<NaiveDateTime>,
/// Elemente des Versicherungsobjektes
pub policy_data: Vec<PolicyData>,
/// Name der Versicherungsliste
pub name: String,
/// Status der Versicherungsliste
pub selected: bool
}
/// implements the helper methods, to manage policy data collections.
impl PolicyDataList {
/// Prüfung auf Versicherungselemente
pub fn is_empty(&self) -> bool {
self.policy_data.is_empty()
}
/// Versicherungselement am Anfang anfügen
pub fn insert_front(&mut self, policy_data: PolicyData) {
self.policy_data.insert(0, policy_data);
}
/// Index zum Versicherungselement zurückgeben (unveränderbar)
pub fn get(&self, index: usize) -> Option<&PolicyData> {
self.policy_data.get(index)
}
/// Index zum Versicherungselement zurückgeben (veränderbar)
pub fn get_mut(&mut self, index: usize) -> Option<&mut PolicyData> {
self.policy_data.get_mut(index)
}
/// Berechnet die Anzahl der Versicherungselemente.
pub fn len(&self) -> usize {
self.policy_data.len()
}
/// Neues Versicherungselement erstellen.
pub fn new(name: impl Into<String>) -> Self {
// the new inserted element will be active by default
PolicyDataList {
date_valid_until: None,
name: name.into(),
selected: true,
..Default::default()
}
}
/// Versicherungselement anfügen
pub fn push(&mut self, policy_data: PolicyData) {
self.policy_data.push(policy_data);
}
/// Versicherungselement löschen
pub fn remove(&mut self, index: usize) -> PolicyData {
self.policy_data.remove(index)
}
}
/// Structure representing a policy data element
/// This structure groups a set of fields that describes a policy number.
/// The data are regularily updated via a data import from a comma seperated
/// text file (csv file).
/// Since we parse the source record fields to rust types (serde deserialize)
/// the field order in our struct must meet the data field order in the source!
/// We do use field attribute to precisely rename the source fields (header names)
/// to our target rust field names.
/// Referenz: POLLFNR_WOECHENTLICH.txt ->
/// Header 'DION VERS POLLFNR'
/// Record '1 AS 1515735810'
// DION: Allianz id => len = 1??
// VERS: policy_code => enum(AS; ??)
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct PolicyData {
/// Erstellungsdatum
pub date_inserted: Option<NaiveDateTime>,
/// Allianz Dion
#[serde(rename = "DION")]
pub dion: u8,
/// Kennzeichen des Allianz Versicherungscodes
#[serde(rename = "VERS")]
pub policy_code: PolicyCode,
/// Versicherungsscheinnummer (10stellig, numerisch)
#[serde(rename = "POLLFNR")]
pub policy_number: u64,
/// Status des Versicherungsscheins
pub status: Option<Status>
}
/// Policy Number Set
#[derive(Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
pub struct AllianzPolicyNumber {
/// Allianz Dion
#[serde(rename = "DION")]
pub dion: u8,
/// Kennzeichen des Allianz Versicherungstyps
#[serde(rename = "VERS")]
pub policy_code: String,
/// 10-stellige Versicherungsscheinnummer (numerisch)
#[serde(rename = "POLLFNR")]
pub policy_number: usize
}
// /// List of Allianz Policy Number records
// /// The structure elements are required for an export to a comma seperated text list.
// #[derive(Default, Debug, Deserialize)]
// pub struct AllianzPolicyNumberList {
// records: Vec<AllianzPolicyNumber>
// }
into_property_source!(PolicyCheck);
into_property_source!(PolicyDataList);
into_property_source!(PolicyList);

View File

@@ -1,248 +0,0 @@
{
"err.lang.not_found": {
"de_DE.UTF-8": "Konnte Sprachkode nicht auslesen",
"de_DE": "Konnte Sprachkode nicht auslesen",
"C": "Couldn't read LANG"
},
"err.user.not_found": {
"fr": "Utilisateur introuvable: $email, $id",
"de_DE.UTF-8": "Anwender nicht gefunden: $email, $id",
"de_DE": "Anwender nicht gefunden: $email, $id",
"C": "User not found: $email, $id"
},
"main.started": {
"de_DE.UTF-8": "Programmlogik starten",
"de_DE": "Programmlogik starten",
"C": "Program logic started"
},
"main.finished": {
"de_DE.UTF-8": "Programmlogik beendet",
"de_DE": "Programmlogik beendet",
"C": "Program logic finished"
},
"parse.arguments": {
"de_DE.UTF-8": "Programmargumente prüfen",
"de_DE": "Programmargumente prüfen",
"C": "Parsing arguments"
},
"parse.environment": {
"de_DE.UTF-8": "Umgebungsvariablen prüfen",
"de_DE": "Umgebungsvariablen prüfen",
"C": "Parsing environment"
},
"parse.results": {
"de_DE.UTF-8": "Ergebnisse der Konfigurations-Parameterprüfung",
"de_DE": "Ergebnisse der Konfigurationsparameterprüfung",
"C": "Config parsing results"
},
"config.name": {
"de_DE.UTF-8": "Konfigurationswert für",
"de_DE": "Konfigurationswert für",
"C": "Config Value for"
},
"config.name.lang": {
"de_DE.UTF-8": "Sprach-Code_DE",
"de_DE": "Sprach-Code_DE",
"C": "Language code_DE"
},
"config.name.verbositylevel": {
"de_DE.UTF-8": "Ausgabe-Ebene",
"de_DE": "Ausgabe-Ebene",
"C": "verbosity level"
},
"config.name.environment": {
"de_DE.UTF-8": "Umgebungsvariablen",
"de_DE": "Umgebungsvariablen",
"C": "environment"
},
"config.name.configfile": {
"de_DE.UTF-8": "Konfigurations-Datei",
"de_DE": "Konfigurations-Datei",
"C": "config file"
},
"config.name.dbdriver": {
"de_DE.UTF-8": "Datenbank-Treiber",
"de_DE": "Datenbank-Treiber",
"C": "database driver"
},
"config.name.redis": {
"de_DE.UTF-8": "Redis Datenbank",
"de_DE": "Redis Datenbank",
"C": "Redis database"
},
"csv.export.started": {
"de_DE.UTF-8": "Export in eine CSV Datei starten",
"de_DE": "Export in eine CSV Datei starten",
"C": "Export to csv file started"
},
"csv.export.finished": {
"de_DE.UTF-8": "Export in eine CSV Datei beendet",
"de_DE": "Export in eine CSV Datei beendet",
"C": "Export to csv file finished"
},
"csv.import.started": {
"de_DE.UTF-8": "Import aus einer CSV Datei",
"de_DE": "Import aus einer CSV Datei",
"C": "Import from a csv file"
},
"csv.import.finished": {
"de_DE.UTF-8": "Import aus einer CSV Datei beendet",
"de_DE": "Import aus einer CSV Datei beendet",
"C": "Import from a csv file finished"
},
"redis.connection.error": {
"de_DE.UTF-8": "Es konnte keine Redis Verbindung aufgebaut werden",
"de_DE": "Es konnte keine Redis Verbindung aufgebaut werden",
"C": "Could not establish a redis connection"
},
"policy.hashmap.success": {
"de_DE.UTF-8": "Hashmap wurde erfolgreich erstellt",
"de_DE": "Hashmap wurde erfolgreich erstellt",
"C": "Hashmap creation was successfull"
},
"policy.hashmap.failed": {
"de_DE.UTF-8": "Hashmap konnte nicht erstellt werden",
"de_DE": "Hashmap konnte nicht erstellt werden",
"C": "Hashmap creation failed"
},
"policy.menu.label": {
"de_DE.UTF-8": "Menü",
"de_DE": "Menü",
"C": "Menu"
},
"policy.menu.label_account": {
"de_DE.UTF-8": "Aktueller Benutzer",
"de_DE": "Aktueller Benutzer",
"C": "Active user"
},
"policy.menu.label_quit": {
"de_DE.UTF-8": "Beenden",
"de_DE": "Beenden",
"C": "Quit"
},
"policy.menu.label_toggle_theme": {
"de_DE.UTF-8": "Thema wechseln",
"de_DE": "Thema wechseln",
"C": "Toggle theme"
},
"policy.string.header": {
"de_DE.UTF-8": "Validierung Versicherungsnummer",
"de_DE": "Validierung Versicherungsnummer",
"C": "Policy number validation"
},
"policy.string.label_policy_data": {
"de_DE.UTF-8": "Importierte Daten",
"de_DE": "Importierte Daten",
"C": "imported data"
},
"policy.string.label_policy_list": {
"de_DE.UTF-8": "Versicherungsnummern-Liste",
"de_DE": "Versicherungsnummern-Liste",
"C": "policy list"
},
"policy.string.label_policy_number": {
"de_DE.UTF-8": "Versicherungsnummer",
"de_DE": "Versicherungsnummer",
"C": "policy number"
},
"policy.string.label_result": {
"de_DE.UTF-8": "Prüfungsergebnis",
"de_DE": "Prüfungsergebnis",
"C": "check result"
},
"policy.string.data_count": {
"de_DE.UTF-8": "Anzahl Prüflistenelemente",
"de_DE": "Anzahl Prüflistenelemente",
"C": "Number of checklist elements"
},
"policy.string.import_data": {
"de_DE.UTF-8": "Importieren der Prüflisten-Elemente",
"de_DE": "Importieren der Prüflisten-Elemente",
"C": "Import checklist elements"
},
"policy.string.progress_time": {
"de_DE.UTF-8": "Bearbeitungszeit",
"de_DE": "Bearbeitungszeit",
"C": "processing time"
},
"policy.string.progress_text": {
"de_DE.UTF-8": "Importiere Daten",
"de_DE": "Importiere Daten",
"C": "Importing data"
},
"policy.validation.button_failed": {
"de_DE.UTF-8": "ungültig",
"de_DE": "ungültig",
"C": "invalid"
},
"policy.validation.button_success": {
"de_DE.UTF-8": "gültig",
"de_DE": "gültig",
"C": "valid"
},
"policy.validation.failed": {
"de_DE.UTF-8": "Die Versicherungsscheinnummber ist ungültig",
"de_DE": "Die Versicherungsscheinnummber ist ungültig",
"C": "The given policy number is invalid"
},
"policy.validation.new": {
"de_DE.UTF-8": "Neue Prüfung",
"de_DE": "Neue Prüfung",
"C": "New validation"
},
"policy.validation.success": {
"de_DE.UTF-8": "Die Versicherungsscheinnummber ist gültig",
"de_DE": "Die Versicherungsscheinnummber ist gültig",
"C": "The given policy number is valid"
},
"policy.validation.started": {
"de_DE.UTF-8": "Die Prüfung der Versicherungsscheinnummber wurde gestartet",
"de_DE": "Die Prüfung der Versicherungsscheinnummber wurde gestartet",
"C": "Validation of the policy number started"
},
"policy.validation.finished": {
"de_DE.UTF-8": "Die Prüfung der Versicherungsscheinnummber wurde beendet",
"de_DE": "Die Prüfung der Versicherungsscheinnummber wurde beendet",
"C": "Validation of the policy number finished"
},
"policy.validation.invalid_input": {
"de_DE.UTF-8": "Nur Nummer sind zulässig",
"de_DE": "Nur Nummer sind zulässig",
"C": "Only numbers are valid"
},
"policy.validation.not_found": {
"de_DE.UTF-8": "Nummer ist nicht aktiviert",
"de_DE": "Nummer ist nicht aktiviert",
"C": "number isn't marked active"
},
"policy.validation.to_long": {
"de_DE.UTF-8": "Die Nummer ist zu lang",
"de_DE": "Die Nummer ist zu lang",
"C": "Policy number is to long"
},
"policy.validation.to_short": {
"de_DE.UTF-8": "Die Nummer ist zu kurz",
"de_DE": "Die Nummer ist zu kurz",
"C": "Policy number is to short"
},
"sendticketdata.export.started":{
"de_DE.UTF-8": "Versenden von ticket daten via eMail gestartet",
"de_DE": "Versenden von ticket daten via eMail gestartet",
"C": "Send ticket data via eMail started"
},
"sendticketdata.export.finished":{
"de_DE.UTF-8": "Versenden von ticket daten via eMail beendet",
"de_DE": "Versenden von ticket daten via eMail beendet",
"C": "Send ticket data via eMail finished"
},
"state.started": {
"de_DE.UTF-8": "gestartet",
"de_DE": "gestartet",
"C": "started"
},
"state.finished": {
"de_DE.UTF-8": "beendet",
"de_DE": "beended",
"C": "finished"
}
}

View File

@@ -1,225 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
// suppress creation of a new console window on window
#![windows_subsystem = "windows"]
//#[macro_use]
//extern crate lazy_static;
//use chrono::{Local, DateTime};
use dotenv::dotenv;
use locales::t;
use cfg_if::cfg_if;
use serde::Deserialize;
use std::env;
//use std::process;
use substring::Substring;
use tracing::{info, trace, Level};
use orbtk::{
prelude::*,
theme_default::{THEME_DEFAULT, THEME_DEFAULT_COLORS_DARK, THEME_DEFAULT_FONTS},
theming::config::ThemeConfig,
};
#[cfg(target_os = "windows")]
use orbtk::theme_fluent::{THEME_FLUENT, THEME_FLUENT_COLORS_DARK, THEME_FLUENT_FONTS};
// The Main view
use advotracker::widgets::main_view;
mod parse_args;
/// 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 {
lang: String,
test_lang: String,
rust_log: String,
}
// Style extension
static DEFAULT_DARK_EXT: &str = include_str!("../assets/advotracker/default_dark.ron");
cfg_if! {
if #[cfg(windows)] {
static FLUENT_DARK_EXT: &str = include_str!("../assets/advotracker/fluent_dark.ron");
static FLUENT_LIGHT_EXT: &str = include_str!("../assets/advotracker/fluent_light.ron");
}
}
// German localization file.
static ADVOTRACKER_DE_DE: &str = include_str!("../assets/advotracker/advotracker_de_DE.ron");
/// Get the active language environment.
fn get_lang() -> String {
// get system environment
let mut lang = env::var("LANG").unwrap_or_else(|_| "C".to_string());
lang = lang.substring(0,5).to_string(); // "de_DE.UTF-8" -> "de_DE"
info!("GUI-Language: preset to {:?}", lang);
// 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) }
}
trace!(target: "advotracker", lang = ?lang);
// return the active language
lang
}
cfg_if! {
if #[cfg(windows)] {
/// Extend and register theme assets.
fn theme() -> Theme {
register_default_fonts(Theme::from_config(
ThemeConfig::from(DEFAULT_DARK_EXT)
.extend(ThemeConfig::from(THEME_DEFAULT))
.extend(ThemeConfig::from(THEME_DEFAULT_COLORS_DARK))
.extend(ThemeConfig::from(THEME_DEFAULT_FONTS)),
))
}
fn theme_fluent() -> Theme {
register_fluent_fonts(Theme::from_config(
ThemeConfig::from(FLUENT_DARK_EXT)
.extend(ThemeConfig::from(THEME_FLUENT))
.extend(ThemeConfig::from(THEME_FLUENT_COLORS_DARK))
.extend(ThemeConfig::from(THEME_FLUENT_FONTS)),
))
// register_fluent_fonts(Theme::from_config(
// ThemeConfig::from(FLUENT_LIGHT_EXT)
// .extend(ThemeConfig::from(THEME_FLUENT))
// .extend(ThemeConfig::from(THEME_FLUENT_COLORS_DARK))
// .extend(ThemeConfig::from(THEME_FLUENT_FONTS)),
}
} else {
/// Extend and register theme assets.
fn theme() -> Theme {
register_default_fonts(Theme::from_config(
ThemeConfig::from(DEFAULT_DARK_EXT)
.extend(ThemeConfig::from(THEME_DEFAULT))
.extend(ThemeConfig::from(THEME_DEFAULT_COLORS_DARK))
.extend(ThemeConfig::from(THEME_DEFAULT_FONTS)),
))
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
use parse_args::parse_args;
use tracing_subscriber::fmt;
use viperus::Viperus;
let machine_kind = if cfg!(unix) {
"unix"
} else if cfg!(windows) {
"windows"
} else {
"unknown/unsupported"
};
// respect dotenv environment (e.g for testing)
// -> overwrites the preset default values
let rust_log = dotenv::var("RUST_LOG").unwrap_or_else(|_| String::from("None"));
// initialize the tracing subsystem
// a drop in replacement for classical logging
// reference: https://tokio.rs/blog/2019-08-tracing/
let span = tracing::span!(Level::TRACE, "advotracker");
let _enter = span.enter();
let subscriber = fmt::Subscriber::builder()
.with_env_filter(&rust_log)
//.with_max_level(tracing::Level::DEBUG)
.finish();
tracing::subscriber::with_default(subscriber, || {
// get system environment
let lang = get_lang();
let mut state = t!("state.started", lang);
let mut res = t!("parse.environment", lang);
trace!(target: "advotracker", process = ?res, state = ?state);
trace!(target: "advotracker", environment = "system", lang = ?lang);
trace!(target: "advotracker", machine = ?&machine_kind);
// how to handle unimplemented lang resources??
res = t!("parse.environment", lang);
trace!(target: "advotracker", environment = "envy", lang = ?lang);
state = t!("state.finished", lang);
trace!(target: "advotracker", process = ?res, state = ?state);
// initialize viperus structure
let mut viperus = Viperus::new();
// parse commandline arguments
res = t!("parse.arguments", lang);
state = t!("state.started", lang);
trace!(target: "advotracker", process = ?res, state = ?state);
let _ = parse_args(&mut viperus);
state = t!("state.finished", lang);
trace!(target: "advotracker", process = ?res, state = ?state);
// type conversion (viperus String -> u64)
let test_policy_number = viperus.get::<String>("test_policy_number").unwrap().parse::<u64>().unwrap();
trace!(target: "advotracker", test_policy_number = ?test_policy_number);
// main tasks
res = t!("main.started", lang);
state = t!("state.started", lang);
trace!(target: "advotracker", process = ?res, state = ?state);
// use this only if you want to run it as web application.
orbtk::initialize();
// Preset localization and language from given environment.
// if no dictionary is set for the chosen default language
// the content of the text property will be drawn.
//let language = lang.substring(0,5); // "de_DE.UTF-8" -> "de_DE"
//info!("GUI-Language: preset to {:?}", language);
let localization = RonLocalization::create()
.language(&lang)
.dictionary("de_DE", ADVOTRACKER_DE_DE)
.build();
Application::from_name("nwx.advotracker")
.localization(localization)
.theme(theme())
.window(|ctx| {
Window::new()
.title("AdvoTracker - DirectCall")
.position((500.0, 100.0))
.size(800.0, 600.0)
//.min_width(460.0)
//.min_height(380.0)
.resizeable(true)
.child(main_view::MainView::new().build(ctx))
.build(ctx)
})
.run();
state = t!("state.finished", lang);
res = t!("main.finished", lang);
trace!(target: "advotracker", process = ?res, state = ?state);
});
Ok(())
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}

View File

@@ -1,213 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
// parse CLI commandline arguments with clap
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
//use log::{debug, info, trace, warn};
use std::env;
use tracing::trace;
use viperus::Viperus;
/// Parse the commandline arguments and preset default values
/// Precedence: defaults -> config-file -> environment -> commandline
pub fn parse_args(viperus: &mut Viperus) -> Result<(), Box<dyn std::error::Error>> {
if cfg!(feature = "global") {
trace!(target: "Viperus", "Viperus feature 'global' enabled.");
println!("Lasy static: 'VIPERUS' is accessible globaly");
}
if cfg!(feature = "fmt-clap") {
trace!(target: "Viperus", "Viperus feature 'fmt-clap' enabled.");
println!("Using feature fmt-clap");
}
// preset default key/value pairs (lowest priority)
viperus.add_default("config_file", String::from("csv_import.ron"));
viperus.add_default("import_file", String::from("POLLFNR_WOECHENTLICH.txt"));
viperus.add_default("export_file", String::from(""));
viperus.add_default("test_policy_number", String::from("9999999992"));
viperus.add_default("to_email_address_file", String::from("Allianz RA-Hotline <smr-rahotline@allianz.de>"));
viperus.add_default("from_email_address_file", String::from("Allianz-Hotline RA-Hiedemann <azhotline@hiedemann.de>"));
//viperus.add_default("username", String::from("nctalkbot"));
//viperus.add_default("password", String::from("botpassword"));
viperus.add_default("verbose", 0);
// CLI arguments are defined inline
let matches = App::new("advotracker")
.name(crate_name!())
.version(crate_version!())
.author(crate_authors!())
.about(crate_description!())
.after_help("
Testprogramm: Allianz Online-Beratung Im/Export CSV-Daten
Direct-Call via IVR-System (Interactive Voice Response)
SMR Deckungssummen-Prüfung: 089 92529 60211
SMR Unerledigt: 089 92529 60222")
.template(
"\
{bin} v{version}
{about}
{all-args}
(C) 2020 {author}
{after-help}",
)
.arg(
Arg::with_name("configFile")
.short("c")
.long("configFile")
.value_name("FILE")
.help("Select a config file")
.default_value("csv_import.ron")
.takes_value(true),
)
.arg(
Arg::with_name("importFile")
.short("i")
.long("importFile")
.help("Select source file for the csv-import")
.default_value("POLLFNR_WOECHENTLICH.txt")
//.default_value("POLLFNR_MINI.txt")
.takes_value(true),
)
.arg(
Arg::with_name("exportFile")
.short("e")
.long("exportFile")
.help("Select target file for the csv-export")
.default_value("RA-Hiedemann_DirectCall.txt")
.takes_value(true),
)
.arg(
Arg::with_name("fromEmailAddress")
.short("f")
.long("fromEmailAddress")
.help("Select the sender email-address (From:)")
.default_value("Allianz-Hotline RA-Hiedemann <azhotline@hiedemann.de>")
.takes_value(true),
)
.arg(
Arg::with_name("toEmailAddress")
.short("t")
.long("toEmailAddress")
.help("Select the target email-address (To:)")
.default_value("Allianz RA-Hotline <smr-rahotline@allianz.de>")
.takes_value(true),
)
.arg(
Arg::with_name("testPolicyNumber")
.short("p")
.long("testPolicyNumber")
.help("Test validity of given policy number")
//.default_value("")
.takes_value(true),
)
// .arg(
// Arg::with_name("username")
// .short("u")
// .long("username")
// .help("Sets username")
// .takes_value(true),
// )
// .arg(
// Arg::with_name("password")
// .short("P")
// .long("password")
// .help("Sets password")
// .takes_value(true),
// )
.arg(
Arg::with_name("verbose")
.short("v")
.long("verbose")
.help("Sets verbosity level")
.multiple(true),
)
.get_matches();
if matches.occurrences_of("verbose") > 0 {
// clap is using i64, viperus i32
let n = matches.occurrences_of("verbose") as i32;
viperus.add("verbose", n);
}
// preset the prefix for relevant environment variables ("ADVOTRACKER_")
let mut env_prefix: String = crate_name!().to_uppercase();
env_prefix.push('_');
viperus.set_env_prefix(&env_prefix);
// enable caching and automatic update of environment values
viperus.cache(true);
viperus.automatic_env(true);
// load user selected call arguments
// -> overwrites values given via environment variables
viperus.load_clap(matches)?;
// bond the clap names to camel_case rust variable names
viperus.bond_clap("configFile", "config_file");
viperus.bond_clap("importFile", "import_file");
viperus.bond_clap("exportFile", "export_file");
viperus.bond_clap("toEmailAddress", "to_email_address");
viperus.bond_clap("fromEmailAddress", "from_email_address");
viperus.bond_clap("testPolicyNumber", "test_policy_number");
//viperus.bond_clap("username", "username");
//viperus.bond_clap("password", "password");
viperus.bond_clap("verbose", "verbose");
trace!("verbose {:?}", viperus.get::<i32>("verbose").unwrap());
if viperus.get::<i32>("verbose").unwrap() > 0 {
println!(
"config_file: {:?}",
viperus.get::<String>("config_file").unwrap_or_default()
);
println!(
"import_file: {:?}",
viperus.get::<String>("import_file").unwrap_or_default()
);
println!(
"export_file: {:?}",
viperus.get::<String>("export_file").unwrap_or_default()
);
println!(
"to_email_address: {:?}",
viperus.get::<String>("to_email_address").unwrap_or_default()
);
println!(
"from_email_address: {:?}",
viperus.get::<String>("from_email_address").unwrap_or_default()
);
println!(
"test_policy_number: {:?}",
viperus.get::<i32>("test_policy_number").unwrap_or_default()
);
// println!(
// "username: {:?}",
// viperus.get::<String>("username").unwrap_or_default()
// );
// println!(
// "password: {:?}",
// viperus.get::<String>("password").unwrap_or_default()
// ); // only for testing now
println!(
"verbosity level: {:?}",
viperus.get::<i32>("verbose").unwrap_or_default()
);
}
if viperus.get::<i32>("verbose").unwrap() > 1 {
println!("\nEnvironment:");
for (key, value) in env::vars() {
println!("{}={}", key, value);
}
}
Ok(())
}

View File

@@ -1,37 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
//use chrono::{Local, DateTime};
use locales::t;
use std::error::Error;
use tracing::trace;
/// export as csv format
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
/// https://blog.burntsushi.net/csv/
pub fn export(p: &mut String, lang: &str) -> Result<(), Box<dyn Error>> {
use std::fs::File;
use std::path::Path;
//use std::ffi::OsStr;
let mut res = t!("csv.export.started", lang);
let mut state = t!("state.started", lang);
trace!(target: "csv-export", process = ?res, state = ?state);
// Note: slash syntax also works on Windows!
let path = Path::new(p);
// open the file
let file = File::open(path)?;
trace!(target: "csv.export", extension = ?path.extension(), file = ?file);
state = t!("state.finished", lang);
res = t!("csv.export.finished", lang);
trace!(target: "csv-export", process = ?res, state = ?state);
Ok(())
}

View File

@@ -1,12 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// Send ticketdata via email
pub mod send_ticketdata;
/// Exporting Allianz DirecCall data
pub mod allianzdirectcall;

View File

@@ -1,122 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use lettre::{
message::{header, MultiPart, SinglePart},
Message, SmtpTransport, Transport,
transport::smtp::authentication::Credentials,
};
use locales::t;
use maud::html;
use std::error::Error;
//use std::process;
use tracing::{info, error, trace};
use crate::data::structures::Email;
/// send ticket data via eMail
pub fn sendticketdata(email: &Email, lang: &str) -> Result<(), Box<dyn Error>> {
let mut res = t!("sendticketdata.export.started", lang);
let mut state = t!("state.started", lang);
trace!(target: "sendticketdata", process = ?res, state = ?state);
// The html we want to send.
// It uses https://crates.io/crates/maud
let html = html! {
head {
title { (email.subject) " (" (email.policy_code) ")" }
style type="text/css" {
"h2, h4 { font-family: Arial, Helvetica, sans-serif; }"
}
}
div style="display: flex; flex-direction: column; align-items: center;" {
// compose with variables and strings
h2 { (email.subject) " (" (email.policy_code) ")" }
p { "Vers.-Schein/Schadennummer: " (email.policy_code) }
p { "Versicherungsnehmer: " (email.policy_holder) }
p { "Selbstbehalt: "(email.deductible) }
p { "Rückrufnummer: " (email.callback_number) }
p { "Erreichbarkeit: " (email.callback_date) }
p { "Rechtsproblem: "(email.harm_type) }
p { "Rechtsrat: "(email.ivr_comment) }
}
};
let ascii_body = String::new()
+ &"Vers.-Schein/Schadennummer".to_string() + &(email.policy_code) + &"\n"
+ &"Versicherungsnehmer: ".to_string() + &(email.policy_holder) + &"\n"
+ &"Selbstbehalt: ".to_string() + &(email.deductible) + &"\n"
+ &"Rückrufnummer: ".to_string()+ &(email.callback_number) + &"\n"
+ &"Erreichbarkeit: ".to_string() + &(email.callback_date) + &"\n"
+ &"Rechtsproblem: ".to_string() + &(email.harm_type) + &"\n"
+ &"Rechtsrat: ".to_string() + &(email.ivr_comment) + &"\n";
info!("email body: {:?}", ascii_body);
let message = Message::builder()
//.reply_to("Kanzlei Hiedemann <info@hiedemann.de>".parse().unwrap())
.to("Kanzlei Hiedemann <info@hiedemann.de>".parse().unwrap())
.cc(" <ralf.zerres@networkx.de>".parse().unwrap())
.reply_to((email.mail_reply).parse().unwrap())
//.to((email.mail_to).parse().unwrap())
//.cc((email.mail_cc).parse().unwrap())
//.bcc((email.mail_bcc).parse().unwrap())
.from((email.mail_from).parse().unwrap())
.subject(String::new()
+ &email.subject.to_string()
+ &" (".to_string()
+ &email.policy_code.to_string()
+ &")".to_string()
)
.multipart(
MultiPart::alternative() // This is composed of two parts.
.singlepart(
SinglePart::builder()
.header(header::ContentType(
"text/plain; charset=utf8".parse().unwrap(),
))
.body(String::from(ascii_body)),
)
.singlepart(
SinglePart::builder()
.header(header::ContentType(
"text/html; charset=utf8".parse().unwrap(),
))
.body(html.into_string()),
),
)
.expect("failed to build email");
info!("message: {:?}", message);
// Create credential for remote authentication (username, password)
// WIP: get credentials from config file / cli
let creds = Credentials::new("info@kanzlei.hiedemann.de".to_string(), "17info67$".to_string());
// Open a remote connection to relay server (port 2525)
// WIP: get relay address from config file / cli
let mailer = SmtpTransport::relay("hiedemannsbs.kanzlei.hiedemann.de")
.unwrap()
.credentials(creds)
.build();
// Send the email
match mailer.send(&message) {
Ok(_) => info!("Email sent successfully!"),
Err(e) => error!("Could not send email: {:?}", e),
}
trace!(target: "sendticketdata", email = ?email);
state = t!("state.finished", lang);
res = t!("sendticketdata.export.finished", lang);
trace!(target: "sendticketdata", process = ?res, state = ?state);
Ok(())
}

View File

@@ -1,133 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use chrono::{Local, DateTime};
use locales::t;
use std::error::Error;
use std::collections::HashMap;
use std::time::{Duration, SystemTime};
use tracing::trace;
//use crate::db::redis;
use crate::data::structures::{PolicyCode, PolicyDataList, PolicyData};
//use crate::data::structures::PolicyDataList;
/// import AllianzDirectCall data from a csv delimeted file
/// save records to redis backend
/// https://docs.rs/csv/1.1.3/csv/cookbook/index.html
/// https://blog.burntsushi.net/csv/
pub fn import(p: &mut String, data_list: &mut PolicyDataList,
policy_numbers: &mut HashMap<u64, PolicyCode>,
policy_data_count: &mut u64,
lang: &str)
-> Result<(u64, Duration), Box<dyn Error>> {
use std::fs::File;
use std::path::Path;
use std::ffi::OsStr;
let mut res = t!("csv.import.started", lang);
let mut state = t!("state.started", lang);
let time_start = SystemTime::now();
let datetime: DateTime<Local> = time_start.into();
trace!(target: "csv-import", process = ?res, state = ?state, date_start = ?datetime.to_string());
// Note: slash syntax also works on Windows!
let path = Path::new(p);
// must be a readable file
trace!(target: "csv-import", path = ?path);
assert_eq!(path.is_file(), true);
// only accept files with '.txt' extensions
let extension = path.extension();
assert_eq!(extension, Some(OsStr::new("txt")));
// open the file
let file = File::open(path)?;
trace!(target: "csv-import", extension = ?extension, file = ?file);
// Build the CSV reader
let mut csv_reader = csv::ReaderBuilder::new()
.has_headers(true)
.delimiter(b' ')
//.comment(Some(b'#'))
//.flexible(true)
.from_reader(file);
{
// We nest this call in its own scope because of lifetimes.
let headers = csv_reader.headers()?;
trace!(target: "csv-import", header = ?headers);
}
// Iterate over each record, deserialize und write to our structures
let mut count : u64 = 0;
for result in csv_reader.deserialize() {
// The iterator yields Result<StringRecord, Error>, so we check the
// error here.
let record: PolicyData = result?;
//if verbose > 3 {
// println!("{:?}", record);
//}
// WIP: write to redis backend
// for now: append the policy_number to the HashMap
policy_numbers.insert(record.policy_number, record.policy_code);
// push record as new vector elements
data_list.push(record);
count +=1;
*policy_data_count = count;
};
let time_end = SystemTime::now();
let duration = time_end.duration_since(time_start)
.expect("Clock may have gone backwards");
trace!(target: "csv-import", record_count = ?count, duration = ?duration);
state = t!("state.finished", lang);
res = t!("csv.import.finished", lang);
let datetime: DateTime<Local> = time_end.into();
trace!(target: "csv-import", process = ?res, state = ?state, date_stop = ?datetime.to_string());
Ok((count, duration))
}
#[test]
fn test_import() {
// Takes a reference and returns Option<&V>
let my_policy_numbers : [u64; 2] = [1511111111, 9999999993];
assert_eq!(my_policy_numbers, [1511111111, 9999999993]);
let mut csv_import_path = String::from("data/POLLFNR_TEST.txt");
let mut policy_data = PolicyDataList::new("PolicyDataList");
let mut policy_numbers : HashMap<u64, PolicyCode> = HashMap::new();
let mut policy_data_count: u64 = 0;
let lang = "en".to_string();
match import(&mut csv_import_path, &mut policy_data,
&mut policy_numbers, &mut policy_data_count,
&lang) {
Ok((count, duration)) => {
println!("import {:?} records. Duration: {:?}", count, duration);
}
Err(err) => {
println!("error running CSV-Import: {}", err);
}
};
for p in &my_policy_numbers {
match policy_numbers.get(&p) {
Some(policy_code) => {
println!("Test: Policy-Number {:?} => Policy-Type {:?}, as expected!",
p, policy_code);
},
_ => println!("Test: Policy-Number {:?} => not valid, can't dereference the Policy-Type as expected", p),
}
}
}

View File

@@ -1,30 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use std::error::Error;
use std::io;
use std::process;
/// Testing: import from csv format (Standard in)
fn import() -> Result<(), Box<dyn Error>> {
// Build the CSV reader and iterate over each record.
let mut csv_reader = csv::Reader::from_reader(io::stdin());
for result in csv_reader.records() {
// The iterator yields Result<StringRecord, Error>, so we check the
// error here.
let record = result?;
println!("{:?}", record);
}
Ok(())
}
fn main() {
if let Err(err) = import() {
println!("import error: {}", err);
process::exit(1);
}
}

View File

@@ -1,9 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// Importing Allianz DirecCall data
pub mod allianzdirectcall;

View File

@@ -1,12 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// advotracker import modules
pub mod imports;
/// advotracker export modules
pub mod exports;

View File

@@ -1,79 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use serde::{Deserialize, Serialize};
use crate::widgets::configuration::configuration_view::ConfigurationView;
/// Valid `actions` that are handled as state changes in the `Configuration` widget.
#[derive(Clone, Debug)]
pub enum ConfigurationAction {
SaveConfiguration,
LoadConfiguration,
}
/// Define valid configuration data.
/// This structure is serialized and saved inside the OS dependent settings file.
#[derive(Default, Debug, Clone, Serialize, Deserialize)]
struct ConfigurationData(
pub String,
pub String
);
/// Valid `structures` that are handled inside the state of the `Configuration` widget.
#[derive(Debug, Default, AsAny)]
pub struct ConfigurationState {}
impl State for ConfigurationState {
fn messages(
&mut self,
mut messages: MessageReader,
registry: &mut Registry,
ctx: &mut Context<'_>,
) {
for message in messages.read::<ConfigurationAction>() {
match message {
ConfigurationAction::LoadConfiguration => {
registry
.get::<Settings>("settings")
.load_async::<ConfigurationData>(
"configuration_data".to_string(), ctx.entity()
);
}
ConfigurationAction::SaveConfiguration => {
let configuration_file: String = ConfigurationView::configuration_file_clone(&ctx.widget());
let language_id: String = ConfigurationView::language_id_clone(&ctx.widget());
registry
.get::<Settings>("settings")
.save_async(
"configuration_data".to_string(),
ConfigurationData(
configuration_file,
language_id
),
ctx.entity(),
);
}
}
}
// save the result
for message in messages.read::<SettingsResult<()>>() {
println!("Result {:?}", message);
}
// load result
for message in messages.read::<SettingsResult<ConfigurationData>>() {
if let Ok(data) = message {
ConfigurationView::configuration_file_set(&mut ctx.widget(), data.0);
ConfigurationView::language_id_set(&mut ctx.widget(), data.1);
}
}
}
}

View File

@@ -1,139 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use crate::{
data::constants::*,
widgets::configuration::configuration_state::{ConfigurationAction, ConfigurationState},
};
// Macro that initializes the widget structures/variables for our view
widget!(
ConfigurationView<ConfigurationState> {
configuration_file: String,
language_id: String
}
);
/// The template implementation of the configuration view
/// All GUI elements are styled using the "style" attribute referencing to a ron based css
impl Template for ConfigurationView {
fn template(self, id: Entity, ctx: &mut BuildContext<'_>) -> Self {
self.child(
Grid::new()
.id(ID_CONFIGURATION_FORM)
.style("configuration_form")
.columns(
Columns::create()
.push(120)
.push(12)
.push("auto")
)
.rows(Rows::create()
.push("auto") // Header_Bar
.push(4) // Seperator
.push("auto") // Configuartion_File
.push(4) // Seperator
.push("auto") // Language_ID
.push(12) // Seperator
.push("auto"), // Action
)
.child(
TextBlock::new()
.id(ID_CONFIGURATION_HEADER)
.h_align("start")
.attach(Grid::column(0))
.attach(Grid::row(0))
.attach(Grid::column_span(3))
.text("Configuration settings")
.style("header")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_CONFIGURATION_LABEL_CONFIG_FILE)
.attach(Grid::column(0))
.attach(Grid::row(2))
.v_align("center")
.h_align("end")
.text("Configuration file")
.build(ctx),
)
.child(
TextBox::new()
.id(ID_CONFIGURATION_CONFIG_FILE)
.attach(Grid::column(2))
.attach(Grid::row(2))
.text(("configuration_file", id))
.water_mark("Filename...")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_CONFIGURATION_LABEL_LANGUAGE_ID)
.attach(Grid::column(0))
.attach(Grid::row(4))
.v_align("center")
.h_align("end")
.text("Language Id")
.build(ctx),
)
.child(
TextBox::new()
.id(ID_CONFIGURATION_LANGUAGE_ID)
.attach(Grid::column(2))
.attach(Grid::row(4))
.text(("language_id", id))
.water_mark("Locale Identifier...")
.build(ctx),
)
.child(
Grid::new()
.h_align("center")
.attach(Grid::column(0))
.attach(Grid::row(6))
.attach(Grid::column_span(3))
.columns(
Columns::create()
.push("auto")
.push(8)
.push("auto")
)
.rows(Rows::create()
.push("auto")
)
.child(
Button::new()
.style("button_single_content")
.attach(Grid::column(0))
.attach(Grid::row(0))
.text("Load")
.on_click(move |ctx, _| {
ctx.send_message(ConfigurationAction::LoadConfiguration, id);
true
})
.build(ctx),
)
.child(
Button::new()
.text("Save")
.style("button_single_content")
.attach(Grid::column(2))
.attach(Grid::row(0))
.on_click(move |ctx, _| {
ctx.send_message(ConfigurationAction::SaveConfiguration, id);
true
})
.build(ctx),
)
.build(ctx),
)
.build(ctx),
)
}
}

View File

@@ -1,12 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// The configuration state
pub mod configuration_state;
/// The configuration view
pub mod configuration_view;

View File

@@ -1,93 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use dotenv::dotenv;
use serde::Deserialize;
use std::env;
use substring::Substring;
use tracing::{info, trace};
use orbtk::prelude::*;
use crate::{
data::constants::*,
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.
pub trait GlobalState {
fn get_lang() -> String {
// get system environment
let mut lang = env::var("LANG").unwrap_or_else(|_| "C".to_string());
lang = lang.substring(0,5).to_string(); // "de_DE.UTF-8" -> "de_DE"
info!("GUI-Language: preset to {:?}", lang);
// 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) }
}
trace!(target: "advotracker", lang = ?lang);
// return the active language
lang
}
/// Get the text of a widget.
fn get_text(&self, ctx: &mut Context<'_>, entity: Entity) -> Option<String> {
let text = TextBox::text_clone(&ctx.get_widget(entity));
if text.is_empty() {
return None;
}
TextBox::text_set(&mut ctx.get_widget(entity), String::default());
Some(text)
}
// /// Navigates to the given entity.
// fn navigate(&self, to: Entity, ctx: &mut Context<'_>) {
// if let Some(old_focused_element) = *Window::focus_state_ref(&ctx.window()).focused_entity() {
// ctx.push_event_by_window(FocusEvent::RemoveFocus(old_focused_element));
// }
// ctx.widget().set("visibility", Visibility::Collapsed);
// ctx.get_widget(to).set("visibility", Visibility::Visible);
// }
/// Save the our data structure and convert it to `ron` file format.
/// The cargo package identifier (here: 'nwx.advotracker') is taken to create the app directory.
/// in users 'settings directory'. The directory location is OS dependant
/// (Windows: AppData, Unix: XDG_CONFIG_HOME, MacOS: $HOME/Library/Preferences).
/// The data is stored in filename PROP_ADVOTRACKER (here: `advotracker.ron`)
fn save(&self, registry: &mut Registry, ctx: &mut Context<'_>) {
registry
.get::<Settings>("settings")
.save(
PROP_ADVOTRACKER,
ctx.widget().get::<PolicyList>(PROP_ADVOTRACKER),
)
.unwrap();
}
}
// #[cfg(test)]
// mod tests {
// #[test]
// assert_eq!(2 + 2, 4);
// }

View File

@@ -1,40 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use crate::widgets::localization::localization_view::LocalizationView;
#[derive(AsAny, Debug, Default)]
pub struct LocalizationState {
change_language: bool,
}
impl LocalizationState {
pub fn change_language(&mut self) {
self.change_language = true;
}
}
impl State for LocalizationState {
fn update(&mut self, _registry: &mut Registry, ctx: &mut Context<'_>) {
if !self.change_language {
return;
}
let index = *LocalizationView::selected_index_ref(&ctx.widget()) as usize;
let selected_language = LocalizationView::languages_ref(&ctx.widget())[index].clone();
match selected_language.as_str() {
"English" => ctx.set_language("en_US"),
"German" => ctx.set_language("de_DE"),
_ => {}
}
self.change_language = false;
}
}

View File

@@ -1,97 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use crate::{
data::constants::*,
widgets::localization::localization_state::LocalizationState,
};
type List = Vec<String>;
// Macro that initializes the widget structures/variables for our view
widget!(LocalizationView<LocalizationState> {
languages: List,
selected_index: i32 }
);
/// The template implementation of the localization view
/// All GUI elements are styled using the "style" attribute referencing to a ron based css
impl Template for LocalizationView {
fn template(self, id: Entity, ctx: &mut BuildContext<'_>) -> Self {
let languages = vec!["English".to_string(), "German".to_string()];
let count = languages.len();
self.languages(languages)
.selected_index(1)
.child(
Grid::new()
.id(ID_LOCALIZATION_FORM)
.margin(4)
.columns(
Columns::create()
.push(120)
.push(12)
.push(150)
)
.rows(Rows::create()
.push("auto")
.push(4)
.push("auto")
.push(4)
.push("auto")
.push(12)
.push("auto"),
)
.child(
TextBlock::new()
.id(ID_LOCALIZATION_HEADER)
.h_align("start")
.attach(Grid::column(0))
.attach(Grid::row(0))
.attach(Grid::column_span(3))
.text("Localization dialog")
.style("header")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_LOCALIZATION_LABEL_LANGUAGE_NAME)
.attach(Grid::column(0))
.attach(Grid::row(2))
.v_align("center")
.h_align("end")
.text("Language ID")
.build(ctx),
)
.child(
ComboBox::new()
.id(ID_LOCALIZATION_LANGUAGES)
.count(count)
.attach(Grid::column(2))
.attach(Grid::row(2))
.items_builder(move |bc, index| {
let text = bc.get_widget(id)
.get::<Vec<String>>("languages")[index]
.clone();
TextBlock::new()
.id(ID_LOCALIZATION_LANGUAGE_NAME)
.v_align("center")
.text(text)
.build(bc)
})
.on_changed("selected_index", move |states, _| {
states.get_mut::<LocalizationState>(id).change_language();
})
.selected_index(id)
.build(ctx),
)
.build(ctx),
)
}
}

View File

@@ -1,12 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// The localization state
pub mod localization_state;
/// The localizatin view
pub mod localization_view;

View File

@@ -1,76 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use crate::{
data::{
constants::*,
structures::PolicyCheck,
},
widgets::configuration::configuration_view::ConfigurationView,
widgets::policycheck::policycheck_view::PolicycheckView,
widgets::localization::localization_view::LocalizationView,
//widgets::menu::menu_view::MenuView,
widgets::ticketdata::ticketdata_view::TicketdataView,
};
// [START] views
widget!(MainView {
// policy_list: PolicyList,
// policy_data_list: PolicyDataList,
// policylist_view: u32,
// policydata_view: u32,
policycheck_view: PolicyCheck
//ticketdata_view: TicketData
});
impl Template for MainView {
fn template(self, _id: Entity, ctx: &mut BuildContext<'_>) -> Self {
let ticketdata_view = TicketdataView::new()
.build(ctx);
let policycheck_view = PolicycheckView::new()
.target(ticketdata_view.0)
//.policy_number_count(0)
//.policylist_view(id)
.build(ctx);
// let policylist_view = PolicyListView::new()
// .back_entity(policycheck_view.0)
// .policydata_view(id)
// .policylist_view(id)
// .policy_list_count(id)
// .build(ctx);
// let policydata_view = PolicyDataView::new()
// .back_entity(policylist_view.0)
// .policylist_view(id)
// .visibility("collapsed")
// .build(ctx);
self.name("MainView")
//.policycheck_view(PolicyCheck::default())
// //.policycheck_view(0)
// .policydata_view(policydata_view.0)
// //.policylist_view(PolicyList::default())
// .policylist_view(policylist_view.0)
// .child(policydata_view)
// .child(policylist_view)
.child(
TabWidget::new()
.tab(ID_POLICY_CHECK_VIEW, policycheck_view)
.tab(ID_TICKET_DATA_VIEW, ticketdata_view)
.tab(ID_LOCALIZATION_VIEW, LocalizationView::new().build(ctx))
.tab(ID_CONFIGURATION_VIEW, ConfigurationView::new().build(ctx))
//.tab(ID_MENU_VIEW, MenuView::new().build(ctx))
.build(ctx),
)
//.child(policycheck_view)
}
}

View File

@@ -1,427 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use cfg_if::cfg_if;
use orbtk::prelude::*;
use orbtk::shell::event::Key;
use tracing::{info, trace};
use std::process;
use crate::{
data::constants::*,
widgets::menu::menu_view::MenuView,
//widgets::policycheck::policycheck_view::PolicycheckView,
};
/// Valid `actions` that are handled as state changes in the `Menu` widget.
#[derive(Debug, Clone, Copy)]
pub enum MenuAction {
CreateMenu,
CreateMenuToggleTheme,
RemoveMenu,
RemoveMenuToggleTheme,
SetTheme,
UpdateMenuRelativePosition
}
/// Valid `structures` that are handled inside the state of the `Menu` widget.
#[derive(AsAny, Default)]
pub struct MenuState {
action: Option<MenuAction>,
menu: Option<Entity>,
//menu_toggle_theme: Option<Entity>
menu_toggle_theme: Entity
}
/// Method definitions, that react on any given state change inside the `Menu` widget.
impl MenuState {
/// Create a toggle_theme menu as a child of the given parent
/// Select the active theme from a `ComboBox` offering a list of valid `themes`
fn _create_menu_toggle_theme(&mut self, _ctx: &mut Context<'_>) {
self.action = Some(MenuAction::CreateMenuToggleTheme);
}
/// Remove the menu popup box
fn remove_menu(&mut self, ctx: &mut Context<'_>) {
self.action = Some(MenuAction::RemoveMenu);
ctx.remove_child(ctx.entity());
println!("Popup {:?} removed.", ctx.entity());
}
/// Remove the menu popup box
fn _remove_menu_toggle_theme(&mut self, _ctx: &mut Context<'_>) {
self.action = Some(MenuAction::RemoveMenuToggleTheme);
}
/// Sets a new action.
pub fn set_action(&mut self, action: MenuAction) {
self.action = action.into();
}
/// Update the relative position of the menu overlay
fn _update_menu_relative_position(&mut self) {
println!("TODO: Update relative position of menu {}.", ID_MENU_POPUP);
//self.action = Some(MenuAction::UpdateRelativePosition);
}
}
/// Supported methods handled inside the `MenuState`
impl State for MenuState {
// /// Initialize the state of widgets inside `MenuState`
// fn init(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
// }
/// Handle messages for the `MenuState`
fn messages(
&mut self,
mut messages: MessageReader,
_registry: &mut Registry,
ctx: &mut Context<'_>,
) {
for message in messages.read::<MenuAction>() {
match message {
MenuAction::CreateMenu => {
info!("WIP: create a menu popup in MenuState");
// assign parent entity
let parent = ctx.entity();
trace!(parent = ?parent);
//let parent_name = ctx.get_widget().get::<String16>("text");
//trace!(parent = ?parent, parent_name = ?parent_name);
// assign target -> search for a child of parent with given id
let target = ctx
.entity_of_child(ID_MENU_BUTTON_MENU)
.expect("MenuState: Can't find entity of resource 'ID_MENU_BUTTON_MENU'.");
trace!(target = ?target.0, entity_of_child = ?ID_MENU_BUTTON_MENU);
// create the target entity as child of parent
let menu_popup = create_menu_popup(parent, &mut ctx.build_context());
//let menu_popup = create_popup(target, "Testmenu Popup", &mut ctx.build_context());
// append the child to target (overlay stays on top of the main tree)
ctx.build_context()
.append_child_to_overlay(menu_popup)
.expect("Failed create an overlay that consumes popup `menu` as its child.");
self.menu = Some(menu_popup);
trace!(menu = ?self.menu);
// open: is the default
//ctx.get_widget(menu).set("open", true);
info!("CreateMenu: parent {:?}, target: {:?}, popup: {:?}", parent, target, self.menu);
}
MenuAction::SetTheme => {
let theme_index = *MenuView::selected_index_ref(&ctx.widget());
cfg_if! {
if #[cfg(windows)] {
match theme_index {
0 => ctx.switch_theme(theme_default_dark()),
1 => ctx.switch_theme(theme_default_light()),
2 => ctx.switch_theme(theme_redox()),
3 => ctx.switch_theme(theme_fluent_dark()),
4 => ctx.switch_theme(theme_fluent_light()),
_ => {}
}
} else {
match theme_index {
0 => ctx.switch_theme(theme_default_dark()),
1 => ctx.switch_theme(theme_default_light()),
2 => ctx.switch_theme(theme_redox()),
_ => {}
}
}
}
}
_ => {}
}
}
}
/// Update the state of widgets inside the `Menu` view.
fn update(&mut self, _registry: &mut Registry, ctx: &mut Context<'_>) {
if let Some(action) = self.action {
match action {
MenuAction::CreateMenuToggleTheme => {
let menu_target = ctx
.entity_of_child(ID_MENU_LABEL_TOGGLE_THEME)
.expect("MenuState: Can't find entity of resource 'ID_MENU_LABEL_TOGGLE_THEME'.");
let current_entity = ctx.entity();
let build_context = &mut ctx.build_context();
// create a new menu popup
self.menu_toggle_theme = create_menu_toggle_theme_popup(current_entity, build_context);
// create a menu_popup widget as a child of entity "ID_POPUP_MENU"
build_context.append_child(menu_target, self.menu_toggle_theme);
ctx.get_widget(self.menu_toggle_theme).clone::<Visibility>("visibility");
println!("Popup Menu Toggle Theme created: {:?}", self.menu_toggle_theme);
}
MenuAction::RemoveMenu => {
self.remove_menu(ctx);
}
MenuAction::RemoveMenuToggleTheme => {
ctx.remove_child(self.menu_toggle_theme);
println!("Popup {:?} removed.", ctx.entity());
}
MenuAction::UpdateMenuRelativePosition => {
if let Some(menu) = self.menu {
// let theme_combo_box = ctx.entity_of_child(ID_MENU_TOGGLE_THEME).unwrap();
// let selected_index: i32 = ctx.get_widget(theme_combo_box).clone("selected_index");
// // let relative_position: RelativePosition =
// // ctx.get_widget(ID_MENU_POPUP).clone_or_default("relative_position");
// match selected_index {
// 0 => {
// RelativePosition::relative_position_mut(&mut ctx.widget()).into_bottom();
// //RelativePosition::get_mut::<MenuState>("relative_position").into_bottom();
// // ctx
// // .get_widget(self.ID_MENU_POPUP.unwrap())
// // .set("relative_position", relative_position.into_bottom());
// },
// 1 => RelativePosition::relative_position_mut(&mut ctx.widget()).into_top(),
// 2 => RelativePosition::relative_position_mut(&mut ctx.widget()).into_left(),
// 3 => RelativePosition::relative_position_mut(&mut ctx.widget()).into_right(),
// _ => panic!(),
// }
println!("Relative position of menu {:?} updated.", menu);
}
}
_ => (),
}
}
}
}
/// Create a new popup presenting the menu components
fn create_menu_popup(target: Entity, ctx: &mut BuildContext<'_>) -> Entity {
Popup::new()
.id(ID_MENU_POPUP)
.name(ID_MENU_POPUP)
.target(target.0)
.open(true)
// WIP: this requires orbtk-develop with PR #304 (new_popup)
// Specify the popup position relative to the target
//.relative_position(RelativePosition::Bottom(5.0))
// Reference target from given Point
//.target(Point::new(100.0,100.0))
//.style("popup_menu")
.width(300.0)
.height(100.0)
.on_key_down(move | ctx, key_event | {
match key_event.key {
Key::Q(..) => {
//if is_ctrl_home_down(ctx)
println!("KeyHandler: got Ctrl+Q");
process::exit(0);
//}
},
Key::Escape => {
println!("KeyHandler: got Escape");
ctx.get_mut::<MenuState>(target)
.set_action(MenuAction::RemoveMenu);
},
_ => {
println!("KeyHandler: got {:?}", key_event.key);
},
};
true
})
.child(
Container::new()
.child(
TextBlock::new()
//.style("popup_text_block")
.h_align("center")
.v_align("enter")
.text(ID_MENU_POPUP)
.build(ctx),
)
.build(ctx),
)
.child(
Grid::new()
.id(ID_MENU_GRID)
.name(ID_MENU_GRID)
.columns(
Columns::create()
.push("180") // Menu Button
.push("1") // Seperator
.push("auto") // Keyboard Shortcut
)
.rows(
Rows::create()
.push("auto")
.push("auto")
.push("auto")
)
.child(
Button::new()
.id(ID_MENU_LABEL_ACCOUNT)
.name(ID_MENU_LABEL_ACCOUNT)
.style("button_menu")
//.h_align("start")
.attach(Grid::row(0))
.attach(Grid::column(0))
//.attach(Grid::column_span(2))
.icon(material_icons_font::MD_PERSON)
.text("Account")
.build(ctx),
)
.child(
Button::new()
.id(ID_MENU_LABEL_TOGGLE_THEME)
.name(ID_MENU_LABEL_TOGGLE_THEME)
.style("button_menu")
//.h_align("start")
.attach(Grid::row(1))
.attach(Grid::column(0))
//.attach(Grid::column_span(2))
.icon(material_icons_font::MD_EDIT)
.text("Toggle theme")
.on_click(move |ctx, _| {
ctx.get_mut::<MenuState>(target)
.set_action(MenuAction::CreateMenuToggleTheme);
true
})
.build(ctx),
)
.child(
Button::new()
.id(ID_MENU_LABEL_QUIT)
.name(ID_MENU_LABEL_QUIT)
.style("button_menu")
//.h_align("start")
.attach(Grid::row(2))
.attach(Grid::column(0))
//.attach(Grid::column_span(2))
.icon(material_icons_font::MD_SETTINGS_POWER)
.text("Quit")
.on_mouse_down(move |_states, _| {
process::exit(0);
})
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_MENU_SHORTCUT_QUIT)
.name(ID_MENU_SHORTCUT_QUIT)
//.style("button_menu")
.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)
}
fn _create_popup(target: Entity, text: &str, ctx: &mut BuildContext<'_>) -> Entity {
Popup::new()
.id("test_popup")
.name("Test Popup")
// Reference target from given Entity
.target(target.0)
// Reference target from given Point
//.target(Point::new(0.0, 5.0))
// Specify the popup position relative to the target (the button in this case)
//.relative_position(RelativePosition::Bottom(5.0))
.open(true)
.style("popup_form")
.width(350.0)
.height(100.0)
.child(
Container::new()
.child(
TextBlock::new()
//.style("popup_text_block")
.h_align("center")
.text(text)
.build(ctx),
)
.build(ctx),
)
.build(ctx)
}
/// Create a new popup submenu to toogle the active theme
fn create_menu_toggle_theme_popup(id: Entity, ctx: &mut BuildContext<'_>) -> Entity {
cfg_if! {
if #[cfg(windows)] {
// define the list of supported themes
let themes = vec![
"default_dark".to_string(),
"default_light".to_string(),
"redox".to_string(),
"fluent_dark".to_string(),
"fluent_light".to_string()
];
} else {
// define the list of supported themes
let themes = vec![
"default_dark".to_string(),
"default_light".to_string(),
"redox".to_string(),
];
}
}
let themes_count = themes.len();
Popup::new()
.id(ID_MENU_TOGGLE_THEME)
.target(id.0)
.style("container_menu")
.width(280)
.height(140)
.on_key_down(move | _ctx, key_event | {
match key_event.key {
Key::Escape => {
println!("KeyHandler: got Escape");
//ctx.get_mut::<MenuState>(id)
// .set_action(MenuAction::RemoveMenuToggleTheme);
},
_ => {
println!("KeyHandler: got {:?}", key_event.key);
},
};
true
})
.child(
ComboBox::new()
.attach(Grid::column(2))
.attach(Grid::row(6))
.count(themes_count)
.style("combo_box_form")
.items_builder(move |ctx, index| {
let theme_name =
MenuView::themes_ref(&ctx.get_widget(id))[index].clone();
TextBlock::new().v_align("center").text(theme_name).build(ctx)
})
.on_changed("selected_index", move |states, _entity| {
states.send_message(MenuAction::SetTheme, id);
println!("changed theme.");
})
.selected_index(id)
.build(ctx),
)
.build(ctx)
}

View File

@@ -1,127 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use crate::data::constants::*;
use crate::widgets::menu::menu_state::{MenuAction, MenuState};
type List = Vec<String>;
// Macro that initializes the widget structures/variables for the menu view
widget!(
MenuView<MenuState> {
//menu_stack: Entity,
//button_menu: Entity,
selected_index: i32,
themes: List
}
);
/// The template implementation of the menu view
/// All GUI elements are styled using the "style" attribute referencing to a ron based css
impl Template for MenuView {
fn template(self, id: Entity, ctx: &mut BuildContext<'_>) -> Self {
let menu_bottom_bar = Container::new()
.id(ID_MENU_BOTTOM_BAR)
.style(STYLE_BOTTOM_BAR)
.attach(Grid::row(3))
.attach(Grid::column(1))
.attach(Grid::column_span(2))
.v_align("end")
.child(
Container::new()
.child( Container::new()
.margin((0, 16, 16, 0))
.v_align("center")
.child(
ImageWidget::new()
.image("assets/advotracker/hiedemann_logo.png")
.v_align("center")
.build(ctx),
)
.build(ctx),
)
.build(ctx),
)
.child(
Container::new()
.attach(Grid::column(1))
.h_align("end")
.v_align("end")
.child(
TextBlock::new()
.margin((0, 9, 48, 0))
.text("©Networkx GmbH")
.build(ctx)
)
.build(ctx),
)
.build(ctx);
let menu_button_menu = Button::new()
.id(ID_MENU_BUTTON_MENU)
.name(ID_MENU_BUTTON_MENU)
.style("button_single_content")
.icon(material_icons_font::MD_MENU)
.attach(Grid::column(2))
//.min_size(16, 16)
//.h_align("end")
.h_align("start")
.on_click(move |ctx, _| {
ctx.send_message(MenuAction::CreateMenu, id);
true
})
.build(ctx);
let menu_header_bar = Container::new()
.id(ID_MENU_HEADER_BAR)
.style(STYLE_HEADER_BAR)
.attach(Grid::row(0))
.attach(Grid::column(1))
.attach(Grid::column_span(2))
.child(
Grid::new()
.child(
TextBlock::new()
.style("header")
.id(ID_MENU_HEADER)
.v_align("center")
.h_align("left")
.text("Ticket Data")
.build(ctx),
)
.build(ctx),
)
.child(menu_button_menu)
.build(ctx);
//self.themes(themes).child(MenuState::create_menu(ID_MENU_POPUP, ctx))
self.name("MenuView")
.child(
Grid::new()
.id(ID_MENU_VIEW)
.columns(
Columns::create()
.push(50) // Left margin
.push("*") // Content
.push(50) // Right margin
)
.rows(
Rows::create()
.push("auto") // Header_Bar
.push(28) // Seperator
.push("*") // InputForm
.push("auto") // Bottom_Bar
)
.child(menu_header_bar) // Row 0
.child(menu_bottom_bar) // Row 3
.build(ctx),
)
}
}

View File

@@ -1,12 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// The menu view
pub mod menu_view;
/// The menu state
pub mod menu_state;

View File

@@ -1,33 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// Configuration widget.
pub mod configuration;
/// Global helper functions.
pub mod global_state;
/// Localization widget.
pub mod localization;
/// The starting point (Main View).
pub mod main_view;
/// Menu widget.
pub mod menu;
/// Policycheck wigdet.
pub mod policycheck;
// /// Policydata widget.
// pub mod policydata;
// /// Policylists widget.
// pub mod policylist;
/// Ticketdata wigdet.
pub mod ticketdata;

View File

@@ -1,12 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// The policy check state
pub mod policycheck_state;
/// The policy check view
pub mod policycheck_view;

View File

@@ -1,12 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// The policy check state
pub mod policycheck_state;
/// The policy check view
pub mod policycheck_view;

Some files were not shown because too many files have changed in this diff Show More