diff options
| -rw-r--r-- | src/model/address.rs | 2 | ||||
| -rw-r--r-- | src/model/dates.rs | 69 | ||||
| -rw-r--r-- | src/model/mod.rs | 65 | ||||
| -rw-r--r-- | src/model/name.rs | 2 | ||||
| -rw-r--r-- | src/model/organizational.rs | 2 | ||||
| -rw-r--r-- | src/model/other_identification.rs | 116 | ||||
| -rw-r--r-- | src/model/telephone.rs | 2 | ||||
| -rw-r--r-- | src/model/vcard.rs | 8 | ||||
| -rw-r--r-- | src/view/main.rs | 93 | ||||
| -rw-r--r-- | src/view/property_group.rs | 8 | 
10 files changed, 237 insertions, 130 deletions
diff --git a/src/model/address.rs b/src/model/address.rs index 2c42a98..2321f82 100644 --- a/src/model/address.rs +++ b/src/model/address.rs @@ -28,7 +28,7 @@ pub enum AddressMsg {      Generate,  } -impl VCardPropertyInputObject<AddressMsg> for Address { +impl VCardPropertyInputGroupObject<AddressMsg> for Address {      fn new() -> Self {          Self {              post_office_box: String::new(), diff --git a/src/model/dates.rs b/src/model/dates.rs deleted file mode 100644 index 192f986..0000000 --- a/src/model/dates.rs +++ /dev/null @@ -1,69 +0,0 @@ -use super::*; - -/// Type that represents the vcard `anniversary` and `birthday` properties. -#[derive(Clone, Debug, PartialEq)] -pub struct Dates { -    pub anniversary: String, -    pub birthday: String, -} - -#[derive(Clone, PartialEq)] -pub enum DatesMsg { -    UpdateAnniversary(String), -    UpdateBirthday(String), - -    Generate, -} - -impl VCardPropertyInputObject<DatesMsg> for Dates { -    fn new() -> Self { -        Self { -            anniversary: String::new(), -            birthday: String::new(), -        } -    } -    fn get_title(&self) -> std::string::String { -        "Dates".to_string() -    } -    fn get_input_fields( -        &self, -        link: &yew::html::Scope<PropertyGroupInputComponent<Self, DatesMsg>>, -    ) -> std::vec::Vec<VCardPropertyInputField> { -        let typ = String::from("date"); -        vec![ -            VCardPropertyInputField::Text { -                label: "Anniversary".to_string(), -                id: Some("anniversary".to_string()), -                placeholder: None, -                oninput: link.callback(|e: InputData| DatesMsg::UpdateAnniversary(e.value)), -                value: self.anniversary.clone(), -                typ: typ.clone(), -            }, -            VCardPropertyInputField::Text { -                label: "Birthday".to_string(), -                id: Some("birthday".to_string()), -                placeholder: None, -                oninput: link.callback(|e: InputData| DatesMsg::UpdateBirthday(e.value)), -                value: self.birthday.clone(), -                typ, -            }, -        ] -    } -    fn update( -        &mut self, -        props: InputProps<Self, DatesMsg>, -        msg: <PropertyGroupInputComponent<Self, DatesMsg> as yew::Component>::Message, -    ) -> bool { -        match msg { -            DatesMsg::UpdateAnniversary(a) => self.anniversary = a, -            DatesMsg::UpdateBirthday(b) => self.birthday = b, -            DatesMsg::Generate => { -                props.generated.emit(self.clone()); -            } -        }; -        true -    } -    fn is_empty(&self) -> bool { -        self.anniversary.is_empty() && self.birthday.is_empty() -    } -} diff --git a/src/model/mod.rs b/src/model/mod.rs index 45c91f1..b8dcfff 100644 --- a/src/model/mod.rs +++ b/src/model/mod.rs @@ -7,23 +7,23 @@ use yew::prelude::*;  use yew::services::ConsoleService;  pub mod address; -pub mod dates;  pub mod name;  pub mod organizational; +pub mod other_identification;  pub mod telephone;  pub mod utility;  pub mod vcard;  /// Trait for types that represent the data of a vcard property used inside of a `VCardPropertyInputComponent`. -pub trait VCardPropertyInputObject<M: 'static + PartialEq + Clone>: Clone + PartialEq +pub trait VCardPropertyInputGroupObject<M: 'static + PartialEq + Clone>: Clone + PartialEq  where      Self: Sized,  { -    /// Function for creating a new (and empty) `VCardPropertyInputObject`. +    /// Function for creating a new (and empty) `VCardPropertyInputGroupObject`.      fn new() -> Self;      /// Getter function for the title of the component      fn get_title(&self) -> String; -    /// Converts each field of the `VCardPropertyInputObject` to a VCardPropertyInputField and returns them as a vector. +    /// Converts each field of the `VCardPropertyInputGroupObject` to a VCardPropertyInputField and returns them as a vector.      fn get_input_fields(          &self,          link: &ComponentLink<PropertyGroupInputComponent<Self, M>>, @@ -33,7 +33,7 @@ where          props: InputProps<Self, M>,          msg: <PropertyGroupInputComponent<Self, M> as yew::Component>::Message,      ) -> bool; -    /// Returns a `Html` representation of the `VCardPropertyInputObject`. +    /// Returns a `Html` representation of the `VCardPropertyInputGroupObject`.      fn render(&self, link: &ComponentLink<PropertyGroupInputComponent<Self, M>>) -> Html {          html! {              <div class="columns is-mobile is-multiline"> @@ -45,7 +45,7 @@ where              </div>          }      } -    /// Convenience function for checking if the `VCardPropertyInputObject` is empty. +    /// Convenience function for checking if the `VCardPropertyInputGroupObject` is empty.      fn is_empty(&self) -> bool;  } @@ -73,6 +73,13 @@ pub enum VCardPropertyInputField {          callback: Callback<Option<File>>,          value: Option<File>,      }, +    Select { +        label: String, +        id: Option<String>, +        options: Vec<(String, String)>, +        onchange: Callback<ChangeData>, +        value: String, +    },      CheckBox {          label: String,          id: Option<String>, @@ -99,6 +106,13 @@ impl VCardPropertyInputField {                  callback,                  value,              } => Self::file_field_input(label, name, callback, value), +            Self::Select { +                label, +                id, +                options, +                onchange, +                value, +            } => Self::select_field_input(label, id, options, onchange, value),              Self::CheckBox {                  label,                  id, @@ -180,10 +194,10 @@ impl VCardPropertyInputField {          });          html! {              <div class="field column -                        is-one-fifth-widescreen -                        is-one-quarter-desktop -                        is-one-third-tablet -                        is-half-mobile" > +                        is-one-third-widescreen +                        is-two-quarters-desktop +                        is-two-thirds-tablet +                        is-full-mobile" >                  <label class="label">{ label }</label>                  <div class="file has-name control">                      <label class="file-label"> @@ -213,6 +227,37 @@ impl VCardPropertyInputField {              </div>          }      } +    fn select_field_input( +        label: &str, +        id: &Option<String>, +        options: &Vec<(String, String)>, +        onchange: &Callback<ChangeData>, +        value: &str, +    ) -> 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="select"> +                    <select id=id.as_ref().unwrap_or(&"".to_string()) +                            value=value +                            onchange=onchange > +                        { +                            for options.iter().map(|option| +                                html! { +                                    <option value=option.0>{ option.1.clone() }</option> +                                } +                            ) +                        } +                    </select> +                </div> + +            </div> +        } +    }      /// Returns an `Html` representation of a checkbox input field with the given parameters.      fn checkbox_field_input(          label: &str, diff --git a/src/model/name.rs b/src/model/name.rs index 915579d..8cc889c 100644 --- a/src/model/name.rs +++ b/src/model/name.rs @@ -35,7 +35,7 @@ pub enum NameMsg {      Generate,  } -impl VCardPropertyInputObject<NameMsg> for Name { +impl VCardPropertyInputGroupObject<NameMsg> for Name {      fn new() -> Self {          Self {              prefix: String::new(), diff --git a/src/model/organizational.rs b/src/model/organizational.rs index f82f5d7..cfdb44d 100644 --- a/src/model/organizational.rs +++ b/src/model/organizational.rs @@ -22,7 +22,7 @@ pub enum OrganizationalMsg {      Generate,  } -impl VCardPropertyInputObject<OrganizationalMsg> for Organizational { +impl VCardPropertyInputGroupObject<OrganizationalMsg> for Organizational {      fn new() -> Self {          Self {              org: String::new(), diff --git a/src/model/other_identification.rs b/src/model/other_identification.rs new file mode 100644 index 0000000..a01b818 --- /dev/null +++ b/src/model/other_identification.rs @@ -0,0 +1,116 @@ +use super::*; + +/// Type that represents the vcard `anniversary` and `birthday` properties. +#[derive(Clone, Debug, PartialEq)] +pub struct OtherIdentification { +    pub nickname: String, +    pub photo: Option<File>, +    pub birthday: String, +    pub anniversary: String, +    pub gender: String, +} + +#[derive(Clone, PartialEq)] +pub enum OtherIdentificationMsg { +    UpdateNickname(String), +    UpdatePhoto(Option<File>), +    UpdateBirthday(String), +    UpdateAnniversary(String), +    UpdateGender(String), + +    Generate, + +    Nope, +} + +impl VCardPropertyInputGroupObject<OtherIdentificationMsg> for OtherIdentification { +    fn new() -> Self { +        Self { +            nickname: String::new(), +            photo: None, +            birthday: String::new(), +            anniversary: String::new(), +            gender: String::new(), +        } +    } +    fn get_title(&self) -> std::string::String { +        "Other Identification Properties".to_string() +    } +    fn get_input_fields( +        &self, +        link: &yew::html::Scope<PropertyGroupInputComponent<Self, OtherIdentificationMsg>>, +    ) -> std::vec::Vec<VCardPropertyInputField> { +        vec![ +            VCardPropertyInputField::Text { +                label: String::from("Nickname"), +                id: Some(String::from("nickname")), +                placeholder: None, +                oninput: link +                    .callback(|e: InputData| OtherIdentificationMsg::UpdateNickname(e.value)), +                value: self.nickname.clone(), +                typ: String::from("text"), +            }, +            VCardPropertyInputField::File { +                label: String::from("Photo"), +                name: String::from("photo"), +                callback: link +                    .callback(|file: Option<File>| OtherIdentificationMsg::UpdatePhoto(file)), +                value: self.photo.clone(), +            }, +            VCardPropertyInputField::Text { +                label: "Birthday".to_string(), +                id: Some("birthday".to_string()), +                placeholder: None, +                oninput: link +                    .callback(|e: InputData| OtherIdentificationMsg::UpdateBirthday(e.value)), +                value: self.birthday.clone(), +                typ: String::from("date"), +            }, +            VCardPropertyInputField::Text { +                label: "Anniversary".to_string(), +                id: Some("anniversary".to_string()), +                placeholder: None, +                oninput: link +                    .callback(|e: InputData| OtherIdentificationMsg::UpdateAnniversary(e.value)), +                value: self.anniversary.clone(), +                typ: String::from("date"), +            }, +            VCardPropertyInputField::Select { +                label: String::from("Gender"), +                id: Some(String::from("gender")), +                options: vec![ +                    (String::from(""), String::from("Select one")), +                    (String::from("M"), String::from("Male")), +                    (String::from("F"), String::from("Female")), +                    (String::from("O"), String::from("Other")), +                    (String::from("N"), String::from("Not applicable")), +                    (String::from("U"), String::from("Unknown")), +                ], +                onchange: link.callback(|c: ChangeData| match c { +                    ChangeData::Select(v) => OtherIdentificationMsg::UpdateGender(v.value()), +                    _ => OtherIdentificationMsg::Nope, +                }), +                value: self.gender.clone(), +            }, +        ] +    } +    fn update( +        &mut self, +        props: InputProps<Self, OtherIdentificationMsg>, +        msg: <PropertyGroupInputComponent<Self, OtherIdentificationMsg> as yew::Component>::Message, +    ) -> bool { +        match msg { +            OtherIdentificationMsg::UpdateNickname(n) => self.nickname = n, +            OtherIdentificationMsg::UpdatePhoto(p) => self.photo = p, +            OtherIdentificationMsg::UpdateBirthday(b) => self.birthday = b, +            OtherIdentificationMsg::UpdateAnniversary(a) => self.anniversary = a, +            OtherIdentificationMsg::UpdateGender(g) => self.gender = g, +            OtherIdentificationMsg::Generate => props.generated.emit(self.clone()), +            OtherIdentificationMsg::Nope => (), +        }; +        true +    } +    fn is_empty(&self) -> bool { +        self.anniversary.is_empty() && self.birthday.is_empty() +    } +} diff --git a/src/model/telephone.rs b/src/model/telephone.rs index 946da33..b571aa4 100644 --- a/src/model/telephone.rs +++ b/src/model/telephone.rs @@ -30,7 +30,7 @@ pub enum TelephoneMsg {      Generate,  } -impl VCardPropertyInputObject<TelephoneMsg> for Telephone { +impl VCardPropertyInputGroupObject<TelephoneMsg> for Telephone {      fn new() -> Self {          Self {              number: String::new(), diff --git a/src/model/vcard.rs b/src/model/vcard.rs index ee7e28e..185ae71 100644 --- a/src/model/vcard.rs +++ b/src/model/vcard.rs @@ -1,7 +1,7 @@  use crate::model::address::Address; -use crate::model::dates::Dates;  use crate::model::name::Name;  use crate::model::organizational::Organizational; +use crate::model::other_identification::OtherIdentification;  use crate::model::telephone::Telephone;  /// Type that represents the data structure of a vcard. @@ -10,7 +10,7 @@ pub struct VCardData {      pub names: Vec<Name>,      pub addresses: Vec<Address>,      pub telephones: Vec<Telephone>, -    pub datess: Vec<Dates>, +    pub other_identifications: Vec<OtherIdentification>,      pub organizationals: Vec<Organizational>,  } @@ -28,13 +28,13 @@ impl VCardData {              names: Vec::new(),              addresses: Vec::new(),              telephones: Vec::new(), -            datess: Vec::new(), +            other_identifications: Vec::new(),              organizationals: Vec::new(),          }      }      make_vec_adder_fn!( fn add_name names => name: Name );      make_vec_adder_fn!( fn add_address addresses => address: Address );      make_vec_adder_fn!( fn add_telephone telephones => telephone: Telephone ); -    make_vec_adder_fn!( fn add_dates datess => dates: Dates ); +    make_vec_adder_fn!( fn add_other_identification other_identifications => other_identification: OtherIdentification );      make_vec_adder_fn!( fn add_organizational organizationals => organizational: Organizational );  } diff --git a/src/view/main.rs b/src/view/main.rs index d35fb59..808b160 100644 --- a/src/view/main.rs +++ b/src/view/main.rs @@ -1,14 +1,14 @@ -use crate::view::property_group::PropertyGroupInputComponent; -use crate::view::weak_links::WeakComponentLink;  use crate::model::address::*; -use crate::model::dates::*;  use crate::model::name::*;  use crate::model::organizational::*; +use crate::model::other_identification::*;  use crate::model::telephone::*;  use crate::model::utility::*;  use crate::model::vcard::VCardData;  use crate::model::Error; -use crate::model::VCardPropertyInputObject; +use crate::model::VCardPropertyInputGroupObject; +use crate::view::property_group::PropertyGroupInputComponent; +use crate::view::weak_links::WeakComponentLink;  use boolinator::Boolinator;  use chrono::prelude::*;  use genpdf::Element as _; @@ -23,7 +23,8 @@ use yewtil::ptr::Mrc;  type NameView = PropertyGroupInputComponent<Name, NameMsg>;  type AddressView = PropertyGroupInputComponent<Address, AddressMsg>; -type DatesView = PropertyGroupInputComponent<Dates, DatesMsg>; +type OtherIdentificationView = +    PropertyGroupInputComponent<OtherIdentification, OtherIdentificationMsg>;  type OrganizationalView = PropertyGroupInputComponent<Organizational, OrganizationalMsg>;  type TelephoneView = PropertyGroupInputComponent<Telephone, TelephoneMsg>; @@ -37,7 +38,7 @@ pub struct MainView {      name_links: Vec<WeakComponentLink<NameView>>,      address_links: Vec<WeakComponentLink<AddressView>>,      telephone_links: Vec<WeakComponentLink<TelephoneView>>, -    dates_links: Vec<WeakComponentLink<DatesView>>, +    other_identifications_links: Vec<WeakComponentLink<OtherIdentificationView>>,      organizational_links: Vec<WeakComponentLink<OrganizationalView>>,      answer_count: usize, @@ -54,9 +55,9 @@ pub enum Msg {      Generate,      GeneratedName(Name), +    GeneratedOtherIdentification(OtherIdentification),      GeneratedAddress(Address),      GeneratedTelephone(Telephone), -    GeneratedDates(Dates),      GeneratedOrganizational(Organizational),      GenerationComplete, @@ -78,7 +79,7 @@ impl Component for MainView {              name_links: vec![WeakComponentLink::default()],              address_links: vec![WeakComponentLink::default()],              telephone_links: vec![WeakComponentLink::default()], -            dates_links: vec![WeakComponentLink::default()], +            other_identifications_links: vec![WeakComponentLink::default()],              organizational_links: vec![WeakComponentLink::default()],              answer_count: 0,          } @@ -102,7 +103,7 @@ impl Component for MainView {                  shouldrender = true;              }              Msg::AddDates => { -                self.dates_links.push(WeakComponentLink::default()); +                self.other_identifications_links.push(WeakComponentLink::default());                  shouldrender = true;              }              Msg::AddOrganizational => { @@ -132,9 +133,9 @@ impl Component for MainView {                          telephone_link.send_message(TelephoneMsg::Generate);                      } -                    for dates_link in self.dates_links.iter() { +                    for dates_link in self.other_identifications_links.iter() {                          let dates_link = dates_link.borrow().clone().unwrap(); -                        dates_link.send_message(DatesMsg::Generate) +                        dates_link.send_message(OtherIdentificationMsg::Generate)                      }                      for organizational_links in self.organizational_links.iter() { @@ -172,37 +173,37 @@ impl Component for MainView {                  shouldrender = true;              } -            Msg::GeneratedAddress(address) => { +            Msg::GeneratedOtherIdentification(other_identification) => {                  self.answer_count += 1;                  match self.vcard_data.get_mut() { -                    Some(vcard_data) => vcard_data.add_address(address), +                    Some(vcard_data) => vcard_data.add_other_identification(other_identification),                      None => ConsoleService::info( -                        "Error in GeneratedAddress: Couldn't get mutable borrow of VCardData", +                        "Error in GeneratedOtherIdentification: Couldn't get mutable borrow of VCardData",                      ),                  };                  shouldrender = true;              } -            Msg::GeneratedTelephone(telephone) => { +            Msg::GeneratedAddress(address) => {                  self.answer_count += 1;                  match self.vcard_data.get_mut() { -                    Some(vcard_data) => vcard_data.add_telephone(telephone), +                    Some(vcard_data) => vcard_data.add_address(address),                      None => ConsoleService::info( -                        "Error in GeneratedTelephone: Couldn't get mutable borrow of VCardData", +                        "Error in GeneratedAddress: Couldn't get mutable borrow of VCardData",                      ),                  };                  shouldrender = true;              } -            Msg::GeneratedDates(dates) => { +            Msg::GeneratedTelephone(telephone) => {                  self.answer_count += 1;                  match self.vcard_data.get_mut() { -                    Some(vcard_data) => vcard_data.add_dates(dates), +                    Some(vcard_data) => vcard_data.add_telephone(telephone),                      None => ConsoleService::info( -                        "Error in GeneratedDates: Couldn't get mutable borrow of VCardData", +                        "Error in GeneratedTelephone: Couldn't get mutable borrow of VCardData",                      ),                  }; @@ -336,13 +337,27 @@ impl Component for MainView {                      }                  } -                for dates in vcard_data.datess { -                    if !dates.anniversary.is_empty() { -                        builder = builder.with_anniversary(dates.anniversary); +                for other_identification in vcard_data.other_identifications { +                    if !other_identification.nickname.is_empty() { +                        builder = +                            builder.with_nickname(parameters!(), other_identification.nickname); +                    } + +                    match other_identification.photo { +                        Some(file) => builder = builder.with_photo(parameters!(), file.content), +                        None => (), +                    }; + +                    if !other_identification.anniversary.is_empty() { +                        builder = builder.with_anniversary(other_identification.anniversary);                      } -                    if !dates.birthday.is_empty() { -                        builder = builder.with_bday(parameters!(), dates.birthday); +                    if !other_identification.birthday.is_empty() { +                        builder = builder.with_bday(parameters!(), other_identification.birthday); +                    } + +                    if !other_identification.gender.is_empty() { +                        builder = builder.with_gender(parameters!(), other_identification.gender);                      }                  } @@ -484,6 +499,19 @@ impl Component for MainView {                              }                              { +                                for self.other_identifications_links.iter().map(|link| +                                    html!{ +                                        <OtherIdentificationView  weak_link=link +                                                    generated=self.link.callback( +                                                        |d: OtherIdentification| +                                                            Msg::GeneratedOtherIdentification(d) +                                                    ) +                                        /> +                                    } +                                ) +                            } + +                            {                                  for self.address_links.iter().map(|link|                                      html!{                                          <AddressView    weak_link=link @@ -510,19 +538,6 @@ impl Component for MainView {                              }                              { -                                for self.dates_links.iter().map(|link| -                                    html!{ -                                        <DatesView  weak_link=link -                                                    generated=self.link.callback( -                                                        |d: Dates| -                                                            Msg::GeneratedDates(d) -                                                    ) -                                        /> -                                    } -                                ) -                            } - -                            {                                  for self.organizational_links.iter().map(|link|                                      html!{                                          <OrganizationalView weak_link=link @@ -695,7 +710,7 @@ impl MainView {          self.name_links.len()              + self.address_links.len()              + self.telephone_links.len() -            + self.dates_links.len() +            + self.other_identifications_links.len()              + self.organizational_links.len()      }  } diff --git a/src/view/property_group.rs b/src/view/property_group.rs index 9c86e80..f4b62a4 100644 --- a/src/view/property_group.rs +++ b/src/view/property_group.rs @@ -5,7 +5,7 @@ use yewtil::NeqAssign;  #[derive(Clone, PartialEq, Properties)]  pub struct InputProps< -    O: 'static + VCardPropertyInputObject<M> + Clone, +    O: 'static + VCardPropertyInputGroupObject<M> + Clone,      M: 'static + PartialEq + Clone,  > {      pub generated: Callback<O>, @@ -14,7 +14,7 @@ pub struct InputProps<  #[derive(Clone, PartialEq)]  pub struct PropertyGroupInputComponent< -    O: 'static + VCardPropertyInputObject<M>, +    O: 'static + VCardPropertyInputGroupObject<M>,      M: 'static + PartialEq + Clone,  > {      pub props: InputProps<O, M>, @@ -22,7 +22,7 @@ pub struct PropertyGroupInputComponent<      pub error: Option<Error>,  } -impl<O: 'static + VCardPropertyInputObject<M>, M: 'static + PartialEq + Clone> Component +impl<O: 'static + VCardPropertyInputGroupObject<M>, M: 'static + PartialEq + Clone> Component      for PropertyGroupInputComponent<O, M>  {      type Message = M; @@ -57,7 +57,7 @@ impl<O: 'static + VCardPropertyInputObject<M>, M: 'static + PartialEq + Clone> C      }  } -impl<O: VCardPropertyInputObject<M>, M: 'static + PartialEq + Clone> +impl<O: VCardPropertyInputGroupObject<M>, M: 'static + PartialEq + Clone>      PropertyGroupInputComponent<O, M>  {      /// Returns the error as `Html`  | 
