Flatten create structure

Signed-off-by: Ralf Zerres <ralf.zerres@networkx.de>
This commit is contained in:
2021-05-21 12:46:33 +02:00
parent 9ed395d04b
commit 78be428e7d
198 changed files with 257 additions and 3526 deletions

View File

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

View File

@@ -0,0 +1,235 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
//use locales::t;
use orbtk::prelude::*;
use serde::Deserialize;
//use std::process;
//use std::collections::HashMap;
use std::time::SystemTime;
use tracing::{error, info, trace};
use crate::{
data::{constants::*, structures::Email},
widgets::global_state::GlobalState,
services::exports::send_ticketdata::sendticketdata,
widgets::ticketdata::ticketdata_view::TicketdataView,
//widgets::policycheck::policycheck_state::PolicycheckAction,
Lang,
};
/// Valid `actions` that are handled as state changes in the `Ticketdata` widget.
#[derive(Debug, Clone)]
pub enum TicketdataAction {
/// Clear text in the form
ClearForm(String),
ParseEntry(Entity),
SendForm(),
UpdatePolicyCode(String)
}
/// Define valid environment variables provided via .env files
/// located in the current call directory.
/// This is primarily used in testing scenarios (eg. debugging).
#[derive(Debug, Deserialize)]
struct Environment {
test_lang: String,
rust_log: String,
}
/// Valid `structures` that are handled inside the state of the `Ticket` widget.
#[derive(AsAny, Default)]
pub struct TicketdataState {
actions: Vec<TicketdataAction>,
button_menu: Entity,
lang: Lang,
target: Entity
}
impl GlobalState for TicketdataState {}
/// Method definitions, that react on any given state change inside the `Ticketdata` widget.
impl TicketdataState {
/// Clear the text property of all children of the given form entity
pub fn clear_form(entity: Entity, id: &str, ctx: &mut Context<'_>) {
// form is identified by its id
if ctx.entity_of_child(id).is_some() {
let form_entity = ctx.entity_of_child(ID_TICKET_DATA_FORM_GRID).unwrap();
let form_container: WidgetContainer<'_> = ctx.get_widget(form_entity);
// BUG: Why does name defer from id, they are using the same constant?
info!("Form id: {:?}", form_container.get::<String>("id"));
info!("Form name: {:?}", form_container.get::<String>("name"));
//ctx.clear_children_of(form_entity); // complete form is cleared!
// switch into the context of the form_container
ctx.change_into(form_entity);
if let Some(count) = ctx.widget().children_count() {
for i in 0..count {
if let Some(child) = &mut ctx.try_child_from_index(i) {
let child_name: &str = child.get::<String>("name");
info!("child({:?}) name: {:?}",
i, child_name);
let child_id: &str = child.get::<String>("id");
info!("child({:?}) name: {:?}",
i, child_id);
// TODO: check the orbtk type
// if let child_type: bool = child.get::<String>("id") = std::any::type_name::<TextBox>().to_string() {
match child_name {
"TextBox" => TextBox::text_set(child, ""),
"ticket_data_policy_code" => TextBox::text_set(child, ""),
_ => info!("don't act on types other than 'TextBox'"),
}
// match child_id {
// "ticket_data_policy_code" => TextBox::text_set(child, ""),
// "ticket_data_policy_holder" => TextBox::text_set(child, ""),
// "ticket_data_policy_deductible" => TextBox::text_set(child, ""),
// "ticket_data_policy_callback_number" => TextBox::text_set(child, ""),
// "ticket_data_policy_callback_date" => TextBox::text_set(child, ""),
// "ticket_data_policy_callback_harm_type" => TextBox::text_set(child, ""),
// "ticket_data_policy_callback_ivr_comment" => TextBox::text_set(child, ""),
// _ => info!("don't act on child_id '{:?}", child_id),
// }
}
}
}
// switch back to parent entity
ctx.change_into(entity);
Stack::visibility_set(&mut ctx.child(ID_TICKET_DATA_ACTION_STACK), Visibility::Collapsed);
Button::background_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), String::from("#008000"));
Button::icon_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), material_icons_font::MD_SEND);
}
}
pub fn send_form(entity: Entity, ctx: &mut Context<'_>, _lang: Lang) {
info!("TicketdataState: processing entity[{:?}]", entity);
let mail_to_index = *TicketdataView::selected_index_ref(&ctx.widget()) as usize;
let mail_to_item = TicketdataView::mail_to_ref(&ctx.widget())[mail_to_index].clone();
info!("mail_to item[{:?}]: {:?}]", mail_to_index, mail_to_item);
// create Email structures
let email = Email {
mail_to: mail_to_item.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(),
};
trace!("eMail fields: {:?}", email);
// send email via service
let lang = Lang::De("");
if let Err(err) = sendticketdata(&email, &lang) {
error!("sendticketdata error: {:?}", err);
Button::icon_brush_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), String::from("#008000"));
//Button::foreground_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), String::from("#CC000000"));
Button::background_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), String::from("#CC000000"));
Button::icon_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), material_icons_font::MD_THUMB_DOWN);
//Button::icon_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), material_icons_font::MD_ERROR);
} else {
Button::icon_brush_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), String::from("#FF0000"));
//Button::foreground_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), String::from("#FF0000"));
Button::background_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), String::from("#FF0000"));
Button::icon_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), material_icons_font::MD_THUMB_UP);
};
}
pub fn update_policy_code(_entity: Entity, _id: &str, ctx: &mut Context<'_>) {
Stack::visibility_set(&mut ctx.child(ID_TICKET_DATA_ACTION_STACK), Visibility::Visible);
//self.actions.push(TicketdataAction::UpdatePolicyCode(entity));
}
}
/// Supported methods handled inside the `TicketState`
impl State for TicketdataState {
/// Initialize the state of widgets inside `TicketState`
fn init(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
let time_start= SystemTime::now();
trace!(target: "advotracker", ticketdata_state = "init", status = "started");
// Initialize required menu button entity
self.button_menu = ctx
.entity_of_child(ID_TICKET_DATA_BUTTON_MENU)
.expect("TicketState.init: Can't find resource entity 'ID_TICKET_DATA_BUTTON_MENU'.");
// initialize the entity object, that will receive messages
self.target = Entity::from(ctx.widget().try_clone::<u32>("target")
.expect("TicketState.init: Can't find resource entity 'target'."));
// Get language from environment
//self.lang = TicketdataState::get_lang();
//let self.lang = Lang::De("");
Stack::visibility_set(&mut ctx.child(ID_TICKET_DATA_ACTION_STACK), Visibility::Collapsed);
Button::icon_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_CLEAR), material_icons_font::MD_CLEAR);
Button::icon_set(&mut ctx.child(ID_TICKET_DATA_ACTION_BUTTON_SEND), material_icons_font::MD_SEND);
let time_end = SystemTime::now();
let duration = time_end.duration_since(time_start);
trace!(target: "advotracker", ticketdata_state = "init", status = "finished", duration = ?duration);
}
/// The reader component of the message system handing `TicketdataState``
fn messages(
&mut self,
mut messages: MessageReader,
_registry: &mut Registry,
ctx: &mut Context<'_>,
) {
for message in messages.read::<TicketdataAction>() {
match message {
TicketdataAction::ClearForm(id) => {
TicketdataState::clear_form(ctx.entity(), &id, ctx);
}
TicketdataAction::SendForm() => {
TicketdataState::send_form(ctx.entity(), ctx, self.lang);
}
TicketdataAction::UpdatePolicyCode(id) => {
TicketdataState::update_policy_code(ctx.entity(), &id, ctx);
}
_ => { println!("messages: action not implemented!"); }
}
}
}
fn update(&mut self, _registry: &mut Registry, ctx: &mut Context<'_>) {
let actions: Vec<TicketdataAction> = self.actions.drain(..).collect();
for action in actions {
match action {
TicketdataAction::ClearForm(ref id) => {
ctx.send_message(TicketdataAction::ClearForm(id.to_string()), self.target);
}
// TicketdataAction::SendForm() => {
// //ctx.send_message(TicketdataAction::SendForm(), self.ID_TICKETDATA_FORM);
// info!("update: got send_message {:?}", action);
// }
_ => { println!("TicketdataAction: action not implemented!"); }
}
}
}
}

View File

@@ -0,0 +1,480 @@
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2021 Ralf Zerres <ralf.zerres@networkx.de>
* SPDX-License-Identifier: (0BSD or MIT)
*/
use orbtk::prelude::*;
use crate::{
data::constants::*,
widgets::ticketdata::ticketdata_state::{TicketdataAction, TicketdataState},
};
// Used to define ComboBox list members
type List = Vec<String>;
// 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,
// mail recipients (mail_to) saved in a vector
mail_to: List,
// carbo copy recipients (mail_to) saved in a vector
mail_cc: List,
// active seleced index of combo box
selected_index: i32,
// 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 {
// vector with valid strings of mail recipients addresses (mail_to)
let mail_to = vec![
PROP_MAIL_TO_1.to_string(),
PROP_MAIL_TO_2.to_string(),
PROP_MAIL_TO_3.to_string(),
PROP_MAIL_TO_4.to_string(),
PROP_MAIL_TO_5.to_string(),
];
let count_mail_to = mail_to.len();
// vector with valid carbon copy recipients addresses (mail_to)
let mail_cc = vec![
PROP_MAIL_CC_1.to_string(),
PROP_MAIL_CC_2.to_string(),
];
let _count_mail_cc = mail_cc.len();
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)
.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 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_FORM_GRID)
.name(ID_TICKET_DATA_FORM_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")
.water_mark("ID, bzw. Nummer")
.on_activate(move |states, _entity| {
states.send_message(TicketdataAction::UpdatePolicyCode(ID_TICKET_DATA_POLICY_CODE.to_string()), id);
})
.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()
.id(ID_TICKET_DATA_ACTION_STACK)
//.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, _entity| {
states.send_message(TicketdataAction::ClearForm(ID_TICKET_DATA_FORM_GRID.to_string()), id);
false
})
.build(ctx),
)
.child(
Button::new()
.id(ID_TICKET_DATA_ACTION_BUTTON_SEND)
.style(STYLE_BUTTON_ACTION)
.text("Send")
.on_click(move |states, _entity| {
states.send_message(TicketdataAction::SendForm(), id);
false
})
.build(ctx),
)
.build(ctx),
)
.build(ctx);
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_LABEL_MAIL_TO)
.attach(Grid::row(0))
.attach(Grid::column(1))
.style(STYLE_MAIL_LABEL)
.text("Recipient (To)")
.build(ctx),
)
.child(
ComboBox::new()
.id(ID_TICKET_DATA_COMBO_BOX_MAIL_TO)
.attach(Grid::row(0))
.attach(Grid::column(3))
.style(STYLE_MAIL_TO)
.count(count_mail_to)
// create the items builder context (ibc) for the `mail_to` vector-items
.selected_index(id)
.items_builder(move |ibc, index| {
let text = TicketdataView::mail_to_ref(&ibc.get_widget(id))[index].clone();
TextBlock::new()
.name(ID_TICKET_DATA_MAIL_TO)
.v_align("center")
.text(text)
.build(ibc)
})
//.on_changed("selected_index", move |states, _entity| {
// states.send_message(TicketdataAction::UpdateSelectedIndex(ID_TICKET_DATA_COMBO_BOX_MAIL_TO.to_string()), id);
//})
.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(
TextBlock::new()
.id(ID_TICKET_DATA_COMBO_BOX_MAIL_CC)
.attach(Grid::row(2))
.attach(Grid::column(3))
.name(ID_TICKET_DATA_MAIL_CC)
.margin((12, 0, 0, 0))
.text("service@hiedemann.de")
.build(ctx)
)
// .child(
// ComboBox::new()
// .id(ID_TICKET_DATA_COMBO_BOX_MAIL_CC)
// .attach(Grid::row(2))
// .attach(Grid::column(3))
// .style(STYLE_MAIL_CC)
// .count(count_mail_cc)
// // create the items builder context (ibc) for the `mail_cc` vector-items
// .items_builder(move |ibc, index| {
// // let text = ibc.get_widget(id)
// // .get::<Vec<String>>("mail_cc")[index]
// // .clone();
// let text = TicketdataView::mail_cc_ref(&ibc.get_widget(id))[index].clone();
// TextBlock::new()
// .name(ID_TICKET_DATA_MAIL_CC)
// .text(text)
// .v_align("center")
// .build(ibc)
// })
// .selected_index(id)
// .on_changed("selected_index", move |states, _entity| {
// states.send_message(TicketdataAction::UpdateSelectedIndex(ID_TICKET_DATA_COMBO_BOX_MAIL_CC.to_string()), id);
// })
// .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)
.mail_to(mail_to)
.mail_cc(mail_cc)
.selected_index(0)
//.selected_index_mail_to(0)
//.selected_index_mail_cc(0)
.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),
)
}
}