use crate::model::property_groups::address::*; use crate::model::property_groups::communication::*; use crate::model::property_groups::name::*; use crate::model::property_groups::organizational::*; use crate::model::property_groups::other_identification::*; use crate::model::property_groups::telephone::*; use crate::model::utility::*; use crate::model::vcard::VCardData; use crate::model::Error; use crate::view::property_group::PropertyGroupInputComponent; use crate::view::weak_links::WeakComponentLink; use qrcodegen::QrCode; use qrcodegen::QrCodeEcc; use yew::prelude::*; use yew::services::ConsoleService; use yewtil::ptr::Mrc; type NameView = PropertyGroupInputComponent; type AddressView = PropertyGroupInputComponent; type OtherIdentificationView = PropertyGroupInputComponent; type OrganizationalView = PropertyGroupInputComponent; type TelephoneView = PropertyGroupInputComponent; type CommunicationView = PropertyGroupInputComponent; pub struct MainView { link: ComponentLink, error: Option, download: Option, selected_option: DownloadOption, vcard_data: Mrc, name_links: Vec>, address_links: Vec>, telephone_links: Vec>, communcation_links: Vec>, other_identifications_links: Vec>, organizational_links: Vec>, answer_count: usize, } pub enum Msg { AddName, DelName(usize), AddAddress, DelAddress(usize), AddTelephone, DelTelephone(usize), AddOtherIdentification, DelOtherIdentification(usize), AddOrganizational, DelOrganizational(usize), AddCommunication, DelCommunication(usize), ChangeDownloadOption(DownloadOption), Generate, GeneratedName(Name), GeneratedOtherIdentification(OtherIdentification), GeneratedAddress(Address), GeneratedTelephone(Telephone), GeneratedOrganizational(Organizational), GeneratedCommunication(Communication), GenerationComplete, Nope, } impl Component for MainView { type Message = Msg; type Properties = (); fn create(_props: Self::Properties, link: ComponentLink) -> Self { MainView { link, error: None, download: None, selected_option: DownloadOption::VCard, vcard_data: Mrc::new(VCardData::new()), name_links: vec![WeakComponentLink::default()], address_links: vec![WeakComponentLink::default()], telephone_links: vec![WeakComponentLink::default()], communcation_links: vec![WeakComponentLink::default()], other_identifications_links: vec![WeakComponentLink::default()], organizational_links: vec![WeakComponentLink::default()], answer_count: 0, } } fn update(&mut self, msg: Self::Message) -> ShouldRender { self.error = None; let shouldrender = match msg { Msg::AddName => { self.name_links.push(WeakComponentLink::default()); true } Msg::DelName(idx) => { self.name_links.remove(idx); true } Msg::AddAddress => { self.address_links.push(WeakComponentLink::default()); true } Msg::DelAddress(idx) => { self.address_links.remove(idx); true } Msg::AddTelephone => { self.telephone_links.push(WeakComponentLink::default()); true } Msg::DelTelephone(idx) => { self.telephone_links.remove(idx); true } Msg::AddOtherIdentification => { self.other_identifications_links .push(WeakComponentLink::default()); true } Msg::DelOtherIdentification(idx) => { self.other_identifications_links.remove(idx); true } Msg::AddOrganizational => { self.organizational_links.push(WeakComponentLink::default()); true } Msg::DelOrganizational(idx) => { self.organizational_links.remove(idx); true } Msg::AddCommunication => { self.communcation_links.push(WeakComponentLink::default()); true } Msg::DelCommunication(idx) => { self.communcation_links.remove(idx); true } Msg::ChangeDownloadOption(option) => { self.selected_option = option; false } Msg::Generate => { for name_link in self.name_links.iter() { let name_link = name_link.borrow().clone().unwrap(); name_link.send_message(NameMsg::Generate); } for address_link in self.address_links.iter() { let address_link = address_link.borrow().clone().unwrap(); address_link.send_message(AddressMsg::Generate); } for telephone_link in self.telephone_links.iter() { let telephone_link = telephone_link.borrow().clone().unwrap(); telephone_link.send_message(TelephoneMsg::Generate); } for other_identifications_link in self.other_identifications_links.iter() { let other_identifications_link = other_identifications_link.borrow().clone().unwrap(); other_identifications_link.send_message(OtherIdentificationMsg::Generate) } for organizational_link in self.organizational_links.iter() { let organizational_link = organizational_link.borrow().clone().unwrap(); organizational_link.send_message(OrganizationalMsg::Generate) } for communcation_link in self.communcation_links.iter() { let communcation_link = communcation_link.borrow().clone().unwrap(); communcation_link.send_message(CommunicationMsg::Generate) } true } Msg::GeneratedName(name) => { self.answer_count += 1; 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", ), }; true } Msg::GeneratedOtherIdentification(other_identification) => { self.answer_count += 1; match self.vcard_data.get_mut() { Some(vcard_data) => vcard_data.add_other_identification(other_identification), None => ConsoleService::info( "Error in GeneratedOtherIdentification: Couldn't get mutable borrow of VCardData", ), }; true } Msg::GeneratedAddress(address) => { self.answer_count += 1; 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", ), }; true } Msg::GeneratedTelephone(telephone) => { self.answer_count += 1; 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", ), }; true } Msg::GeneratedCommunication(communication) => { self.answer_count += 1; match self.vcard_data.get_mut() { Some(vcard_data) => vcard_data.add_communication(communication), None => ConsoleService::info( "Error in GeneratedCommunication: Couldn't get mutable borrow of VCardData", ), }; true } Msg::GeneratedOrganizational(organizational) => { self.answer_count += 1; match self.vcard_data.get_mut() { Some(vcard_data) => vcard_data.add_organizational(organizational), None => ConsoleService::info("Error in GeneratedOrganizational: Couldn't get mutable borrow of VCardData"), }; true } Msg::GenerationComplete => { self.answer_count = 0; if let DownloadOption::PDF = self.selected_option { match self.vcard_data.generate_pdf() { Ok(pdf) => { let mut vcard_name = String::new(); if let Some(vcard_data) = self.vcard_data.get_mut() { if let Some(name) = vcard_data.names.get(0) { vcard_name = name.generate_fn(); } } self.download = Some( Download { file_name: format!("Visitenkarten {}.pdf", vcard_name), content: pdf, mime_type: MimeType::PDF, } ); }, Err(_) => self.error = Some( Error { msg: String::from("Unexpected error while generating the PDF. Please contact me about it.") } ), }; } else { match self.vcard_data.build_vcard() { 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"), }; true } Msg::Nope => false, }; if self.answer_count >= self.get_subcomponent_count() { self.link.send_message(Msg::GenerationComplete); } if self.error.is_some() { self.download = None; } shouldrender } fn change(&mut self, _props: Self::Properties) -> ShouldRender { false } fn view(&self) -> Html { let download_options = self.link.callback(|e: ChangeData| match e { ChangeData::Select(v) => match v.value().as_str() { "vcard" => Msg::ChangeDownloadOption(DownloadOption::VCard), "pdf" => Msg::ChangeDownloadOption(DownloadOption::PDF), "qrcode" => Msg::ChangeDownloadOption(DownloadOption::QrCode), _ => Msg::Nope, }, _ => Msg::Nope, }); html! { <>

{ "A Generator for vCards" }

{ "Supports generating vCards (.vcf), print-ready PDF business cards and QR Codes" }

{ self.render_error() }

{ "Names" }

{ for self.name_links.iter().enumerate().map(move |(idx, link)| html!{ } ) }

{ "Other Identification Properties" }

{ for self.other_identifications_links.iter().enumerate().map(move |(idx, link)| html!{ } ) }

{ "Addresses" }

{ for self.address_links.iter().enumerate().map(move |(idx, link)| html!{ } ) }

{ "Telephone Numbers" }

{ for self.telephone_links.iter().enumerate().map(move |(idx, link)| html!{ } ) }

{ "Communication" }

{ for self.communcation_links.iter().enumerate().map(move |(idx, link)| html!{ } ) }

{ "Organisations" }

{ for self.organizational_links.iter().enumerate().map(move |(idx, link)| html!{ } ) }
{ self.render_download() }
{ self.render_preview() }
} } } impl MainView { fn render_error(&self) -> Html { html! { <> { match &self.error { Some(error) => { html!{
{ error.msg.clone() }
} }, None => html!{}, } } } } fn render_download(&self) -> Html { if self.download.is_some() { let download = self.download.as_ref().unwrap(); html! { { "Download" } } } else { html! {} } } fn render_preview(&self) -> Html { if self.download.is_some() { let download = self.download.as_ref().unwrap(); match download.mime_type { MimeType::PDF => html! {