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}; use genpdf::Element as _; use genpdf::{elements, style, fonts}; use qrcodegen::QrCode; use qrcodegen::QrCodeEcc; use yew::prelude::*; use vcard::properties; use vcard::{VCard, VCardError}; use crate::viewmodel::utility::*; pub struct MainView { link: ComponentLink, error: Option, download: Option, selected_option: DownloadOption, vcard: Option, name_links: Vec>, address_links: Vec>, telephone_links: Vec>, answer_count: usize, } pub enum Msg { AddName, AddAddress, AddTelephone, ChangeDownloadOption(DownloadOption), Generate, GeneratedFormattedName(Result), GeneratedName(Result), GeneratedAddress(Result), GeneratedTelephone(Result), 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: None, name_links: vec![WeakComponentLink::default()], address_links: vec![WeakComponentLink::default()], telephone_links: vec![WeakComponentLink::default()], answer_count: 0, } } fn update(&mut self, msg: Self::Message) -> ShouldRender { let shouldrender; // let the compiler check if it is always set self.error = None; match msg { Msg::AddName => { self.name_links.push(WeakComponentLink::default()); shouldrender = true; }, Msg::AddAddress => { self.address_links.push(WeakComponentLink::default()); shouldrender = true; }, Msg::AddTelephone => { self.telephone_links.push(WeakComponentLink::default()); shouldrender = true; }, Msg::ChangeDownloadOption(option) => { self.selected_option = option; shouldrender = false; }, Msg::Generate => { if self.selected_option == DownloadOption::VCard || self.selected_option == DownloadOption::QrCode { for name_link in self.name_links.iter() { let name_link = name_link.borrow().clone().unwrap(); name_link.send_message(name::Msg::Generate); } for address_link in self.address_links.iter() { let address_link = address_link.borrow().clone().unwrap(); address_link.send_message(address::Msg::Generate); } for telephone_link in self.telephone_links.iter() { let telephone_link = telephone_link.borrow().clone().unwrap(); telephone_link.send_message(telephone::Msg::Generate); } } /* 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.")), } } } */ shouldrender = true; }, Msg::GeneratedFormattedName(formatted_name) => { self.answer_count += 1; match formatted_name { Ok(formatted_name) => { match &mut self.vcard { None => { match VCard::from_formatted_name(formatted_name) { Ok(vcard) => self.vcard = Some(vcard), Err(VCardError::FormatError(err)) => { self.error = Some(Error{ msg: err.to_string(), }); }, Err(VCardError::EmptyFormatName) => { self.error= Some(Error{ msg: String::from("At least one of the name fields should be filled out."), }); }, }; }, Some(vcard) => { vcard.formatted_names.insert(formatted_name); }, }; }, Err(_) => (), }; shouldrender = true; }, Msg::GeneratedName(name) => { self.answer_count += 1; match name { Ok(name) => { match self.vcard { Some(vcard) => { match vcard.names { Some(names) => { names.insert(name); }, None => { let names = { let mut names = HashSet::new(); names.insert(name); names }; vcard.names = Some(vcard::Set::from_hash_set(names).unwrap()); } }; }, None => (), }; }, Err(_) => (), }; shouldrender = true; }, Msg::GeneratedAddress(address) => { self.answer_count += 1; match address { Ok(address) => { match self.vcard { Some(vcard) => { match vcard.addresses { Some(addresses) => { addresses.insert(address); }, None => { let addresses = { let mut addresses = HashSet::new(); addresses.insert(address); addresses }; vcard.addresses = Some(vcard::Set::from_hash_set(addresses).unwrap()); } }; }, None => (), }; }, Err(_) => (), }; shouldrender = true; }, Msg::GeneratedTelephone(telephone) => { 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(_) => (), } shouldrender = true; }, Msg::GenerationComplete => { 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; }, None => shouldrender = false, // what TODO here? } }, Msg::Nope => shouldrender = 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() } { for self.name_links.iter().map(|link| html!{ | Msg::GeneratedFormattedName(fmn) ) generated_name=self.link.callback( |n: Result| Msg::GeneratedName(n) ) /> } ) } { for self.address_links.iter().map(|link| html!{ | Msg::GeneratedAddress(a) ) /> } ) } { for self.telephone_links.iter().map(|link| html!{ | Msg::GeneratedTelephone(t) ) /> } ) }
{ 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!{