summaryrefslogtreecommitdiff
path: root/src/viewmodel
diff options
context:
space:
mode:
authorjelemux <jeremias.weber@protonmail.com>2020-11-25 10:31:04 +0100
committerjelemux <jeremias.weber@protonmail.com>2020-11-25 10:31:04 +0100
commitb1ba906491a1ed396d47b0751f080fef991ea344 (patch)
treec8e306c217dbdc352e66000822d8fc7e4cdc55fb /src/viewmodel
parent5a03734b6767fed04c0913384584d8f59dc597ea (diff)
downloadwasm-card-b1ba906491a1ed396d47b0751f080fef991ea344.tar.gz
wasm-card-b1ba906491a1ed396d47b0751f080fef991ea344.tar.bz2
Struktur umbauen
Diffstat (limited to 'src/viewmodel')
-rw-r--r--src/viewmodel/address.rs151
-rw-r--r--src/viewmodel/mod.rs104
-rw-r--r--src/viewmodel/name.rs118
-rw-r--r--src/viewmodel/telephone.rs162
-rw-r--r--src/viewmodel/utility.rs39
5 files changed, 574 insertions, 0 deletions
diff --git a/src/viewmodel/address.rs b/src/viewmodel/address.rs
new file mode 100644
index 0000000..757236c
--- /dev/null
+++ b/src/viewmodel/address.rs
@@ -0,0 +1,151 @@
+use vcard::properties;
+use vcard::parameters;
+use vcard::values::{self, text};
+use std::collections::HashSet;
+use super::*;
+use crate::view::address::*;
+
+#[derive(Clone)]
+pub struct Address {
+ pub post_office_box: String,
+ pub extension: String,
+ pub street: String,
+ pub locality: String,
+ pub region: String,
+ pub code: String,
+ pub country: String,
+ pub work: bool,
+ pub home: bool,
+}
+
+impl VCardPropertyInputObject<properties::Address, AddressView> for Address {
+ fn new() -> Self {
+ Self {
+ post_office_box: String::new(),
+ extension: String::new(),
+ street: String::new(),
+ locality: String::new(),
+ region: String::new(),
+ code: String::new(),
+ country: String::new(),
+ work: false,
+ home: false,
+ }
+ }
+ fn get_input_fields(&self, link: &ComponentLink<AddressView>) -> Vec<VCardPropertyInputField> {
+ vec![
+ VCardPropertyInputField::Text{
+ label: "Post Office Box".to_string(),
+ id: Some("post_office_box".to_string()),
+ placeholder: None,
+ oninput: link.callback(|e: InputData| Msg::UpdatePostOfficeBox(e.value)),
+ value: self.post_office_box.clone(),
+ },
+ VCardPropertyInputField::Text{
+ label: "Extension".to_string(),
+ id: Some("extension".to_string()),
+ placeholder: None,
+ oninput: link.callback(|e: InputData| Msg::UpdateExtension(e.value)),
+ value: self.extension.clone(),
+ },
+ VCardPropertyInputField::Text{
+ label: "Street".to_string(),
+ id: Some("street".to_string()),
+ placeholder: None,
+ oninput: link.callback(|e: InputData| Msg::UpdateStreet(e.value)),
+ value: self.street.clone(),
+ },
+ VCardPropertyInputField::Text{
+ label: "Locality".to_string(),
+ id: Some("locality".to_string()),
+ placeholder: None,
+ oninput: link.callback(|e: InputData| Msg::UpdateLocality(e.value)),
+ value: self.locality.clone(),
+ },
+ VCardPropertyInputField::Text{
+ label: "Region".to_string(),
+ id: Some("region".to_string()),
+ placeholder: None,
+ oninput: link.callback(|e: InputData| Msg::UpdateRegion(e.value)),
+ value: self.region.clone(),
+ },
+ VCardPropertyInputField::Text{
+ label: "Code".to_string(),
+ id: Some("code".to_string()),
+ placeholder: None,
+ oninput: link.callback(|e: InputData| Msg::UpdateCode(e.value)),
+ value: self.code.clone(),
+ },
+ VCardPropertyInputField::Text{
+ label: "Country".to_string(),
+ id: Some("country".to_string()),
+ placeholder: None,
+ oninput: link.callback(|e: InputData| Msg::UpdateCountry(e.value)),
+ value: self.country.clone(),
+ },
+ VCardPropertyInputField::CheckBox{
+ label: "Work".to_string(),
+ id: Some("work".to_string()),
+ onclick: link.callback(|_: MouseEvent| Msg::ToggleWork),
+ value: self.work,
+ },
+ VCardPropertyInputField::CheckBox{
+ label: "Home".to_string(),
+ id: Some("home".to_string()),
+ onclick: link.callback(|_: MouseEvent| Msg::ToggleHome),
+ value: self.home,
+ },
+ ]
+ }
+ fn to_vcard_property(&self) -> Result<properties::Address, VCardPropertyInputError> {
+ let address_value = values::address_value::AddressValue::from_components(
+ match self.post_office_box.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.post_office_box).unwrap()),
+ },
+ match self.extension.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.extension).unwrap()),
+ },
+ match self.street.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.street).unwrap()),
+ },
+ match self.locality.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.locality).unwrap()),
+ },
+ match self.region.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.region).unwrap()),
+ },
+ match self.code.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.code).unwrap()),
+ },
+ match self.country.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.country).unwrap()),
+ },
+ );
+
+ let mut address = properties::Address::from_address_value(address_value);
+
+ let type_values = {
+ let mut type_values = HashSet::new();
+
+ if self.work {
+ type_values.insert(values::type_value::TypeValue::Work);
+ }
+ if self.home {
+ type_values.insert(values::type_value::TypeValue::Home);
+ }
+
+ vcard::Set::from_hash_set(type_values).unwrap()
+ };
+
+ address.typ = Some(parameters::typ::Type::from_type_values(type_values));
+
+ Ok(address)
+ }
+} \ No newline at end of file
diff --git a/src/viewmodel/mod.rs b/src/viewmodel/mod.rs
new file mode 100644
index 0000000..42ad77b
--- /dev/null
+++ b/src/viewmodel/mod.rs
@@ -0,0 +1,104 @@
+use vcard::properties;
+use yew::prelude::*;
+use crate::view::VCardPropertyInputComponent;
+
+pub mod address;
+pub mod name;
+pub mod telephone;
+pub mod utility;
+
+pub trait VCardPropertyInputObject<P: properties::Property, C: VCardPropertyInputComponent<P, Self>>
+ where Self: Sized
+{
+ fn new() -> Self;
+ fn get_input_fields(&self, link: &ComponentLink<C>) -> Vec<VCardPropertyInputField>;
+ fn render(&self, link: &ComponentLink<C>) -> Html {
+ html!{
+ <div class="columns is-mobile is-multiline">
+ {
+ for self.get_input_fields(link).iter().map(|field|
+ field.render()
+ )
+ }
+ </div>
+ }
+ }
+ fn to_vcard_property(&self) -> Result<P, VCardPropertyInputError>;
+}
+
+#[derive(Debug)]
+pub struct VCardPropertyInputError {
+ msg: String,
+}
+
+pub enum VCardPropertyInputField {
+ Text {
+ label: String,
+ id: Option<String>,
+ placeholder: Option<String>,
+ oninput: Callback<InputData>,
+ value: String,
+ },
+ CheckBox {
+ label: String,
+ id: Option<String>,
+ onclick: Callback<MouseEvent>,
+ value: bool,
+ },
+}
+
+impl VCardPropertyInputField {
+ pub fn render(&self) -> Html {
+ match self {
+ Self::Text {
+ label,
+ id,
+ placeholder,
+ oninput,
+ value: _,
+ } => Self::text_field_input(label, id, placeholder, oninput),
+ Self::CheckBox {
+ label,
+ id,
+ onclick,
+ value,
+ } => Self::checkbox_field_input(label, id, value, onclick),
+ }
+ }
+ fn text_field_input(label: &str, id: &Option<String>, placeholder: &Option<String>, oninput: &Callback<InputData>) -> Html {
+ html!{
+ <div class="field column
+ is-one-fifth-widescreen
+ is-one-quarter-desktop
+ is-one-third-tablet
+ is-half-mobile" >
+ <label class="label">{ label }</label>
+ <div class="control">
+ <input id=id.as_ref().unwrap_or(&"".to_string())
+ type="text"
+ placeholder=placeholder.as_ref().unwrap_or(&"".to_string())
+ oninput=oninput
+ />
+ </div>
+ </div>
+ }
+ }
+ fn checkbox_field_input(label: &str, id: &Option<String>, checked: &bool, onclick: &Callback<MouseEvent>) -> Html {
+ html!{
+ <div class="field column
+ is-one-fifth-widescreen
+ is-one-quarter-desktop
+ is-one-third-tablet
+ is-half-mobile" >
+ <label class="checkbox">
+ <input id=id.as_ref().unwrap_or(&"".to_string())
+ type="checkbox"
+ checked=*checked
+ onclick=onclick
+ />
+ { label }
+ </label>
+ </div>
+ }
+ }
+} \ No newline at end of file
diff --git a/src/viewmodel/name.rs b/src/viewmodel/name.rs
new file mode 100644
index 0000000..55c1b4c
--- /dev/null
+++ b/src/viewmodel/name.rs
@@ -0,0 +1,118 @@
+use vcard::properties;
+use vcard::values::{self, text};
+use super::*;
+use crate::view::name::*;
+
+#[derive(Clone)]
+pub struct Name {
+ pub prefix: String,
+ pub first_name: String,
+ pub middle_name: String,
+ pub last_name: String,
+ pub suffix: String,
+}
+
+impl VCardPropertyInputObject<properties::Name, NameView> for Name {
+ fn new() -> Self {
+ Self {
+ prefix: String::new(),
+ first_name: String::new(),
+ middle_name: String::new(),
+ last_name: String::new(),
+ suffix: String::new(),
+ }
+ }
+ fn get_input_fields(&self, link: &ComponentLink<NameView>) -> std::vec::Vec<VCardPropertyInputField> {
+ vec![
+ VCardPropertyInputField::Text{
+ label: "Prefix".to_string(),
+ id: Some("prefix".to_string()),
+ placeholder: Some("Sir".to_string()),
+ oninput: link.callback(|e: InputData| Msg::UpdatePrefix(e.value)),
+ value: self.prefix.clone(),
+ },
+ VCardPropertyInputField::Text{
+ label: "First Name".to_string(),
+ id: Some("first_name".to_string()),
+ placeholder: Some("Arthur".to_string()),
+ oninput: link.callback(|e: InputData| Msg::UpdateFirstName(e.value)),
+ value: self.first_name.clone(),
+ },
+ VCardPropertyInputField::Text{
+ label: "Middle Name".to_string(),
+ id: Some("middle_name".to_string()),
+ placeholder: Some("Charles".to_string()),
+ oninput: link.callback(|e: InputData| Msg::UpdateMiddleName(e.value)),
+ value: self.middle_name.clone(),
+ },
+ VCardPropertyInputField::Text{
+ label: "Last Name".to_string(),
+ id: Some("last_name".to_string()),
+ placeholder: Some("Clarke".to_string()),
+ oninput: link.callback(|e: InputData| Msg::UpdateLastName(e.value)),
+ value: self.last_name.clone(),
+ },
+ VCardPropertyInputField::Text{
+ label: "Suffix".to_string(),
+ id: Some("suffix".to_string()),
+ placeholder: Some("CBE FRAS".to_string()),
+ oninput: link.callback(|e: InputData| Msg::UpdateSuffix(e.value)),
+ value: self.suffix.clone(),
+ },
+ ]
+ }
+ fn to_vcard_property(&self) -> std::result::Result<properties::Name, VCardPropertyInputError> {
+ let name_value = values::name_value::NameValue::from_components(
+ match self.last_name.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.last_name).unwrap()),
+ },
+ match self.first_name.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.first_name).unwrap()),
+ },
+ match self.middle_name.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.middle_name).unwrap()),
+ },
+ match self.prefix.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.prefix).unwrap()),
+ },
+ match self.suffix.is_empty() {
+ true => None,
+ false => Some(text::Component::from_str(&self.suffix).unwrap()),
+ },
+ );
+
+ Ok(properties::Name::from_name_value(name_value))
+ }
+}
+
+impl Name {
+ pub fn formatted_name(&self) -> String {
+ let mut formatted_name = String::new();
+
+ if !self.prefix.is_empty() {
+ formatted_name.push_str(&self.prefix);
+ }
+ if !self.first_name.is_empty() {
+ formatted_name.push_str(" ");
+ formatted_name.push_str(&self.first_name);
+ }
+ if !self.middle_name.is_empty() {
+ formatted_name.push_str(" ");
+ formatted_name.push_str(&self.middle_name);
+ }
+ if !self.last_name.is_empty() {
+ formatted_name.push_str(" ");
+ formatted_name.push_str(&self.last_name);
+ }
+ if !self.suffix.is_empty() {
+ formatted_name.push_str(", ");
+ formatted_name.push_str(&self.suffix);
+ }
+
+ formatted_name
+ }
+} \ No newline at end of file
diff --git a/src/viewmodel/telephone.rs b/src/viewmodel/telephone.rs
new file mode 100644
index 0000000..b67b0fb
--- /dev/null
+++ b/src/viewmodel/telephone.rs
@@ -0,0 +1,162 @@
+use vcard::properties;
+use vcard::parameters;
+use vcard::values;
+use std::collections::HashSet;
+use super::*;
+use crate::view::telephone::*;
+
+#[derive(Clone)]
+pub struct Telephone {
+ pub number: String,
+ pub extension: String,
+ pub work: bool,
+ pub home: bool,
+ pub text: bool,
+ pub voice: bool,
+ pub fax: bool,
+ pub cell: bool,
+ pub video: bool,
+ pub pager: bool,
+ pub text_phone: bool,
+}
+
+impl VCardPropertyInputObject<properties::Telephone, TelephoneView> for Telephone {
+ fn new() -> Self {
+ Self {
+ number: String::new(),
+ extension: String::new(),
+ work: false,
+ home: false,
+ text: false,
+ voice: false,
+ fax: false,
+ cell: false,
+ video: false,
+ pager: false,
+ text_phone: false,
+ }
+ }
+ fn get_input_fields(&self, link: &ComponentLink<TelephoneView>) -> Vec<VCardPropertyInputField> {
+ vec![
+ VCardPropertyInputField::Text{
+ label: "Number".to_string(),
+ id: Some("number".to_string()),
+ placeholder: None,
+ oninput: link.callback(|e: InputData| Msg::UpdateNumber(e.value)),
+ value: self.number.clone(),
+ },
+ VCardPropertyInputField::Text{
+ label: "Extension".to_string(),
+ id: Some("extension".to_string()),
+ placeholder: None,
+ oninput: link.callback(|e: InputData| Msg::UpdateExtension(e.value)),
+ value: self.extension.clone(),
+ },
+ VCardPropertyInputField::CheckBox{
+ label: "Work".to_string(),
+ id: Some("work".to_string()),
+ onclick: link.callback(|_: MouseEvent| Msg::ToggleWork),
+ value: self.work,
+ },
+ VCardPropertyInputField::CheckBox{
+ label: "Home".to_string(),
+ id: Some("home".to_string()),
+ onclick: link.callback(|_: MouseEvent| Msg::ToggleHome),
+ value: self.home,
+ },
+ VCardPropertyInputField::CheckBox{
+ label: "Text".to_string(),
+ id: Some("text".to_string()),
+ onclick: link.callback(|_: MouseEvent| Msg::ToggleText),
+ value: self.text,
+ },
+ VCardPropertyInputField::CheckBox{
+ label: "Voice".to_string(),
+ id: Some("voice".to_string()),
+ onclick: link.callback(|_: MouseEvent| Msg::ToggleVoice),
+ value: self.voice,
+ },
+ VCardPropertyInputField::CheckBox{
+ label: "Fax".to_string(),
+ id: Some("fax".to_string()),
+ onclick: link.callback(|_: MouseEvent| Msg::ToggleFax),
+ value: self.fax,
+ },
+ VCardPropertyInputField::CheckBox{
+ label: "Cell".to_string(),
+ id: Some("cell".to_string()),
+ onclick: link.callback(|_: MouseEvent| Msg::ToggleCell),
+ value: self.cell,
+ },
+ VCardPropertyInputField::CheckBox{
+ label: "Video".to_string(),
+ id: Some("video".to_string()),
+ onclick: link.callback(|_: MouseEvent| Msg::ToggleVideo),
+ value: self.video,
+ },
+ VCardPropertyInputField::CheckBox{
+ label: "Pager".to_string(),
+ id: Some("pager".to_string()),
+ onclick: link.callback(|_: MouseEvent| Msg::TogglePager),
+ value: self.pager,
+ },
+ VCardPropertyInputField::CheckBox{
+ label: "Text Phone".to_string(),
+ id: Some("text_phone".to_string()),
+ onclick: link.callback(|_: MouseEvent| Msg::ToggleTextPhone),
+ value: self.text_phone,
+ },
+ ]
+ }
+ fn to_vcard_property(&self) -> Result<properties::Telephone, VCardPropertyInputError> {
+ let mut telephone = properties::Telephone::from_telephone_value(
+ values::telephone_value::TelephoneValue::from_telephone_number_str(
+ self.number.clone(),
+ match self.extension.is_empty() {
+ true => None::<&str>,
+ false => Some(&self.extension),
+ },
+ ).unwrap()
+ );
+
+ let type_values = {
+ let mut type_values = HashSet::new();
+
+ if self.work {
+ type_values.insert(values::type_value::TypeValueWithTelephoneType::Work);
+ }
+ if self.home {
+ type_values.insert(values::type_value::TypeValueWithTelephoneType::Home);
+ }
+ if self.text {
+ type_values.insert(values::type_value::TypeValueWithTelephoneType::Text);
+ }
+ if self.voice {
+ type_values.insert(values::type_value::TypeValueWithTelephoneType::Voice);
+ }
+ if self.fax {
+ type_values.insert(values::type_value::TypeValueWithTelephoneType::Fax);
+ }
+ if self.cell {
+ type_values.insert(values::type_value::TypeValueWithTelephoneType::Cell);
+ }
+ if self.video {
+ type_values.insert(values::type_value::TypeValueWithTelephoneType::Video);
+ }
+ if self.pager {
+ type_values.insert(values::type_value::TypeValueWithTelephoneType::Pager);
+ }
+ if self.text_phone {
+ type_values.insert(values::type_value::TypeValueWithTelephoneType::TextPhone);
+ }
+
+ vcard::Set::from_hash_set(type_values).unwrap()
+ };
+
+ if let properties::Telephone::TelephoneValue { ref mut typ, .. } = telephone {
+ *typ = Some(parameters::typ::TypeWithTelType::from_type_values(type_values));
+ }
+
+ Ok(telephone)
+ }
+} \ No newline at end of file
diff --git a/src/viewmodel/utility.rs b/src/viewmodel/utility.rs
new file mode 100644
index 0000000..a296c1e
--- /dev/null
+++ b/src/viewmodel/utility.rs
@@ -0,0 +1,39 @@
+#[derive(Clone)]
+pub struct Download {
+ pub file_name: String,
+ pub content: String,
+ pub mime_type: MimeType,
+}
+
+impl Download {
+ pub fn as_data_link(&self) -> String {
+ let data = base64::encode(&*self.content);
+ let uri_component: String = js_sys::encode_uri_component(&data).into();
+
+ format!("data:{};base64,{}", self.mime_type.as_text(), uri_component)
+ }
+}
+
+#[derive(Clone, Copy)]
+pub enum MimeType {
+ PDF,
+ VCard,
+ SVG,
+}
+
+impl MimeType {
+ pub fn as_text(&self) -> &str {
+ match self {
+ MimeType::PDF => "application/pdf",
+ MimeType::VCard => "text/vcard",
+ MimeType::SVG => "image/svg+xml",
+ }
+ }
+}
+
+#[derive(Clone, Copy)]
+pub enum DownloadOption {
+ PDF,
+ VCard,
+ QrCode,
+} \ No newline at end of file