62 Commits

Author SHA1 Message Date
cff156c024 advotracker_client: introduce Windows icon handling
* include `windres` crate
* create a `build.rs`
* include a `hotline.svg` that is converted to advotracker.ico
  using inkscape and imagemagick
* crate a `README.md`

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-18 11:06:36 +01:00
78851ebbcf Cargo: move profile definitions to workspace root
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-10 09:58:58 +01:00
f6ac43816f data:constants: correct callback_number bug
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-10 09:47:22 +01:00
2b4eb454cc examples: insert sdl2_demo
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-10 09:19:14 +01:00
abe56741e8 widgets:ticketdata: correct mail_from address
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-10 09:18:24 +01:00
0202d4a34b advotracker_client: bump version 0.1.5-alpha2
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 17:26:46 +01:00
520e0cb712 widget:ticketdata: error handling and button glyphs
* assign glyphs depending on action state
* feedback on send_ticketdata return code
* cleanup

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 17:24:07 +01:00
c555ce4d85 service:send_ticketdata: adapt alingnment of http mail and relay
* cleanup comments
* correct relay / credential handling

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 12:07:14 +01:00
a8f6ac6a37 services:send_ticketdata: correct relay authentication issues
* correct mail_from identifier
* correct mail_reply identifier
* correct mail_cc identifier

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 11:16:50 +01:00
8abdef6e44 widget: bump to 0.1.5-alpha2
* typo cleanup
* temporary disable mail-cc combobox
* correct mail_cc address

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 09:50:12 +01:00
a5dae6e397 advotrackerdb: update use reference after structure update
* binaries: reference advotrackerdb, not crate

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 04:32:12 +01:00
e03c5ab667 main: adapt window size
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 04:32:11 +01:00
d8e94513c3 widget:policycheck: enable ClearPolicyNumber
* new action button "Clear", "New ticket"
* enable needed send_message routine
* create action method
* update visibility state of involved view properties

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 04:32:11 +01:00
5a9965751a 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>
2021-03-08 04:32:11 +01:00
4c88167bef advotracker: restructure project using crate tree
* advotracker: the framework crate
* crate/advotrackerdb: crate implementing the database backend
* crate/advotrackerd: the backend daemon
* crate/adovtracker: the application (CLI and GUI)

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 04:32:11 +01:00
1ce1d029e5 widget:ticketdata: bug correction for ComboBox
* always use 'TextBlock', since editing is not allowed
  'TextBox ' also disturbs correct rendering

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 04:32:10 +01:00
2e927c8a6a widget:ticketdata: implement ClearForm
* reset all children of a given form to clean initial state
* use `match` expression that compares the widget name,
  that resolves to the widget type (here: TextBox)

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 04:32:10 +01:00
f3db69ce62 Cargo.toml: bump version to 0.1.5-alpha0
* include dependency to crate lettre
* include depenency to crate maud
* this version initially supports ticketdata dialo
* data can be send via Email

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-08 04:31:40 +01:00
55040e37cf widget:global_state: remove usage of navigate
* this needs to be adopted to use event handler code

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-06 15:27:20 +01:00
ba3a6fb4d3 ticketdata: update ticketdata_view using widget builder
* create and handle items in combo boxes using list
  and widget builder

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-06 15:08:57 +01:00
8184af8135 ticketdata: code cleanup 2021-03-06 15:08:57 +01:00
87cbf493a2 advotracker: updated localization strings and constants
* update due to customer request
* constants
* translation strings
* disable WIP menu widget
* labels used in Email submission

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-06 15:08:57 +01:00
4381c3d299 main_view: disable wip menu widget
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-06 15:08:57 +01:00
791b451d39 main: handle test_policy_number
* provide cli-flag `testPolicyNumber` as String
  since viperus doesnt support u64
* handle stringconversion (String -> u64) inside main

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-04 07:07:01 +01:00
aeaafd8c57 widget:ticketdata: function extention to handle Email sending
* remap to use `policy code`
* adapt the constants
* start with clear_form()
* use service 'send_ticketdata' which crate lettre
* enable smtp authorization via credentilas
* support html using crate 'maud'
* provide the needed structures
* update the constants for property and entity assigns
* include send Email service (sendticketdata)
* send_ticketdata: include html  maud modules

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-04 07:06:03 +01:00
1af299dc01 widget:policycheck: map to ID_POLICY_CHECK_POLICY_CODE
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-03 22:35:20 +01:00
bd6971d4d0 .gitmodules: update dead module path
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-03 16:32:33 +01:00
85fb4ceb16 advotracker-db: update to head
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-03 16:32:21 +01:00
a451b58ab4 widget:menu: deactivate requirement for new popup_code
* since new popup code is just in PR #304, do not rely on its availibility

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-03 11:53:17 +01:00
b96c3c510f widgets:main_view: update widget activation handling
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-03 11:51:50 +01:00
2c903c67dd data:constants: update widget id's identifier
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-03 11:50:33 +01:00
a40f6e94dd widget:global_state: activate navigate() method
* allow widgets to nagivate to other widget context

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-03 11:48:16 +01:00
8af49deb34 widget:ticketdata: introduce message passing
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-03 11:47:26 +01:00
202ba81b4f widget:policycheck: introduce message passing
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-03 11:46:39 +01:00
43db004179 examples: move csv-test
* test validity of a given policy number
* cli program will match via  hashmap
* hashmap is constructed from a csv file

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-03 00:38:10 +01:00
3b65dafbec examples: introduce messages_test
* showcase demenstrating messages passing from a sender (widget1)
  to a receiver (widget 2)
* use modular source tree structure

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-03-03 00:33:26 +01:00
23732350ca policycheck: refine header bar
* place tenent logo at upper right
* adapt header text placement

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 20:15:31 +01:00
3c40055e2e theming: update default_dark
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:25 +01:00
6a61d2f878 policycheck: functionality cleanup
* sorting
* string usage

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:25 +01:00
044ad84598 services: allianzdireectcall update
* rust update using &str instead of &String

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:25 +01:00
b2a9d9aa52 widget/configuration: typo and documentation update
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:24 +01:00
157da4228a include substring handling
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:24 +01:00
26cf43bfae ticketdata: introduce new widget
* Cargo.toml: introduce carte `lettre` used in send_ticketdata.rs
* locales: extend translations
* theme: extend translations
* send_ticketdata: send harm data via email
* ticket_data: aquisition of harm data
* update constant usage

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:24 +01:00
a2314d4909 envy: update .env
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:24 +01:00
0dab2dddb3 csv-test: typo update
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>

csv-test: update

* move to subdir `examples`
* typo update

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:24 +01:00
bb40033554 parse_args: typo update
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:24 +01:00
a4a09bc37c data/structures: typo update
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:24 +01:00
9fba66d8a6 widget/configuration: styling update
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:24 +01:00
7d6476205f Cargo.toml: include crate if_cfg
* use macro to compile os-dependent features

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:24 +01:00
41ebf4168a widgets/configuration: reference styling to theme handling
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:23 +01:00
c4caf12706 widget/policycheck: update logic
* remove handling of the menu logic (isolated in dedicated widget)
* reference styling via theme
* update documentation strings

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:23 +01:00
075505eec9 widgets/menu: introduce dedicated module menu
* new menu_view
* new menu_state
* update constants
* update main_view referencing a tab_view

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:23 +01:00
59e7e71143 assets: update theme definitions for default_dark.ron
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:23 +01:00
7440f7a6dd widgets/menu: introduce dedicated menu module
* new menu_view
* new menu_state
* adapt constant values for the menu structure

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:23 +01:00
a401379f9e theme update dark
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:23 +01:00
be9b8b1a1c widget/configuration: correcting label constant
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:23 +01:00
70bd6b8b8d language: update
* update constants
* adopt width of languages combo box

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:23 +01:00
1f3c6a7fff widget/policycheck: intoduce os dependent theme handling
* theme_fluent: only makes sense in windows environment

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:23 +01:00
ef26a3bf65 widgets/localization: update label constant
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:22 +01:00
fa4914839e assets: adapt default_dark theme definitions
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:46:18 +01:00
571243731d assets: adapt fluent_dark theme definitions
Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:45:57 +01:00
b38a677b7b policycheck: function update
* insert copyright hint
* more descriptive import of allianzdirectcall function
* documentation update
* introduce KeyHandler in menu popup
* rename action function to `set_action`

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
2021-02-28 19:45:33 +01:00
205 changed files with 8627 additions and 1242 deletions

11
.gitmodules vendored
View File

@@ -1,9 +1,6 @@
[submodule "backend"] [submodule "advotrackerdb"]
path = backend path = crates/advotrackerdb
url = ./backend/ url = https://gitea.networkx.de:50443/rzerres/advotrackerdb
[submodule "advotracker-db"]
path = advotracker-db
url = https://gitea.networkx.de:50443/rzerres/advotracker-db
[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,10 +8,39 @@ 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"
[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-alpha2", path = "crates/advotracker_client", default-features = false }
[features]
default = ["sqlite"]
# enable optional db backends
sqlite = []
#sqlite = ["advotrackerdb_sqlite"]
#postgresql = ["advotrackerdb_pstgresql"]
[profile.dev]
#opt-level = 0
opt-level = 1
incremental = true
debug = true
lto = false
codegen-units = 5
panic = 'unwind'
overflow-checks = true
[profile.release] [profile.release]
incremental = true
panic = "abort" panic = "abort"
lto = true lto = true
codegen-units=1 codegen-units=1
@@ -21,15 +50,6 @@ opt-level="s"
# optimize to smallest size # optimize to smallest size
#opt-level = "z" #opt-level = "z"
[profile.dev]
opt-level = 0
debug = true
lto = false
codegen-units = 5
panic = 'unwind'
incremental = true
overflow-checks = true
[profile.test] [profile.test]
opt-level = 0 opt-level = 0
debug = 2 debug = 2
@@ -43,8 +63,7 @@ overflow-checks = true
[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 d29c747d7b

View File

@@ -1,54 +0,0 @@
Theme (
styles: {
"button_menu": (
base: "button",
properties: {
"padding": 4,
"border_radius": 0,
},
),
"container_form": (
base: "container",
properties: {
"padding": 14,
"border_width": 1,
"border_radius": 0,
"border_brush": "$CONTAINER_BORDER",
},
),
"configuration_form": (
base: "container",
properties: {
"margin": 4,
},
),
"container_progress": (
base: "container",
properties: {
"padding": 14,
//"border_width": 1,
//"border_radius": 0,
"border_brush": "$CONTAINER_BORDER",
},
),
"popup_progress": (
base: "popup",
properties: {
//"background": "$BACKGROUND",
"padding": 4,
},
),
"text_block_progress": (
base: "small_text",
properties: {
"background": "$PROGRESS_BAR_BACKGROUND",
},
),
"stack_progress": (
base: "container",
properties: {
"spacing": 10,
},
),
}
)

View File

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

View File

@@ -1,88 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
// Styles (RON based theme system)
pub static STYLE_BOTTOM_BAR: &str = "bottom_bar";
pub static STYLE_HEADER_BAR: &str = "header_bar";
pub static STYLE_SEPERATOR: &str = "seperator";
//pub static STYLE_ITEM_BUTTON: &str = "item_button";
pub static STYLE_MENU: &str = "menu";
pub static STYLE_BUTTON_MENU: &str = "button_menu";
pub static STYLE_STACK_MENU: &str = "stack_menu";
// Widget IDs (DCES: Entity[id] => [Component1, .. , Component<n>] -> data or state)
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_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_MENU_POPUP: &str = "menu_popup";
pub static ID_MENU_STACK: &str = "menu_stack";
pub static ID_MENU_BUTTON: &str = "menu_button";
pub static ID_MENU_GRID: &str = "menu_grid";
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_FORM: &str = "policy_check_form";
pub static ID_POLICY_CHECK_FORM_ROW_0: &str = "policy_check_form_row_0";
pub static ID_POLICY_CHECK_FORM_ROW_1: &str = "policy_check_form_row_1";
pub static ID_POLICY_CHECK_FORM_ROW_2: &str = "policy_check_form_row_2";
pub static ID_POLICY_CHECK_HEADER: &str = "policy_check_header";
pub static ID_POLICY_CHECK_ITEMS_WIDGET: &str = "policy_check_items_widget";
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_HINT: &str = "policy_check_hint";
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_NUMBER: &str = "policy_check_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";
// Component Values (Properties)
pub static PROP_ADVOTRACKER: &str = "advotracker";
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";

View File

@@ -1,300 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 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 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(Entity),
RemoveMenu,
RemoveMenuToggleTheme(Entity),
SetTheme
}
/// Valid `structures` that are handled inside the state of the `Menu` widget.
#[derive(AsAny, Default)]
pub struct MenuState {
action: Option<MenuAction>,
menu: Entity,
menu_toggle_theme: Entity
}
/// Method definitions, that react on any given state change inside the `Menu` widget.
impl MenuState {
/// Set a menu holding all valid menu elements
/// The elements are ordered compontents inside a stack
pub fn create_menu(&mut self, ctx: &mut Context<'_>) {
// create a stack as a child of the given component
let stack = ctx
.entity_of_child(ID_MENU_BUTTON)
.expect("PolicycheckState: Can't find entity of resource 'ID_MENU_BUTTON'.");
//.entity_of_child(<PolicycheckView>ID_MENU_BUTTON)
//.expect("PolicycheckState: Can't find entity of resource 'ID_POLICY_CHECK_POPUP_MENU'.");
let current_entity = ctx.entity();
let build_context = &mut ctx.build_context();
// create a new popup menu overlay
self.menu = create_menu_popup(current_entity, build_context);
// create a menu_popup widget as a child of entity "ID_POLICY_CHECK_BUTTON_MENU"
build_context.append_child(stack, self.menu);
println!("Popup Menu created: {:?}", self.menu);
}
/// Set a toggle_theme menu
/// Select the active theme from a `ComboBox` offering a list of valid `themes``
fn create_menu_toggle_theme(&mut self, ctx: &mut Context<'_>) {
let stack = 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 overlay
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(stack, self.menu_toggle_theme);
println!("Popup Menu Toggle Theme created: {:?}", self.menu_toggle_theme);
}
/// Remove the menu popup box
fn remove_menu(&mut self, ctx: &mut Context<'_>) {
ctx.remove_child(ctx.entity());
println!("Popup {:?} removed !", ctx.entity());
}
/// Remove the menu popup box
fn remove_menu_toggle_theme(&mut self, id: Entity, ctx: &mut Context<'_>) {
ctx.remove_child(self.menu_toggle_theme);
println!("Popup {:?} removed !", id);
}
/// Sets a new action.
pub fn set_action(&mut self, action: MenuAction) {
self.action = action.into();
}
}
/// 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<'_>) {
// Initialize required entities
// let menu_button = ctx
// .entity_of_child(ID_MENU_STACK)
// .expect("MenuState.init: Can't find resource entity 'PolicycheckView::ID_POLICY_CHECK_BUTTON_MENU'.");
}
/// 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::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::CreateMenu => {
println!("MenuAction::CreateMenu(_entity)");
self.create_menu(ctx);
}
MenuAction::CreateMenuToggleTheme(_entity) => {
self.create_menu_toggle_theme(ctx);
}
MenuAction::RemoveMenu => {
self.remove_menu(ctx);
}
MenuAction::RemoveMenuToggleTheme(entity) => {
self.remove_menu_toggle_theme(entity, ctx);
}
_ => (),
}
}
}
}
/// Create a new popup presenting the menu components
pub fn create_menu_popup(id: Entity, ctx: &mut BuildContext<'_>) -> Entity {
Popup::new()
.id(ID_MENU_POPUP)
.style("container_menu")
.target(id)
.open(true)
.width(280)
.height(140)
.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>(id)
.set_action(MenuAction::RemoveMenu);
},
_ => {
println!("KeyHandler: got {:?}", key_event.key);
},
};
true
})
.child(
Grid::new()
.id(ID_MENU_GRID)
.columns(
Columns::create()
.push("80") // Menu Button
.push("1") // Seperator
.push("*") // Keyboard Shortcut
.build(),
)
.rows(
Rows::create()
.push("auto")
.push("auto")
.push("auto")
.build(),
)
.child(
Button::new()
.id(ID_MENU_LABEL_ACCOUNT)
.style("button_menu")
.attach(Grid::row(0))
.attach(Grid::column(0))
.attach(Grid::column_span(2))
.icon(material_icons_font::MD_PERSON)
.text("Account")
.build(ctx),
)
.child(
Button::new()
.id(ID_MENU_LABEL_TOGGLE_THEME)
.style("button_menu")
.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>(id)
// .set_action(MenuAction::SetTheme(id));
// true
// })
.build(ctx),
)
.child(
Button::new()
.id(ID_MENU_LABEL_QUIT)
.style("button_menu")
.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)
.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)
}
/// Create a new popup submenu to toogle the active theme
pub fn create_menu_toggle_theme_popup(id: Entity, ctx: &mut BuildContext<'_>) -> Entity {
//let themes_count = themes.len();
//ProgressBar::val_set(&mut ctx.child(ID_POLICY_CHECK_PROGRESS_BAR), new_width);
Popup::new()
.id(ID_MENU_TOGGLE_THEME)
.style("container_menu")
.target(id)
.open(true)
.width(280)
.height(140)
.child(
ComboBox::new()
.attach(Grid::column(2))
.attach(Grid::row(6))
//.count(themes_count)
.items_builder(move |build_ctx, index| {
let theme_name =
MenuView::themes_ref(&build_ctx.get_widget(id))[index].clone();
TextBlock::new().v_align("center").text(theme_name).build(build_ctx)
})
.on_changed("selected_index", move |ctx, _| {
ctx.send_message(MenuAction::SetTheme, id);
println!("changed theme.");
})
.selected_index(id)
.build(ctx),
)
.build(ctx)
}

View File

@@ -1,82 +0,0 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use cfg_if::cfg_if;
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 {
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(),
];
}
}
//self.themes(themes).child(MenuState::create_menu(ID_MENU_POPUP, ctx))
self.themes(themes).child(
Stack::new()
.id(ID_MENU_STACK)
.child(
TextBlock::new()
.style("header")
.attach(Grid::row(0))
.attach(Grid::column(0))
.style("small_text")
.text("Select theme")
.build(ctx),
)
.child(
Button::new()
//.id("button_menu")
.id(ID_MENU_BUTTON)
.style("button_single_content")
.icon(material_icons_font::MD_MENU)
.attach(Grid::column(2))
.h_align("end")
.on_click(move |ctx, _| {
println!("WIP: open menu popup from MenuView");
ctx.get_mut::<MenuState>(id)
.set_action(MenuAction::CreateMenu);
true
})
.build(ctx),
)
.build(ctx),
)
}
}

View File

@@ -1,396 +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> {
lang: String,
policy_check: PolicyCheck,
policy_check_title: String,
policy_data_count: 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 policy_check_bottom_bar = Container::new()
//.style(STYLE_BOTTOM_BAR)
.attach(Grid::row(4))
.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 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")
.h_align("start")
.v_align("center")
.visibility(Visibility::Collapsed)
.enabled(false)
.build(ctx);
let policy_check_header_bar = Container::new()
.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_POLICY_CHECK_HEADER)
.v_align("center")
.h_align("left")
.text("Validation policy number")
.build(ctx),
)
.build(ctx),
)
.child(policy_check_button_menu)
.build(ctx);
let policy_check_form_row_0 = Stack::new()
// 1st row
.id(ID_POLICY_CHECK_FORM_ROW_0)
.attach(Grid::row(0))
.attach(Grid::column(0))
.attach(Grid::column_span(5))
.orientation("horizontal")
.v_align("center")
//.h_align("center")
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_LABEL_POLICY_NUMBER)
.style("body")
.attach(Grid::row(0))
.attach(Grid::column(0))
.margin((0, 0, 16, 0))
.h_align("end")
.v_align("center")
.width(300)
.min_width(300)
.text("Policy number")
.build(ctx),
)
.child(
TextBox::new()
.attach(Grid::row(0))
.attach(Grid::column(2))
.id(ID_POLICY_CHECK_POLICY_NUMBER)
.h_align("start")
.lose_focus_on_activation(false)
//WIP: localization for water_mark
.water_mark("10-stellig")
.on_activate(move |ctx, entity| {
// Entity is entered/activated via Mouse/Keyboard
//ctx.get_mut::<PolicycheckState>(policy_check_view)
ctx.get_mut::<PolicycheckState>(id)
.set_action(PolicycheckAction::ParseEntry(entity));
})
//.on_changed(|_, entity, _, _| println!("Selection changed: {:?}", entity))
// .on_changed(move |ctx, entity, _| {
// ctx.get_mut::<PolicycheckState>(id)
// .set_action(Action::SetProgressBox(entity));
// ctx.get_mut::<PolicycheckState>(id)
// .set_action(Action::AddProgress(0.5));
// ctx.get_mut::<PolicycheckState>(id)
// .set_action(Action::InputTextChanged(entity));
// ctx.get_mut::<PolicycheckState>(id)
// .set_action(Action::SetVisibility(entity));
// ctx.get_widget(policy_check_label_policy_number).set("visible");
// ctx.get_mut::<PolicycheckState>(id)
// .set_action(Action::SetVisility(entity));
// })
// .on_mouse_down | .on_mouse_move | .on_mouse_up (move |ctx, entity| {
// state(id, states).set_action(Action::AddItem);
// })
.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)
.build(ctx);
let policy_check_form_row_1 = Stack::new()
// 2nd row
.id(ID_POLICY_CHECK_FORM_ROW_1)
.attach(Grid::row(1))
.attach(Grid::column(0))
.attach(Grid::column_span(5))
.orientation("horizontal")
.v_align("center")
//.h_align("center")
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_LABEL_RESULT)
.style("body")
.attach(Grid::row(1))
.attach(Grid::column(0))
.margin((0, 0, 16, 0))
.h_align("end")
.v_align("center")
.width(300)
.min_width(300)
.text("Policy code")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_RESULT)
.style("body")
.attach(Grid::row(1))
.attach(Grid::column(2))
.h_align("start")
.v_align("center")
.text("empty")
.build(ctx)
)
.build(ctx);
let policy_check_form_row_2 = Stack::new()
// 3nd row
.id(ID_POLICY_CHECK_FORM_ROW_2)
.attach(Grid::row(2))
.attach(Grid::column(0))
.attach(Grid::column_span(5))
.orientation("horizontal")
.v_align("center")
.h_align("center")
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_LABEL_HINT)
//.style("hint")
.attach(Grid::row(2))
.attach(Grid::column(0))
.margin((0, 0, 16, 0))
.h_align("end")
.v_align("center")
.width(300)
.min_width(300)
.font_size(11.)
.text("Error:")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_POLICY_CHECK_HINT)
//.style("hint")
.attach(Grid::row(2))
.attach(Grid::column(2))
.h_align("start")
.v_align("center")
.font_size(11)
.build(ctx)
)
.build(ctx);
let policy_check_form = Container::new()
.id(ID_POLICY_CHECK_FORM)
.min_width(420)
.attach(Grid::row(2))
.attach(Grid::column(1))
.style("container_form")
.child(
Grid::new()
.id(ID_POLICY_CHECK_FORM)
.width(450)
.min_width(400)
.columns(
Columns::create()
// Label
.push("300")
// Seperator
.push("16")
// Values
.push("auto")
// Seperator
.push("16")
// Result-Button
.push("32")
//.build(),
)
.rows(
Rows::create()
.push("auto")
.push("auto")
.push("*")
//.build(),
)
.child(policy_check_form_row_0)
.child(policy_check_form_row_1)
.child(policy_check_form_row_2)
.build(ctx),
)
.build(ctx);
// WIP: this widget type should handle our target natively
// but it isn't able to get textinput, nor handle usize values
// ... yet
let _policy_check_numeric_box = NumericBox::new()
.id(ID_POLICY_CHECK_POLICY_NUMBER)
.h_align("start")
.width(100)
//.min(<usize>1000000000)
//.max(<usize>9999999999)
.val(0)
.min_width(95)
.margin((0, 0, 0, 16))
// WIP code @kivimango
// .on_activate(move |ctx, entity| {
// ctx.get_mut::<PolicycheckState>(id)
// .set_action(Action::ParseEntry(entity));
// })
// .on_changed(move |ctx, entity| {
// ctx.get_mut::<PolicycheckState>(id)
// .set_action(Action::InputTextChanged(entity));
//})
.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)
//.spacing("4")
.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)
.push("*")
.push(50)
//.build(),
)
.rows(
Rows::create()
.push("auto")
.push(28)
.push("*")
.push("auto")
.push("auto")
//.build(),
)
// row 0: Policy Check Header
.child(policy_check_header_bar)
// row 1: Seperator
// row 2: Policy Check Form
.child(policy_check_form)
// row 3: Sum HashMap elements
.child(policy_data_stack)
// row 4: Policy Check Bottom
.child(policy_check_bottom_bar)
.build(ctx),
)
}
}
// helper to request PolicycheckState
//fn state<'a>(id: Entity, states: &'a mut StatesContext) -> &'a mut PolicycheckState {
// states.get_mut(id)
//}

Submodule advotrackerd deleted from 409d8d1f1a

View File

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

View File

@@ -0,0 +1,17 @@
###
# .env
# will overwrite standard environment viariables
###
# set the language variable used in test-runs
#test LANG=de-DE
#test LANG=es-ES
#test LANG=C
# set the language variable (overwriting standard Enviroment)
#TEST_LANG=de_DE
#TEST_LANG=C
#RUST_LOG=advotracker=trace
#LANG=de_DE
RUST_LOG=trace
#RUST_LOG=none
USERNAME=hiedemann
DB_DRIVER=sqlite

View File

@@ -0,0 +1,16 @@
###
# .env
# will overwrite standard environment viariables
###
# set the language variable used in test-runs
#test LANG=es-ES
#test LANG=it-IT
#test LANG=C
# set the language variable (overwriting standard Enviroment)
#TEST_LANG=de_DE
#TEST_LANG=C
#RUST_LOG=advotracker=trace
RUST_LOG=trace
#RUST_LOG=none
USERNAME=hiedemann
DB_DRIVER=sqlite

View File

@@ -1,42 +1,54 @@
[package] [package]
name = "advotracker" name = "advotracker_client"
version = "0.1.4" version = "0.1.5-alpha2"
authors = ["Ralf Zerres <ralf.zerres@networkx.de>"] authors = ["Ralf Zerres <ralf.zerres@networkx.de>"]
description = "Frontend component that supports lawyers to capture relevant data encountered during an online legal advice." description = "Frontend component that supports lawyers to capture relevant data encountered during an online legal advice."
readme = "README.md" readme = "README.md"
license = "(0BSD OR MIT)" license = "(0BSD OR MIT)"
edition = "2018" edition = "2018"
default-run = "advotracker" default-run = "advotracker"
build = "build.rs"
[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] [target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = [ "winuser" ] } winapi = { version = "0.3", features = [ "winuser" ] }
#diesel = { version = "1.4", features = [ "postgres", "sqlite" ] } #diesel = { version = "1.4", features = [ "postgres", "sqlite" ] }
[target.'cfg(target_os = "windows")'.build-dependencies]
winres = { version = "0.1" }
# for language constants
winapi = { version = "0.3", features = [ "winnt" ] }
[dependencies] [dependencies]
async-stream = "~0.2" async-stream = "~0.2"
chrono = { version = "~0.4.0", features = ["serde"] } chrono = { version = "~0.4.0", features = ["serde"] }
cfg-if = { version = "~1.0" }
clap = { version = "~2.33", features = ["suggestions", "color"] } clap = { version = "~2.33", features = ["suggestions", "color"] }
csv = { version = "~1.1" } csv = { version = "~1.1" }
dotenv = { version = "~0.15.0" } dotenv = { version = "~0.15.0" }
envy = { version = "~0.4" } envy = { version = "~0.4" }
#lettre ={ version = "0.10.0-beta.1", features = ["smtp-transport", "native-tls", "hostname", "r2d2", "builder"] }
lettre ={ version = "0.10.0-beta.1" }
lazy_static = { version = "~1.4.0" } lazy_static = { version = "~1.4.0" }
log = { version = "~0.4.8" } log = { version = "~0.4.8" }
locales = { version = "~0.1" } locales = { version = "~0.1" }
maud = { version = "~0.22.1" }
#orbtk = { version = "~0.3.1-alpha4" } #orbtk = { version = "~0.3.1-alpha4" }
orbtk = { git = "https://github.com/redox-os/orbtk.git", branch = "develop" } #orbtk = { git = "https://github.com/redox-os/orbtk.git", branch = "develop" }
#orbtk = { path = "../../orbtk" } orbtk = { path = "../../../orbtk" }
serde = { version = "~1.0", features = ["derive"] } serde = { version = "~1.0", features = ["derive"] }
sdl2 = { version = "~0.34" }
substring = { version = "~1" }
#tokio = { version = "~0.2", features = ["macros", "rt-threaded", "stream", "time"] } #tokio = { version = "~0.2", features = ["macros", "rt-threaded", "stream", "time"] }
tracing = { version = "~0.1" } tracing = { version = "~0.1" }
tracing-subscriber = { version = "~0.2.0", features = ["tracing-log"] } tracing-subscriber = { version = "~0.2.0", features = ["tracing-log"] }
viperus = { git = "https://github.com/maurocordioli/viperus", features = ["cache", "fmt-clap", "fmt-env", "global", "watch"] } viperus = { git = "https://github.com/maurocordioli/viperus", features = ["cache", "fmt-clap", "fmt-env", "global", "watch"] }
[build-dependencies]
winres = { version = "0.1" }
#[dev-dependencies]
[features] [features]
# no features by default
default = [] default = []
debug = ["orbtk/debug"] debug = ["orbtk/debug"]
light = [] light = []
@@ -46,3 +58,14 @@ name = "advotracker"
identifier = "nwx.advotracker" identifier = "nwx.advotracker"
short_description = "Online legal advice helper." short_description = "Online legal advice helper."
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"
[package.metadata.winres]
LegalCopyright = "Copyright © 2020-2021"
#[[bin]]
#//name = "policycheck"
#path = "src/bin/policycheck.rs"
[[bin]]
name = "advotracker"
path = "src/main.rs"

View File

@@ -0,0 +1 @@
POLLFNR_WOECHENTLICH_test.txt

View File

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

View File

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

View File

@@ -0,0 +1 @@
Allianz DirectCall Protokoll!

View File

@@ -0,0 +1,38 @@
# About
This is the client component of `advotracker`.
## Windows specific
We like to support an icon an object attributes for the compiled
version of `advotracker`. While searching for a solution, the description of this
[Web link][https://graphicdesign.stackexchange.com/questions/77359/how-to-convert-a-square-svg-to-all-size-ico]
was adapted and combined with a `windres` crate.
### Icon creation
This commandline solution will create an icon that can be linked into the Windows binary.
* create the `svg` art file
You may use `inkscape`, a versitile and user frendly
tool to create your vector graphics art. Save it as `advotracker.svg`. Next export the scaled png files.
```
inkscape -w 16 -h 16 -o advotracker_16.png -l advotracker.svg
inkscape -w 32 -h 32 -o advotracker_32.png -l advotracker.svg
inkscape -w 48 -h 48 -o advotracker_48.png -l advotracker.svg
inkscape -w 64 -h 64 -o advotracker_64.png -l advotracker.svg
```
* create the `ico` file
The ico format can handle multiple layes with different resolutions.
We make use of ImageMagick to create the icon file like this:
```
convert advotracker_16.png advotracker_32.png advotracker_48.png advotracker_64.png advotracker.ico
```
* link in the icon
rust offers the `windres` crate, that will handle the linking of icons
as well as the definition of binary objet resources. `advotracker`
will define the needed settings in its `build.rs` file.

View File

@@ -0,0 +1,61 @@
// *
// * 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
"Check result": "Prüfungsergebnis",
"Checklist elements: ": "Prüflistenelemente: ",
"Clear": "Zurücksetzen",
"Create ticket": "Ticket erstellen",
"Importing data": "Importiere Datensätze",
"Only numbers are valid": "Nur Nummern sind zulässig",
"Error:": "Fehler:",
"Quit": "Beenden",
"Policy code": "Vers.-Schein/Schadennummer",
"Policy holder": "Versicherungsnehmer",
"Policy number is to long": "Die Nummer ist zu lang",
"Policy number is to short": "Die Nummer ist zu kurz",
"Policy number": "Versicherungsnummer",
"Processing time": "Bearbeitungszeit",
"Reason": "Grund",
"The given policy number is invalid": "Die Versicherungsnummer ist ungültig",
"The given policy number is valid": "Die Versicherungsnummer ist gültig",
"Account": "Benutzer",
"Toggle theme": "Thema wechseln",
"Validation policy number": "Prüfung Versicherungsnummer",
// 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
"English": "Englisch",
"German": "Deutsch",
"Language ID": "Sprache ID",
"Localization dialog": "Lokalisierungs-Dialog",
// configuration view
"Configuration settings": "Konfigurationseinstellungen",
"Configuration file": "Konfigurationsdatei",
"Default theme": "Standard-Thema",
"Language Id": "Sprach-Id",
"Load": "Laden",
"Save": "Speichern",
}
)

View File

@@ -0,0 +1,179 @@
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,
},
),
"combo_box_popup": (
base: "popup_box_popup",
properties: {
"height": 80,
"min_height": 80,
"width": 160,
"min_width": 80,
},
),
"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",
},
),
"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_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

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 220 B

After

Width:  |  Height:  |  Size: 220 B

View File

Before

Width:  |  Height:  |  Size: 123 B

After

Width:  |  Height:  |  Size: 123 B

View File

Before

Width:  |  Height:  |  Size: 123 B

After

Width:  |  Height:  |  Size: 123 B

View File

Before

Width:  |  Height:  |  Size: 289 B

After

Width:  |  Height:  |  Size: 289 B

View File

Before

Width:  |  Height:  |  Size: 126 B

After

Width:  |  Height:  |  Size: 126 B

View File

Before

Width:  |  Height:  |  Size: 158 B

After

Width:  |  Height:  |  Size: 158 B

View File

Before

Width:  |  Height:  |  Size: 351 B

After

Width:  |  Height:  |  Size: 351 B

View File

Before

Width:  |  Height:  |  Size: 130 B

After

Width:  |  Height:  |  Size: 130 B

View File

Before

Width:  |  Height:  |  Size: 193 B

After

Width:  |  Height:  |  Size: 193 B

View File

Before

Width:  |  Height:  |  Size: 452 B

After

Width:  |  Height:  |  Size: 452 B

View File

Before

Width:  |  Height:  |  Size: 131 B

After

Width:  |  Height:  |  Size: 131 B

View File

Before

Width:  |  Height:  |  Size: 223 B

After

Width:  |  Height:  |  Size: 223 B

View File

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

View File

@@ -0,0 +1,143 @@
<?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="181.41733"
height="181.41733"
viewBox="0 0 48 48"
version="1.1"
id="svg8"
sodipodi:docname="Hotline.svg"
inkscape:version="1.0.2 (e86c870879, 2021-01-15)"
inkscape:export-filename="/data/development/advotracker/images/Hotline.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<title
id="title903">Hotline</title>
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="3.5001171"
inkscape:cx="106.62221"
inkscape:cy="103.19504"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="false"
units="px"
inkscape:window-width="1280"
inkscape:window-height="656"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
showguides="false"
inkscape:guide-bbox="true">
<sodipodi:guide
position="-2.2601038,30.435621"
orientation="0,-1"
id="guide1331" />
</sodipodi:namedview>
<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>Hotline</dc:title>
<cc:license
rdf:resource="http://artlibre.org/licence/lal" />
</cc:Work>
<cc:License
rdf:about="http://artlibre.org/licence/lal">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Hotline-Icon"
inkscape:groupmode="layer"
id="layer1"
style="display:inline">
<g
id="g1369"
transform="translate(47.971251,-0.00147642)">
<path
style="fill:#ffc49b;fill-opacity:0.470588;stroke:#d1b5a4;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.988588;paint-order:markers fill stroke"
d="m -43.193278,41.999791 c 1.49691,-2.40444 3.504494,-4.137234 3.97049,-7.897551 -8.897002,-20.115732 11.448594,-39.761883 23.320156,-25.6774766 4.111107,0.7296566 15.904257,0.2419988 9.448496,27.2025326 0.655793,2.44805 2.687955,4.433014 5.1147,6.285219 -7.038787,4.303603 -14.139814,3.119543 -21.26392,-0.09939 -7.121959,1.345389 -14.838126,5.638639 -20.589922,0.186666 z"
id="path954"
sodipodi:nodetypes="ccccccc" />
<path
style="fill:#fff69f;fill-opacity:1;stroke:#d1b4a3;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.992157;paint-order:markers fill stroke"
d="m -16.566294,17.564379 c 2.321537,1.627329 4.680103,3.221015 5.43583,6.271019 l -0.128201,11.537305 c -1.500786,4.68743 -3.897101,6.738521 -6.558077,8.314102 -1.547997,0.916578 -2.915462,2.596633 -4.733266,2.74464 -2.358949,0.192067 -3.335981,-1.37334 -4.702985,-2.208498 -10.561198,-6.452258 -9.299955,-15.045913 -3.54451,-18.563078 5.999351,-1.157234 11.292071,-3.485647 14.231209,-8.09549 z"
id="path956"
sodipodi:nodetypes="cccssscc" />
<path
style="fill:none;fill-opacity:1;stroke:#acbac7;stroke-width:0.999997;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
d="m -5.8305041,36.150455 c 0.3952343,5.0031 -3.5482004,3.771616 -15.3273579,3.956909"
id="path1001"
sodipodi:nodetypes="cc" />
<g
id="g1357">
<circle
style="opacity:0.902314;fill:#8c8c8c;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.470588;paint-order:markers fill stroke"
id="path1314"
cx="-16.847094"
cy="31.137058"
r="1.6374409" />
<circle
style="opacity:0.902314;fill:#8c8c8c;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.470588;paint-order:markers fill stroke"
id="circle1316"
cx="-29.12112"
cy="31.137058"
r="1.6374409" />
<ellipse
style="opacity:0.902314;fill:#8c8c8c;fill-opacity:1;stroke:none;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.470588;paint-order:markers fill stroke"
id="path1301"
ry="1.5932699"
rx="2.0367212"
cy="39.994835"
cx="-22.984106" />
</g>
<g
id="g1337"
transform="translate(0,1.7607786)">
<rect
style="opacity:1;vector-effect:none;fill:#d9e0e5;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect1293"
width="4.1744041"
height="8.3096123"
x="-7.5382333"
y="25.556793" />
<path
style="opacity:0.902314;mix-blend-mode:normal;fill:none;fill-opacity:0.975108;stroke:#acbac7;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:markers fill stroke"
d="m -7.6299573,25.267021 c 0,0 4.3765084,-0.627056 4.3333554,0.61985 -0.090936,2.627603 0.2119865,5.547594 -0.1762703,7.668357 -0.2291003,1.251407 -4.3491445,0.568011 -4.3491445,0.568011 z"
id="path999"
sodipodi:nodetypes="csscc" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

Before

Width:  |  Height:  |  Size: 768 B

After

Width:  |  Height:  |  Size: 768 B

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

Before

Width:  |  Height:  |  Size: 455 KiB

After

Width:  |  Height:  |  Size: 455 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 237 KiB

After

Width:  |  Height:  |  Size: 237 KiB

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@@ -0,0 +1,19 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use winres;
fn main() {
if cfg!(target_os = "windows") {
let mut res = winres::WindowsResource::new();
res.set_icon("assets/icons/adovtracker/advotracker.ico")
.set("InternalName", "ADVOTRACKER.EXE")
// manually set version 0.1.5.2
.set_version_info(winres::VersionInfo::PRODUCTVERSION, 0x0000000100050002);
res.compile().unwrap();
}
}

View File

@@ -0,0 +1,89 @@
/*
* OrbTk - The Orbital Widget Toolkit
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (MIT)
*/
// use orbtk::prelude::*;
// /*
// * WidgetContainer = entity
// */
// // methods get, get_mut, try_get, try_get_mut and clone
// // ctx.widget returns a WidgetContainer that wraps the current widget of the state
// let mut widget_container: WidgetContainer = ctx.widget();
// // property handling (componets)
// // Gets a reference for the property
// // .get<PropertyType>("property_name");
// widget_container.get::<String16>("text");
// // Sets the value of a property
// // .set<PropertyType>("property_name", property_value);
// widget_container.set::<String16>("text", "my_text");
// /*
// * Child WidgetContainer = child entity
// */
// // child of a state's widget, that is referenced by an entity id.
// // e.g: .child(TextBox::new().id(child_entity_id).build(ctx)
// let mut child: WidgetContainer = ctx.get_widget(child_entity_id);
// // child of a state's widget that is referenced by an string id
// // e.g: .child(TextBox::new().id("text_box_id").build(ctx)
// let child: WidgetContainer = ctx.child("text_box_id");
// // property handling (components)
// // Gets an TextBoxCtx wrapper for the text box child.
// let mut text_box: TextBoxCtx = text_box(ctx.child("text_box_id"));
// // or as an alternative:
// let text_box: TextBoxCtx = TextBox::get(ctx.child("text_box_id"));
// // get child field attributes
// let text_len = text_box.text().len();
// // set child field attributes
// text_box.set_text("My new text");
// /*
// * Registry handling
// */
// // register service
// fn update(registry: &mut Registry, _: &mut Context) {
// registry.register("my_db_serve", MyDBServie::new());
// }
// // access service
// fn update(registry: &mut Registry, _: &mut Context) {
// let mut my_db_service: MyDBSerivce = registry.get_mut("my_db_service");
// }
// API Update: access properties of widgets in states
// Old style
// let text = *button(&mut ctx.widget()).text();
// let text = Button::get(&mut ctx.widget()).text();
// let text = *button(&mut ctx.widget()).clone_text();
// let text = Button::get(&mut ctx.widget()).clone_text();
// button(&mut ctx.widget()).text_mut().push_str("test");
// Button::get(&mut ctx.widget()).text_mut().push_str("test");
// button(&mut ctx.widget()).set_text(String16::from("test"));
// Button::get(&mut ctx.widget()).set_text(String16::from("test"));
// Current style
// let text = Button::text_clone(&ctx.widget());
// Button::text_mut(&mut ctx.widget()).push_str("test");
// Button::text_set(&mut ctx.widget(), String16::from("test"));
//
// TextBehaviour::offset_set(&mut ctx.widget(self.text_block), offset);
// or
// ctx.get_widget(self.text_block).set("offset", offset);
fn main() {}

View File

@@ -0,0 +1,800 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
// suppress creation of a new console window on window
#![windows_subsystem = "windows"]
use locales::t;
use orbtk::{
prelude::*,
theme_default::{THEME_DEFAULT, THEME_DEFAULT_COLORS_DARK, THEME_DEFAULT_FONTS},
theming::config::ThemeConfig,
};
use cfg_if::cfg_if;
use serde::Deserialize;
use std::env;
use std::time::SystemTime;
use tracing::{Level, info, trace};
use advotracker::{
data::{constants::*, structures::Email},
widgets::global_state::GlobalState,
//services::exports::send_ticketdata::sendticketdata,
widgets::policycheck::*,
widgets::policycheck_state::*,
widgets::main_view,
widgets::ticketdata::*,
};
#[cfg(target_os = "windows")]
use orbtk::theme_fluent::{THEME_FLUENT, THEME_FLUENT_COLORS_DARK, THEME_FLUENT_FONTS};
pub enum TicketdataAction {
ClearForm(),
SendForm(),
UpdatePolicyCode(String)
}
// 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);
// 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)),
))
}
}
}
// Main
fn main() -> Result<(), Box<dyn std::error::Error>> {
// 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(trace)
//.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);
// 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(())
}
// View
widget!(MainView {
policycheck_view: PolicyCheck
});
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)
.build(ctx);
self.name("MainView")
.child(
TabWidget::new()
.tab(ID_POLICY_CHECK_VIEW, policycheck_view)
.tab(ID_TICKET_DATA_VIEW, ticketdata_view)
.build(ctx),
)
}
}
// Macro that initializes the widget structures/variables for the policy check view
widget!(
/// Form to enter data of a ticket record
TicketdataView<TicketdataState> {
// language used inside the widget
lang: String,
// title used in the header
ticket_data_title: String,
// entity id that will receive the messages
target: u32
}
);
/// The template implementation of the ticket view
/// All GUI elements are styled using the "style" attribute referencing to a ron based css
impl Template for TicketdataView {
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 ticket_data_bottom_bar = Container::new()
.id(ID_TICKET_DATA_BOTTOM_BAR)
.style(STYLE_BOTTOM_BAR)
.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 ticket_data_button_menu = Button::new()
.id(ID_TICKET_DATA_BUTTON_MENU)
.attach(Grid::row(0))
.attach(Grid::column(2))
.h_align("end")
.icon(material_icons_font::MD_MENU)
//.style("button_single_content")
.style(STYLE_BUTTON_MENU)
.build(ctx);
let ticket_data_form = Container::new()
.id(ID_TICKET_DATA_FORM)
.name(ID_TICKET_DATA_FORM)
.attach(Grid::row(2))
.attach(Grid::column(1))
.style("container_form")
.child(
Grid::new()
.id(ID_TICKET_DATA_GRID)
.name(ID_TICKET_DATA_GRID)
.columns(
Columns::create()
.push("auto") // Label
.push(16) // Delimiter
.push("*") // Data
.push(32) // Delimiter (2x margin)
)
.rows(
Rows::create()
.push("auto") // Row 0
.push(14) // Seperator
.push("auto") // Row 2
.push(14) // Seperator
.push("auto") // Row 4
.push(14) // Seperator
.push("auto") // Row 6
.push(14) // Seperator
.push("auto") // Row 8
.push(14) // Seperator
.push("auto") // Row 10
.push(14) // Seperator
.push("auto") // Row 12
.push(14) // Seperator
)
.child(
TextBlock::new()
.id(ID_TICKET_DATA_LABEL_POLICY_CODE)
.attach(Grid::row(0))
.attach(Grid::column(0))
.text("Policy code")
.h_align("end")
.v_align("center")
.build(ctx),
)
.child(
TextBox::new()
.id(ID_TICKET_DATA_POLICY_CODE)
.attach(Grid::row(0))
.attach(Grid::column(2))
.text("")
.v_align("center")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_TICKET_DATA_LABEL_POLICY_HOLDER)
.attach(Grid::row(2))
.attach(Grid::column(0))
.text("Policy holder")
.h_align("end")
.v_align("center")
.build(ctx),
)
.child(
TextBox::new()
.id(ID_TICKET_DATA_POLICY_HOLDER)
.attach(Grid::row(2))
.attach(Grid::column(2))
.text("")
.water_mark("Name des Versicherungsnehmers")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_TICKET_DATA_LABEL_DEDUCTIBLE)
.attach(Grid::row(4))
.attach(Grid::column(0))
.text("Deductible")
.h_align("end")
.v_align("center")
.build(ctx),
)
.child(
TextBox::new()
.id(ID_TICKET_DATA_DEDUCTIBLE)
.attach(Grid::row(4))
.attach(Grid::column(2))
.text("")
.water_mark("im Beratungsgespräch erfragen")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_TICKET_DATA_LABEL_CALLBACK_NUMBER)
.attach(Grid::row(6))
.attach(Grid::column(0))
.text("Callback number")
.h_align("end")
.v_align("center")
.build(ctx),
)
.child(
TextBox::new()
.id(ID_TICKET_DATA_CALLBACK_NUMBER)
.attach(Grid::row(6))
.attach(Grid::column(2))
.text("")
.water_mark("wie zu erreichen")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_TICKET_DATA_LABEL_CALLBACK_DATE)
.attach(Grid::row(8))
.attach(Grid::column(0))
.text("Callback date")
.h_align("end")
.v_align("center")
.build(ctx),
)
.child(
TextBox::new()
.id(ID_TICKET_DATA_CALLBACK_DATE)
.attach(Grid::row(8))
.attach(Grid::column(2))
.text("")
.water_mark("Rückruf gewünscht um")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_TICKET_DATA_LABEL_HARM_TYPE)
.attach(Grid::row(10))
.attach(Grid::column(0))
.text("Harm type")
.h_align("end")
.v_align("center")
.build(ctx),
)
.child(
TextBox::new()
.id(ID_TICKET_DATA_HARM_TYPE)
.name(ID_TICKET_DATA_HARM_TYPE)
.attach(Grid::row(10))
.attach(Grid::column(2))
.text("")
.water_mark("Schadenstyp")
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_TICKET_DATA_LABEL_IVR_COMMENT)
.attach(Grid::row(12))
.attach(Grid::column(0))
.text("IVR comment")
.h_align("end")
.v_align("center")
.build(ctx),
)
.child(
TextBox::new()
.id(ID_TICKET_DATA_IVR_COMMENT)
.attach(Grid::row(12))
.attach(Grid::column(2))
.text("")
.water_mark("Kommentar zur Haftung, bzw. zur Deckung")
//.height(48.0)
.build(ctx),
)
.build(ctx),
)
.build(ctx);
let ticket_data_form_action = Container::new()
.id(ID_TICKET_DATA_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_TICKET_DATA_ACTION_BUTTON_CLEAR)
.style(STYLE_BUTTON_ACTION)
.text("Clear")
.on_click(move |states, _| {
states.send_message(TicketdataAction::ClearForm(), id);
false
})
.build(ctx),
)
.child(
Button::new()
.id(ID_TICKET_DATA_ACTION_BUTTON_SEND)
.style(STYLE_BUTTON_ACTION)
.text("Send")
//.visibility(Visibility::Collapsed)
.on_click(move |states, _entity| {
states.send_message(TicketdataAction::SendForm(), id);
false
})
.build(ctx),
)
.build(ctx),
)
.build(ctx);
// vector with valid mail recipients addresses (mail_to)
let items_mail_to = vec![
PROP_MAIL_TO_1,
PROP_MAIL_TO_2,
PROP_MAIL_TO_3,
PROP_MAIL_TO_4,
];
let items_mail_to_count = items_mail_to.len();
// vector with valid carbon copy recipients addresses (mail_to)
let items_mail_cc = vec![
PROP_MAIL_CC_1,
PROP_MAIL_CC_2,
];
let items_mail_cc_count = items_mail_cc.len();
let ticket_data_form_mail = Container::new()
.id(ID_TICKET_DATA_CONTAINER_MAIL)
.name(ID_TICKET_DATA_CONTAINER_MAIL)
.attach(Grid::row(1))
.attach(Grid::column(1))
.style(STYLE_CONTAINER_MAIL)
.child(
Grid::new()
.columns(
Columns::create()
.push(16) // Delimiter
.push("stretch") // Label
.push(16) // Delimiter
.push("auto") // MailAddress
.push("32") // Delimiter (2x margin)
)
.rows(
Rows::create()
.push("auto") // Row 0
.push(2) // Seperator
.push("auto") // Row 2
.push(2) // Seperator
)
.child(
TextBlock::new()
.id(ID_TICKET_DATA_MAIL_TO)
.attach(Grid::row(0))
.attach(Grid::column(1))
.style(STYLE_MAIL_LABEL)
.text("Recipient (To)")
.build(ctx),
)
.child(
/// WIP: get selected item
ComboBox::new()
.id(ID_TICKET_DATA_MAIL_TO)
.attach(Grid::row(0))
.attach(Grid::column(3))
.style(STYLE_MAIL_TO)
.count(items_mail_to_count)
.items_builder(move |ibc, index| {
let text_mail_to = TicketdataView::items_mail_to_ref(&ibc.get_widget(id))[index].clone();
TextBox::new()
.text(text_mail_to)
.v_align("center")
.build(ibc)
})
.selected_index(0)
.build(ctx),
)
.child(
TextBlock::new()
.id(ID_TICKET_DATA_LABEL_MAIL_CC)
.attach(Grid::row(2))
.attach(Grid::column(1))
.style(STYLE_MAIL_LABEL)
.text("Copie (CC)")
.build(ctx),
)
.child(
ComboBox::new()
.id(ID_TICKET_DATA_MAIL_CC)
.attach(Grid::row(2))
.attach(Grid::column(3))
.style(STYLE_MAIL_CC)
.count(items_mail_cc_count)
.items_builder(move |ibc, index| {
let text_mail_cc = TicketdataView::items_mail_cc_ref(&ibc.get_widget(id))[index].clone();
TextBox::new()
.text(text_mail_cc)
.v_align("center")
.build(ibc)
})
.selected_index(0)
.build(ctx),
)
.build(ctx),
)
.build(ctx);
let ticket_data_header_text = TextBlock::new()
.id(ID_TICKET_DATA_HEADER)
.attach(Grid::column(0))
.style(STYLE_HEADER_TEXT)
.text("Ticket Data")
.build(ctx);
let ticket_data_header_bar = Container::new()
.id(ID_TICKET_DATA_HEADER_BAR)
.attach(Grid::row(0))
.attach(Grid::column_span(3))
.style(STYLE_HEADER_BAR)
.child(tenent_logo)
.child(ticket_data_header_text)
.child(ticket_data_button_menu)
.build(ctx);
// Widget: Ticket data view
self.id(ID_TICKET_DATA_VIEW)
.name(ID_TICKET_DATA_VIEW)
.min_height(410.0)
.child(
Grid::new()
.id(ID_TICKET_DATA_GRID)
.columns(
Columns::create()
.push(50) // Left margin
.push("*") // Content
.push(50) // Right margin
)
.rows(
Rows::create()
.push("auto") // Header_Bar
.push("auto") // Mail_Form
.push("*") // Input_Form
.push("auto") // Action
.push("auto") // Bottom_Bar
)
.child(ticket_data_header_bar) // row 0
.child(ticket_data_form_mail) // row 1
.child(ticket_data_form) // row 2
.child(ticket_data_form_action) // row 3
.child(ticket_data_bottom_bar) // row 4
.build(ctx),
)
}
}
// State
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, ctx: &mut Context<'_>) {
if let Some(count) = ctx.get_widget(entity).children_count() {
info!("Widget name: {:?}", ctx.get_widget(entity).get::<String>("name"));
info!("Widget id: {:?}", ctx.get_widget(entity).get::<String>("id"));
}
// identify the form by its id
if let form_entity = ctx.child(ID_TICKET_DATA_GRID).entity() {
info!("Form id: {:?}", ctx.get_widget(form_entity).get::<String>("id"));
info!("Form node name: {:?}", ctx.get_widget(form_entity).get::<String>("name"));
// Loop through children
if let Some(count) = ctx.get_widget(form_entity).children_count() {
for c in 1..=count {
info!("WIP clear entry of child {:?}", c);
//info!("WIP clear entry of child {:?}: {:?}", c, ctx.get_child(form_entity).get::<String>("name"));
}
}
}
}
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
let _ = sendticketdata(&email, &lang);
}
}
/// 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 entities
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'.");
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);
}
fn messages(
&mut self,
mut messages: MessageReader,
_registry: &mut Registry,
ctx: &mut Context<'_>,
) {
for message in messages.read::<TicketdataAction>() {
match message {
TicketdataAction::ClearForm() => {
info!("message: {:?} recieved", message);
TicketdataState::clear_form(ctx.entity(), 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, _: &mut Registry, ctx: &mut Context<'_>) {
let actions: Vec<TicketdataAction> = self.actions.drain(..).collect();
for action in actions {
match action {
TicketdataAction::ClearForm() => {
info!("update: send_message {:?}", action);
ctx.send_message(TicketdataAction::ClearForm(), self.target);
}
TicketdataAction::SendForm() => {
//ctx.send_message(TicketdataAction::SendForm(), self.ID_TICKETDATA_FORM);
info!("update: send_message {:?}", action);
}
_ => { println!("TicketdataAction: action not implemented!"); }
}
}
}
}
/// 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);
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)),
)
)
.expect("failed to build email");
info!("message: {:?}", message);
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

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

View File

@@ -9,9 +9,12 @@ use chrono::{Local, DateTime};
use locales::t; use locales::t;
//use serde::{Deserialize, Serialize}; //use serde::{Deserialize, Serialize};
use serde::Deserialize; use serde::Deserialize;
use std::env; use std::{
use std::{error::Error, process}; collections::HashMap,
use std::collections::HashMap; env,
{error::Error, process},
//path::{Path, PathBuf},
};
use tracing::{debug, trace, Level}; use tracing::{debug, trace, Level};
use advotracker::data::structures::{PolicyCode, PolicyList, PolicyDataList, PolicyData}; use advotracker::data::structures::{PolicyCode, PolicyList, PolicyDataList, PolicyData};
@@ -49,14 +52,6 @@ fn export(p: &mut String, lang: &String) -> Result<u64, Box<dyn Error>> {
// Note: slash syntax also works on Windows! // Note: slash syntax also works on Windows!
let path = Path::new(p); let path = Path::new(p);
// only create files with a '.txt' extensions
//let extension = path.extension();
// match extension {
// //Some(String) => println!("file extension ok!"),
// //_ => extension = OsStr::new("txt")
// _ => println!("got file extension {:?}", extension)
// };
// open the file descriptor // open the file descriptor
let mut file = File::create(path)?; let mut file = File::create(path)?;
trace!(target: "csv-export", extension = ?path.extension(), file = ?file); trace!(target: "csv-export", extension = ?path.extension(), file = ?file);
@@ -103,10 +98,6 @@ fn import(p: &mut String, data_list: &mut PolicyDataList,
// must be a readable file // must be a readable file
trace!(target: "csv-test", path = ?path); trace!(target: "csv-test", path = ?path);
let valid = path.is_file();
println!("is_file: {}", valid);
//if let Some(res) = valid
assert_eq!(path.is_file(), true); assert_eq!(path.is_file(), true);
// only accept files with '.txt' extensions // only accept files with '.txt' extensions
@@ -333,8 +324,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
state = t!("state.started", lang); state = t!("state.started", lang);
trace!(target: "csv-test", process = ?res, state = ?state); trace!(target: "csv-test", process = ?res, state = ?state);
// importing policy code elements from csv-file // create policy structures
let policy_list = PolicyList::new("Allianz Versicherungsnummen-List"); let policy_list = PolicyList::new("Allianz Versicherungsnummen-Liste");
println!("Policy List {:?} ", policy_list.name); println!("Policy List {:?} ", policy_list.name);
let mut policy_data = PolicyDataList::new("Allianz-Import 20200628"); let mut policy_data = PolicyDataList::new("Allianz-Import 20200628");
@@ -355,9 +346,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
// test if policy_number is_valid // test if policy_number is_valid
let test_policy_number = v.get::<i32>("test_policy_number").unwrap() as u64; // 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); trace!(target: "csv-test", test_policy_number = ?test_policy_number);
//let policy_number : u64 = 1999999999;
//match is_valid(&policy_number, &policy_data, &mut policy_numbers, &lang) { //match is_valid(&policy_number, &policy_data, &mut policy_numbers, &lang) {
// Ok(true) => { // Ok(true) => {
// use Hashmap method 'get' to check if we have the given key // use Hashmap method 'get' to check if we have the given key
@@ -394,3 +385,25 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
Ok(()) 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

@@ -25,7 +25,7 @@ pub fn parse_args(v: &mut Viperus) -> Result<(), Box<dyn std::error::Error>> {
v.add_default("config_file", String::from("csv_import.ron")); v.add_default("config_file", String::from("csv_import.ron"));
v.add_default("import_file", String::from("POLLFNR_WOECHENTLICH.txt")); v.add_default("import_file", String::from("POLLFNR_WOECHENTLICH.txt"));
v.add_default("export_file", String::from("")); v.add_default("export_file", String::from(""));
v.add_default("test_policy_number", 123456789); 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("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("from_email_address_file", String::from("Allianz-Hotline RA-Hiedemann <azhotline@hiedemann.de>"));
//v.add_default("username", String::from("nctalkbot")); //v.add_default("username", String::from("nctalkbot"));
@@ -188,7 +188,7 @@ SMR Unerledigt: 089 92529 60222")
); );
println!( println!(
"test_policy_number: {:?}", "test_policy_number: {:?}",
v.get::<i32>("test_policy_number").unwrap_or_default() v.get::<String>("test_policy_number").unwrap_or_default()
); );
// println!( // println!(
// "username: {:?}", // "username: {:?}",

View File

@@ -0,0 +1,40 @@
use lettre::{
transport::smtp::authentication::Credentials,
Message, SmtpTransport, Transport,
};
fn main() {
let email = Message::builder()
.from("Info <info@networkx.de>".parse().unwrap())
.reply_to("Support <support@networkx.de>".parse().unwrap())
.to("Ralf Zerres <ralf.zerres@networkx.de>".parse().unwrap())
.subject("Eine advotracker eMail")
.body("Eine neue advotracker eMail!".to_string())
.unwrap();
// Create credential for remote authentication (username, password)
//let creds = Credentials::new("ralf.zerres@networkx.de".to_string(), "dekifjgh".to_string());
let creds = Credentials::new("ralf.zerres.de@gmail.com".to_string(), "20jacara03".to_string());
// Open a remote connection to relay server
//let mailer = SmtpTransport::relay("nwxex.networkx.de")
let mailer = SmtpTransport::relay("smtp.gmail.com")
.unwrap()
.credentials(creds)
.build();
// Open a remote connection to gmail using STARTTLS
// let mailer = SmtpTransport::starttls_relay("nwxex.networkx.de")
// .unwrap()
// .credentials(creds)
// .build();
// Open a local connection on port 25
//let mailer = SmtpTransport::unencrypted_localhost();
// Send the email
match mailer.send(&email) {
Ok(_) => println!("Email sent successfully!"),
Err(e) => panic!("Could not send email: {:?}", e),
}
}

View File

@@ -0,0 +1,23 @@
/*
* OrbTK - The Orbital Widget Toolkit
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
// constants
pub static ID_RECEIVER: &str = "Receiver_Widget";
pub static ID_RECEIVER_CONTAINER: &str = "reciever_container";
pub static ID_RECEIVER_PROGRESS_BAR: &str = "receiver_progress_bar";
pub static ID_RECEIVER_TEXT_BLOCK: &str = "receiver_text_block";
//pub static ID_RECEIVER_MESSAGE_BOX: &str = "receiver_message_box";
pub static ID_RECEIVER_MESSAGE_BLOCK: &str = "receiver_message_block";
//pub static ID_RECEIVER_MESSAGE: &str = "receiver_message";
pub static ID_SENDER: &str = "Sender_Widget";
pub static ID_SENDER_CONTAINER: &str = "sender_container";
pub static ID_SENDER_GRID: &str = "sender_grid";
pub static ID_SENDER_BUTTON: &str = "sender_button";
pub static ID_SENDER_TEXT_BOX: &str = "sender_text_box";
pub static COLOR_BOMBAY: &str = "#adb3B8";

View File

@@ -0,0 +1,9 @@
/*
* OrbTK - The Orbital Widget Toolkit
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
/// provides orbtk widgets constants
pub mod constants;

View File

@@ -0,0 +1,32 @@
/*
* 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

@@ -0,0 +1,48 @@
/*
* 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

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

View File

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

View File

@@ -0,0 +1,70 @@
/*
* 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

@@ -0,0 +1,37 @@
/*
* 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

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

View File

@@ -0,0 +1,58 @@
/*
* 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

@@ -0,0 +1,34 @@
/*
* 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

@@ -0,0 +1,143 @@
use orbtk::prelude::*;
//|---------------------------------------------------------------------------|
//|------------------------------SENDER---------------------------------------|
//|---------------------------------------------------------------------------|
// View
widget!(SenderWidget<SenderState> {
// the Entity of the widget that will receive the messages
target: u32
});
impl Template for SenderWidget {
fn template(self, id: Entity, bc: &mut BuildContext) -> Self {
self.name("SenderWidget")
.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();
false
})
.build(bc)
)
}
}
// States
enum Action {
UpdateProgress(f64)
}
#[derive(Default, AsAny)]
struct SenderState {
actions: Vec<Action>,
target: Entity
}
impl SenderState {
fn send_message(&mut self) {
self.actions.push(Action::UpdateProgress(0.1));
}
}
impl State for SenderState {
fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
self.target = Entity::from(ctx.widget().try_clone::<u32>("target")
.expect("ERROR: SenderState::init(): target entity not found!"));
}
fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
let actions: Vec<Action> = self.actions.drain(..).collect();
for action in actions {
match action {
Action::UpdateProgress(amount) => {
ctx.send_message(Action::UpdateProgress(amount), self.target);
println!("Message sent!");
}
}
}
}
}
//|---------------------------------------------------------------------------|
//|------------------------------RECEIVER-------------------------------------|
//|---------------------------------------------------------------------------|
// View
widget!(ReceiverWidget<ReceiverState>);
impl Template for ReceiverWidget {
fn template(self, _id: Entity, bc: &mut BuildContext) -> Self {
self.name("ReceiverWidget")
.child(
ProgressBar::new()
.id("progress_bar")
.build(bc)
)
}
}
// States
#[derive(Default, AsAny)]
struct ReceiverState {
progress_bar: Entity
}
impl State for ReceiverState {
fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
self.progress_bar = ctx.entity_of_child("progress_bar").expect("Cannot find ProgressBar!");
}
fn messages(&mut self, mut messages: MessageReader, _registry: &mut Registry, ctx: &mut Context) {
for action in messages.read::<Action>() {
match action {
Action::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);
}
}
}
}
}
//|---------------------------------------------------------------------------|
//|--------------------------------MAIN---------------------------------------|
//|---------------------------------------------------------------------------|
pub fn main() {
Application::new()
.window(|ctx| {
let receiver = ReceiverWidget::new().build(ctx);
let sender = SenderWidget::new()
// the entity of the target (receiver)
.target(receiver.0)
.build(ctx);
Window::new()
.title("Messages example")
.position((100.0, 100.0))
.resizeable(true)
.size(450.0, 500.0)
.child(
Stack::new()
.orientation("vertical")
.child(sender)
.child(receiver)
.build(ctx)
)
.build(ctx)
})
.run();
}

View File

@@ -0,0 +1,112 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
fn main() {
// use this only if you want to run it as web application.
orbtk::initialize();
Application::new()
.window(|ctx| {
Window::new()
.title("OrbTk - Pager test")
.position((100, 100))
.size(800, 600)
.resizeable(true)
.child(PagerTestView::new().build(ctx))
.build(ctx)
})
.run();
}
// Views
widget!(
PagerTestView<PagerTestState> {}
);
impl Template for PagerTestView {
fn template(self, id: Entity, ctx: &mut BuildContext<'_>) -> Self {
let pager = Pager::new()
.attach(Grid::row(1))
.child(TextBlock::new().text("Page 1").build(ctx))
.child(TextBlock::new().text("Page 2").build(ctx))
.child(TextBlock::new().text("Page 3").build(ctx))
.build(ctx);
let next_button = Button::new()
.style("button_single_content")
.icon(material_icons_font::MD_KEYBOARD_ARROW_RIGHT)
.h_align("end")
.attach(Grid::row(2))
.enabled(("next_enabled", pager))
.text("next")
.on_click(move |states, _| {
states.send_message(PagerAction::Next, pager);
true
})
.build(ctx);
let previous_button = Button::new()
.style("button_single_content")
.icon(material_icons_font::MD_KEYBOARD_ARROW_LEFT)
.h_align("start")
.attach(Grid::row(2))
.enabled(("previous_enabled", pager))
.text("previous")
.on_click(move |states, _| {
states.send_message(PagerAction::Previous, pager);
true
})
.build(ctx);
self.child(
Grid::new()
.margin(16)
.rows("32, *, 32")
.child(TextBlock::new().text("Pager Widget").build(ctx))
.child(pager)
.child(previous_button)
.child(next_button)
.build(ctx),
)
}
}
// States
static ID_PAGER_TEST: &str = "id_pager_test";
#[derive(Debug, Clone, Copy)]
pub enum PagerTestAction {}
/// Valid `structures` that are handled inside the state of the `PagerTest` widget.
#[derive(AsAny, Debug, Default)]
pub struct PagerTestState {
pager_test: Entity,
}
/// Method definitions, that react on any given state change inside the `Menu` widget.
impl PagerTestState {
fn init(&mut self, _registry: &mut Registry, ctx: &mut Context) {
self.pager_test = ctx.child(ID_PAGER_TEST).entity();
}
}
impl State for PagerTestState {
/// Handle messages for the `PagerTestState`
fn messages(
&mut self,
mut messages: MessageReader,
_registry: &mut Registry,
ctx: &mut Context<'_>,
) {
for message in messages.read::<PagerTestAction>() {
ctx.send_message(message, self.pager_test);
}
}
}

View File

@@ -0,0 +1,37 @@
//extern crate pdf_extract;
//extern crate lopdf;
use std::env;
use std::path::PathBuf;
use std::path;
use std::io::BufWriter;
use std::fs::File;
use pdf_extract::*;
use lopdf::*;
fn main() {
//let output_kind = "html";
//let output_kind = "txt";
//let output_kind = "svg";
let file = env::args().nth(1).unwrap();
let output_kind = env::args().nth(2).unwrap_or_else(|| "txt".to_owned());
println!("{}", file);
let path = path::Path::new(&file);
let filename = path.file_name().expect("expected a filename");
let mut output_file = PathBuf::new();
output_file.push(filename);
output_file.set_extension(&output_kind);
let mut output_file = BufWriter::new(File::create(output_file).expect("could not create output"));
let doc = Document::load(path).unwrap();
print_metadata(&doc);
let mut output: Box<dyn OutputDev> = match output_kind.as_ref() {
"txt" => Box::new(PlainTextOutput::new(&mut output_file as &mut dyn std::io::Write)),
"html" => Box::new(HTMLOutput::new(&mut output_file)),
"svg" => Box::new(SVGOutput::new(&mut output_file)),
_ => panic!(),
};
output_doc(&doc, output.as_mut());
}

View File

@@ -0,0 +1,65 @@
use ron::de::from_str;
use serde::Deserialize;
use std::collections::HashMap;
#[derive(Debug, Deserialize)]
struct Config {
boolean: bool,
float: f32,
map: HashMap<u8, char>,
nested: Nested,
option: Option<String>,
tuple: (u32, u32),
}
#[derive(Debug, Deserialize)]
struct Nested {
a: String,
b: char,
}
const CONFIG: &str = "
/*
* RON now has multi-line (C-style) block comments!
* They can be freely nested:
* /* This is a nested comment */
* If you just want a single-line comment,
* do it like here:
// Just put two slashes before the comment and the rest of the line
// can be used freely!
*/
// Note that block comments can not be started in a line comment
// (Putting a /* here will have no effect)
(
boolean: true,
float: 8.2,
map: {
1: '1',
2: '4',
3: '9',
4: '1',
5: '2',
6: '3',
},
nested: Nested(
a: \"Decode me!\",
b: 'z',
),
option: Some(\t \"Weird formatting!\" \n\n ),
tuple: (3 /*(2 + 1)*/, 7 /*(2 * 5 - 3)*/),
)";
fn main() {
let config: Config = match from_str(CONFIG) {
Ok(x) => x,
Err(e) => {
println!("Failed to load config: {}", e);
std::process::exit(1);
}
};
println!("Config: {:?}", &config);
}

View File

@@ -0,0 +1,50 @@
use ron::ser::{to_string_pretty, PrettyConfig};
use serde::Serialize;
use std::{collections::HashMap, iter::FromIterator};
#[derive(Serialize)]
struct Config {
float: (f32, f64),
tuple: TupleStruct,
map: HashMap<u8, char>,
nested: Nested,
var: Variant,
array: Vec<()>,
}
#[derive(Serialize)]
struct TupleStruct((), bool);
#[derive(Serialize)]
enum Variant {
A(u8, &'static str),
}
#[derive(Serialize)]
struct Nested {
a: String,
b: char,
}
fn main() {
let data = Config {
float: (2.18, -1.1),
tuple: TupleStruct((), false),
map: HashMap::from_iter(vec![(0, '1'), (1, '2'), (3, '5'), (8, '1')]),
nested: Nested {
a: "Hello from \"RON\"".to_string(),
b: 'b',
},
var: Variant::A(!0, ""),
array: vec![(); 3],
};
let pretty = PrettyConfig::new()
.with_depth_limit(2)
.with_separate_tuple_members(true)
.with_enumerate_arrays(true);
let s = to_string_pretty(&data, pretty).expect("Serialization failed");
println!("{}", s);
}

View File

@@ -0,0 +1,49 @@
use ron::ser::{to_string_pretty, PrettyConfig};
use serde::Serialize;
use std::{collections::HashMap, iter::FromIterator};
#[derive(Serialize)]
struct Config {
float: (f32, f64),
tuple: TupleStruct,
map: HashMap<u8, char>,
nested: Nested,
var: Variant,
array: Vec<()>,
}
#[derive(Serialize)]
struct TupleStruct((), bool);
#[derive(Serialize)]
enum Variant {
A(u8, &'static str),
}
#[derive(Serialize)]
struct Nested {
a: String,
b: char,
}
fn main() {
let data = Config {
float: (2.18, -1.1),
tuple: TupleStruct((), false),
map: HashMap::from_iter(vec![(0, '1'), (1, '2'), (3, '5'), (8, '1')]),
nested: Nested {
a: "Hello from \"RON\"".to_string(),
b: 'b',
},
var: Variant::A(!0, ""),
array: vec![(); 3],
};
let pretty = PrettyConfig::new()
.with_depth_limit(2)
.with_separate_tuple_members(true)
.with_enumerate_arrays(true);
let s = to_string_pretty(&data, pretty).expect("Serialization failed");
println!("{}", s);
}

View File

@@ -0,0 +1,45 @@
extern crate sdl2;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use std::time::Duration;
pub fn main() -> Result<(), String> {
let sdl_context = sdl2::init()?;
let video_subsystem = sdl_context.video()?;
let window = video_subsystem
.window("rust-sdl2 demo: Video", 800, 600)
.position_centered()
.opengl()
.build()
.map_err(|e| e.to_string())?;
let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?;
canvas.set_draw_color(Color::RGB(255, 0, 0));
canvas.clear();
canvas.present();
let mut event_pump = sdl_context.event_pump()?;
'running: loop {
for event in event_pump.poll_iter() {
match event {
Event::Quit { .. }
| Event::KeyDown {
keycode: Some(Keycode::Escape),
..
} => break 'running,
_ => {}
}
}
canvas.clear();
canvas.present();
::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 30));
// The rest of the game loop goes here...
}
Ok(())
}

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