diff options
Diffstat (limited to 'src/view')
-rw-r--r-- | src/view/address.rs | 29 | ||||
-rw-r--r-- | src/view/main.rs | 281 | ||||
-rw-r--r-- | src/view/name.rs | 57 | ||||
-rw-r--r-- | src/view/telephone.rs | 29 |
4 files changed, 256 insertions, 140 deletions
diff --git a/src/view/address.rs b/src/view/address.rs index 23b697a..a16d93a 100644 --- a/src/view/address.rs +++ b/src/view/address.rs @@ -1,5 +1,9 @@ +use yew::services::ConsoleService; +use yewtil::ptr::Irc; +use yewtil::ptr::Mrc; use super::WeakComponentLink; use yew::prelude::*; +use yewtil::NeqAssign; use crate::viewmodel::address::*; use crate::viewmodel::VCardPropertyInputObject; use super::VCardPropertyInputComponent; @@ -8,7 +12,7 @@ use crate::viewmodel::Error; pub struct AddressView { props: Props, - value: Address, + value: Mrc<Address>, error: Option<Error>, } @@ -28,13 +32,19 @@ pub enum Msg { #[derive(Clone, PartialEq, Properties)] pub struct Props { - pub generated: Callback<Address>, + pub generated: Callback<Irc<Address>>, pub weak_link: WeakComponentLink<AddressView>, } impl VCardPropertyInputComponent<Address> for AddressView { fn get_input_object(&self) -> Address { - self.value.clone() + match self.value.irc().try_unwrap() { + Ok(address) => address, + Err(_) => { + ConsoleService::error("Couldn't unwrap address"); + Address::new() + }, + } } fn get_title(&self) -> String { "Address".to_string() @@ -51,7 +61,7 @@ impl Component for AddressView { props.weak_link.borrow_mut().replace(link); Self { props, - value: Address::new(), + value: Mrc::new(Address::new()), error: None, } } @@ -66,19 +76,14 @@ impl Component for AddressView { Msg::UpdateCountry(c) => self.value.country = c, Msg::ToggleWork => self.value.work = !self.value.work, Msg::ToggleHome => self.value.home = !self.value.home, - Generate => { - self.props.generated.emit(self.value); + Msg::Generate => { + self.props.generated.emit(self.value.irc()); }, }; true } fn change(&mut self, props: <Self as yew::Component>::Properties) -> bool { - if self.props != props { - self.props = props; - true - } else { - false - } + self.props.neq_assign(props) } fn view(&self) -> yew::virtual_dom::VNode { let link = self.props.weak_link.borrow().clone().unwrap(); diff --git a/src/view/main.rs b/src/view/main.rs index e926504..b1c0dda 100644 --- a/src/view/main.rs +++ b/src/view/main.rs @@ -1,6 +1,8 @@ +use yew::services::ConsoleService; +use yewtil::ptr::Irc; +use crate::viewmodel::vcard::VCardData; use crate::viewmodel::Error; use crate::view::telephone::{self,TelephoneView}; -use std::collections::HashSet; use super::WeakComponentLink; use super::name::{self,NameView}; use super::address::{self,AddressView}; @@ -9,13 +11,15 @@ use genpdf::{elements, style, fonts}; use qrcodegen::QrCode; use qrcodegen::QrCodeEcc; use yew::prelude::*; -use vobject::Vcard; +use yewtil::ptr::Mrc; use vobject::vcard::VcardBuilder; use vobject::parameters; +use chrono::prelude::*; use crate::viewmodel::name::Name; use crate::viewmodel::address::Address; use crate::viewmodel::telephone::Telephone; use crate::viewmodel::utility::*; +use boolinator::Boolinator; pub struct MainView { @@ -23,7 +27,7 @@ pub struct MainView { error: Option<Error>, download: Option<Download>, selected_option: DownloadOption, - vcard_builder: VcardBuilder, + vcard_data: Mrc<VCardData>, name_links: Vec<WeakComponentLink<NameView>>, address_links: Vec<WeakComponentLink<AddressView>>, @@ -40,10 +44,9 @@ pub enum Msg { ChangeDownloadOption(DownloadOption), Generate, - GeneratedFormattedName(String), - GeneratedName(Name), - GeneratedAddress(Address), - GeneratedTelephone(Telephone), + GeneratedName(Irc<Name>), + GeneratedAddress(Irc<Address>), + GeneratedTelephone(Irc<Telephone>), GenerationComplete, Nope, @@ -59,7 +62,7 @@ impl Component for MainView { error: None, download: None, selected_option: DownloadOption::VCard, - vcard_builder: VcardBuilder::new(), + vcard_data: Mrc::new(VCardData::new()), name_links: vec![WeakComponentLink::default()], address_links: vec![WeakComponentLink::default()], @@ -126,26 +129,14 @@ impl Component for MainView { shouldrender = true; }, - Msg::GeneratedFormattedName(formatted_name) => { - - self.answer_count += 1; - - self.vcard_builder = self.vcard_builder.with_fullname(formatted_name); - - shouldrender = true; - }, Msg::GeneratedName(name) => { self.answer_count += 1; - self.vcard_builder = self.vcard_builder.with_name( - parameters!(), - name.last_name.is_empty().then(|| name.last_name), - name.first_name.is_empty().then(|| name.first_name), - name.middle_name.is_empty().then(|| name.middle_name), - name.prefix.is_empty().then(|| name.prefix), - name.suffix.is_empty().then(|| name.suffix) - ); + match self.vcard_data.get_mut() { + Some(vcard_data) => vcard_data.add_name(name), + None => ConsoleService::info("Error in GeneratedName: Couldn't get mutable borrow of VCardData"), + }; shouldrender = true; @@ -154,9 +145,10 @@ impl Component for MainView { self.answer_count += 1; - self.vcard_builder = self.vcard_builder.with_adr( - parameters!(), - ); + match self.vcard_data.get_mut() { + Some(vcard_data) => vcard_data.add_address(address), + None => ConsoleService::info("Error in GeneratedAddress: Couldn't get mutable borrow of VCardData"), + }; shouldrender = true; }, @@ -164,31 +156,10 @@ impl Component for MainView { self.answer_count += 1; - match telephone { - Ok(telephone) => { - match self.vcard { - Some(vcard) => { - match vcard.telephones { - Some(telephones) => { - telephones.insert(telephone); - }, - None => { - let telephones = { - let mut telephones = HashSet::new(); - telephones.insert(telephone); - - telephones - }; - - vcard.telephones = Some(vcard::Set::from_hash_set(telephones).unwrap()); - } - }; - }, - None => (), - }; - }, - Err(_) => (), - } + match self.vcard_data.get_mut() { + Some(vcard_data) => vcard_data.add_telephone(telephone), + None => ConsoleService::info("Error in GeneratedTelephone: Couldn't get mutable borrow of VCardData"), + }; shouldrender = true; }, @@ -196,43 +167,167 @@ impl Component for MainView { self.answer_count = 0; - match self.vcard.clone() { - Some(vcard) => { - match self.selected_option { - DownloadOption::VCard => { - self.download = Some( - Download { - file_name: String::from("VCard.vcs"), - content: vcard.to_string(), - mime_type: MimeType::VCard, - } - ); - }, - DownloadOption::QrCode => { - match QrCode::encode_text(&vcard.to_string(), QrCodeEcc::Low) { - Ok(qr) => self.download = Some( - Download { - file_name: String::from("QR-Code VCard.svg"), - content: qr.to_svg_string(4), - mime_type: MimeType::SVG, - } - ), - Err(_) => self.error = Some( - Error{ - msg: String::from("Sorry, VCard is too long!"), - } - ), - }; - }, - _ => (), - }; - - self.vcard = None; - shouldrender = true; + let vcard_data = match self.vcard_data.irc().try_unwrap() { + Ok(data) => data, + Err(err) => { + ConsoleService::error(&format!("Error when unwrapping VCardData: {:?}", err)); + VCardData::new() }, - None => shouldrender = false, // what TODO here? + }; + + let mut builder = VcardBuilder::new(); + + for name in vcard_data.names { + + builder = builder + .with_fullname( + name.generate_fn() + ) + .with_name( + parameters!(), + name.last_name.is_empty().as_some(name.last_name.clone()), + name.first_name.is_empty().as_some(name.first_name.clone()), + name.middle_name.is_empty().as_some(name.middle_name.clone()), + name.prefix.is_empty().as_some(name.prefix.clone()), + name.suffix.is_empty().as_some(name.suffix.clone()) + ); + } + + for address in vcard_data.addresses { + let mut types = String::new(); + if address.work { + types.push_str("WORK"); + } + if address.home { + if types.is_empty() { + types.push(','); + } + types.push_str("HOME") + } + + builder = builder.with_adr( + parameters!("TYPE" => types), + address.post_office_box.is_empty().as_some(address.post_office_box.clone()), + address.extension.is_empty().as_some(address.extension.clone()), + address.street.is_empty().as_some(address.street.clone()), + address.locality.is_empty().as_some(address.locality.clone()), + address.region.is_empty().as_some(address.region.clone()), + address.code.is_empty().as_some(address.code.clone()), + address.country.is_empty().as_some(address.country.clone()), + ); } + for telephone in vcard_data.telephones { + let mut types = String::new(); + if telephone.work { + types.push_str("WORK"); + } + if telephone.home { + if types.is_empty() { + types.push(','); + } + types.push_str("HOME") + } + if telephone.text { + if types.is_empty() { + types.push(','); + } + types.push_str("TEXT") + } + if telephone.voice { + if types.is_empty() { + types.push(','); + } + types.push_str("VOICE") + } + if telephone.fax { + if types.is_empty() { + types.push(','); + } + types.push_str("FAX") + } + if telephone.cell { + if types.is_empty() { + types.push(','); + } + types.push_str("CELL") + } + if telephone.video { + if types.is_empty() { + types.push(','); + } + types.push_str("VIDEO") + } + if telephone.pager { + if types.is_empty() { + types.push(','); + } + types.push_str("PAGER") + } + if telephone.text_phone { + if types.is_empty() { + types.push(','); + } + types.push_str("TEXTPHONE") + } + + builder = builder.with_tel( + parameters!("TYPE" => types), + telephone.number.clone(), + ); + } + + + let rev = Local::now(); + + match builder + .with_version("4.0".to_string()) + .with_rev(format!("{}", rev)) + .build() { + Ok(vcard) => { + match self.selected_option { + DownloadOption::VCard => { + self.download = Some( + Download { + file_name: String::from("VCard.vcs"), + content: vobject::write_component(&vcard), + mime_type: MimeType::VCard, + } + ); + }, + DownloadOption::QrCode => { + match QrCode::encode_text(&vobject::write_component(&vcard), QrCodeEcc::Low) { + Ok(qr) => self.download = Some( + Download { + file_name: String::from("QR-Code VCard.svg"), + content: qr.to_svg_string(4), + mime_type: MimeType::SVG, + } + ), + Err(_) => self.error = Some( + Error{ + msg: String::from("Sorry, VCard is too long!"), + } + ), + }; + }, + _ => (), + }; + }, + Err(err) => self.error = Some( + Error{ + msg: err.to_string(), + } + ), + }; + + match self.vcard_data.get_mut() { + Some(vcard_data) => *vcard_data = VCardData::new(), + None => ConsoleService::info("Couldn't reset VCardData"), + }; + + shouldrender = true; + }, Msg::Nope => shouldrender = false, }; @@ -286,12 +381,8 @@ impl Component for MainView { for self.name_links.iter().map(|link| html!{ <NameView weak_link=link - generated_fn=self.link.callback( - |fmn: Result<properties::FormattedName,()>| - Msg::GeneratedFormattedName(fmn) - ) - generated_name=self.link.callback( - |n: Result<properties::Name,()>| + generated=self.link.callback( + |n: Irc<Name>| Msg::GeneratedName(n) ) /> @@ -304,7 +395,7 @@ impl Component for MainView { html!{ <AddressView weak_link=link generated=self.link.callback( - |a: Result<properties::Address,()>| + |a: Irc<Address>| Msg::GeneratedAddress(a) ) /> @@ -317,7 +408,7 @@ impl Component for MainView { html!{ <TelephoneView weak_link=link generated=self.link.callback( - |t: Result<properties::Telephone,()>| + |t: Irc<Telephone>| Msg::GeneratedTelephone(t) ) /> @@ -326,7 +417,7 @@ impl Component for MainView { } <div class="block level-left"> - <button onclick=self.link.callback(|_| Msg::Generate) class="button is-primary level-item" /> + <button onclick=self.link.callback(|_| Msg::Generate) class="button is-primary level-item">{ "Generate" }</button> <div class="select level-item"> <select id="download_options" onchange=download_options> diff --git a/src/view/name.rs b/src/view/name.rs index bee9256..5b64bae 100644 --- a/src/view/name.rs +++ b/src/view/name.rs @@ -1,14 +1,17 @@ +use yew::services::ConsoleService; +use yewtil::ptr::Irc; +use yewtil::ptr::Mrc; use crate::viewmodel::Error; use crate::view::WeakComponentLink; use yew::prelude::*; -use vobject::Property; +use yewtil::NeqAssign; use crate::viewmodel::name::*; use crate::viewmodel::VCardPropertyInputObject; use super::VCardPropertyInputComponent; pub struct NameView { props: Props, - value: Name, + value: Mrc<Name>, error: Option<Error>, } @@ -24,14 +27,19 @@ pub enum Msg { #[derive(Clone, PartialEq, Properties)] pub struct Props { - pub generated_name: Callback<Name>, - pub generated_fn: Callback<String>, + pub generated: Callback<Irc<Name>>, pub weak_link: WeakComponentLink<NameView>, } impl VCardPropertyInputComponent<Name> for NameView { fn get_input_object(&self) -> Name { - self.value.clone() + match self.value.clone().try_unwrap() { + Ok(name) => name, + Err(_) => { + ConsoleService::error("Couldn't unwrap name"); + Name::new() + }, + } } fn get_title(&self) -> String { "Name".to_string() @@ -48,31 +56,40 @@ impl Component for NameView { props.weak_link.borrow_mut().replace(link); Self { props, - value: Name::new(), + value: Mrc::new(Name::new()), error: None, } } fn update(&mut self, msg: <Self as yew::Component>::Message) -> bool { match msg { - Msg::UpdatePrefix(p) => self.value.prefix = p, - Msg::UpdateFirstName(f) => self.value.first_name = f, - Msg::UpdateMiddleName(m) => self.value.middle_name = m, - Msg::UpdateLastName(l) => self.value.last_name = l, - Msg::UpdateSuffix(s) => self.value.suffix = s, - Generate => { - self.props.generated_fn.emit(self.value.generate_fn()); - self.props.generated_name.emit(self.value); + Msg::UpdatePrefix(p) => match self.value.get_mut() { + Some(value) => value.prefix = p, + None => ConsoleService::info("Couldn't get mutable reference to name"), + }, + Msg::UpdateFirstName(f) => match self.value.get_mut() { + Some(value) => value.first_name = f, + None => ConsoleService::info("Couldn't get mutable reference to name"), + }, + Msg::UpdateMiddleName(m) => match self.value.get_mut() { + Some(value) => value.middle_name = m, + None => ConsoleService::info("Couldn't get mutable reference to name"), + }, + Msg::UpdateLastName(l) => match self.value.get_mut() { + Some(value) => value.last_name = l, + None => ConsoleService::info("Couldn't get mutable reference to name"), + }, + Msg::UpdateSuffix(s) => match self.value.get_mut() { + Some(value) => value.suffix = s, + None => ConsoleService::info("Couldn't get mutable reference to name"), + }, + Msg::Generate => { + self.props.generated.emit(self.value.irc()); }, }; true } fn change(&mut self, props: <Self as yew::Component>::Properties) -> bool { - if self.props != props { - self.props = props; - true - } else { - false - } + self.props.neq_assign(props) } fn view(&self) -> yew::virtual_dom::VNode { let link = self.props.weak_link.borrow().clone().unwrap(); diff --git a/src/view/telephone.rs b/src/view/telephone.rs index 26d7806..ca58538 100644 --- a/src/view/telephone.rs +++ b/src/view/telephone.rs @@ -1,19 +1,22 @@ +use yew::services::ConsoleService; +use yewtil::ptr::Irc; +use yewtil::ptr::Mrc; use crate::view::WeakComponentLink; use crate::viewmodel::Error; use yew::prelude::*; +use yewtil::NeqAssign; use crate::viewmodel::telephone::*; use crate::viewmodel::VCardPropertyInputObject; use super::VCardPropertyInputComponent; pub struct TelephoneView { props: Props, - value: Telephone, + value: Mrc<Telephone>, error: Option<Error>, } pub enum Msg { UpdateNumber(String), - UpdateExtension(String), ToggleWork, ToggleHome, ToggleText, @@ -29,13 +32,19 @@ pub enum Msg { #[derive(Clone, PartialEq, Properties)] pub struct Props { - pub generated: Callback<Telephone>, + pub generated: Callback<Irc<Telephone>>, pub weak_link: WeakComponentLink<TelephoneView>, } impl VCardPropertyInputComponent<Telephone> for TelephoneView { fn get_input_object(&self) -> Telephone { - self.value.clone() + match self.value.irc().try_unwrap() { + Ok(telephone) => telephone, + Err(_) => { + ConsoleService::error("Couldn't unwrap telephone"); + Telephone::new() + }, + } } fn get_title(&self) -> String { "Telephone".to_string() @@ -52,14 +61,13 @@ impl Component for TelephoneView { props.weak_link.borrow_mut().replace(link); Self { props, - value: Telephone::new(), + value: Mrc::new(Telephone::new()), error: None, } } fn update(&mut self, msg: <Self as yew::Component>::Message) -> bool { match msg { Msg::UpdateNumber(n) => self.value.number = n, - Msg::UpdateExtension(e) => self.value.extension = e, Msg::ToggleWork => self.value.work = !self.value.work, Msg::ToggleHome => self.value.home = !self.value.home, Msg::ToggleText => self.value.text = !self.value.text, @@ -70,18 +78,13 @@ impl Component for TelephoneView { Msg::TogglePager => self.value.pager = !self.value.pager, Msg::ToggleTextPhone => self.value.text_phone = !self.value.text_phone, Msg::Generate => { - self.props.generated.emit(self.value); + self.props.generated.emit(self.value.irc()); } }; true } fn change(&mut self, props: <Self as yew::Component>::Properties) -> bool { - if self.props != props { - self.props = props; - true - } else { - false - } + self.props.neq_assign(props) } fn view(&self) -> yew::virtual_dom::VNode { let link = self.props.weak_link.borrow().clone().unwrap(); |