use crate::view::telephone::TelephoneView; use std::collections::HashSet; use super::name::{NameView}; use super::address::AddressView; use genpdf::Element as _; use genpdf::{elements, style, fonts}; use qrcodegen::QrCode; use qrcodegen::QrCodeEcc; use yew::prelude::*; use vcard::{VCard, VCardError}; use crate::viewmodel::utility::*; use crate::viewmodel::name::Name; use crate::viewmodel::address::Address; use crate::viewmodel::telephone::Telephone; use crate::viewmodel::VCardPropertyInputObject; pub struct MainView { link: ComponentLink, error: Vec, name: Name, address: Address, telephone: Telephone, download: Option, selected_option: DownloadOption, } pub enum Msg { UpdateName(Name), UpdateAddress(Address), UpdateTelephone(Telephone), Generate(DownloadOption), Nope, } impl Component for MainView { type Message = Msg; type Properties = (); fn create(_props: Self::Properties, link: ComponentLink) -> Self { MainView { link, error: vec![], name: Name::new(), address: Address::new(), telephone: Telephone::new(), download: None, selected_option: DownloadOption::VCard } } fn update(&mut self, msg: Self::Message) -> ShouldRender { self.error.clear(); match msg { Msg::UpdateName(value) => { self.name = value; self.link.send_message(Msg::Generate(self.selected_option)); }, Msg::UpdateAddress(value) => { self.address = value; self.link.send_message(Msg::Generate(self.selected_option)); }, Msg::UpdateTelephone(value) => { self.telephone = value; self.link.send_message(Msg::Generate(self.selected_option)); }, Msg::Generate(option) => { self.selected_option = option; let vcard_content = match self.generate_vcard() { Ok(vcard) => Some(vcard.to_string()), Err(VCardError::FormatError(err)) => { self.error.push(err.to_string()); None } Err(VCardError::EmptyFormatName) => { self.error.push(String::from("At least one of the name fields should be filled out.")); None } }; match option { DownloadOption::VCard => { if vcard_content.is_some() { self.download = Some( Download { file_name: format!("{}.vcs", self.name.formatted_name()), content: vcard_content.unwrap().to_string(), mime_type: MimeType::VCard, } ) } } DownloadOption::QrCode => { if vcard_content.is_some() { match QrCode::encode_text(vcard_content.as_ref().unwrap(), QrCodeEcc::Low) { Ok(qr) => self.download = Some( Download { file_name: format!("QR-Code VCard {}.svg", self.name.formatted_name()), content: qr.to_svg_string(4), mime_type: MimeType::SVG, } ), Err(_) => self.error.push(String::from("Sorry, VCard is too long!")), }; } } DownloadOption::PDF => { match self.generate_pdf() { Ok(pdf) => self.download = Some( Download { file_name: format!("Visitenkarten {}.pdf", self.name.formatted_name()), content: pdf, mime_type: MimeType::PDF, } ), Err(_) => self.error.push(String::from("Unexpected error while generating the PDF. Please contact me about it.")), } } } } Msg::Nope => return false, }; if self.error.len() > 0 { self.download = None; } true } 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::Generate(DownloadOption::VCard), "pdf" => Msg::Generate(DownloadOption::PDF), "qrcode" => Msg::Generate(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_errors() }
{ self.render_download() }
{ self.render_preview() }
} } } impl MainView { fn render_errors(&self) -> Html { html!{ <> { for self.error.iter().map(|err| html!{
{ err }
} ) } } } 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!{