From 49588f22f7d20193f899226107c9e323a82c6951 Mon Sep 17 00:00:00 2001 From: jelemux Date: Thu, 19 Nov 2020 07:37:20 +0100 Subject: added telephone, but causes problems --- Cargo.toml | 5 +- src/address.rs | 239 ------------------------------- src/lib.rs | 370 +---------------------------------------------- src/name.rs | 189 ------------------------ src/util.rs | 39 +++++ src/view/address.rs | 213 ++++++++++++++++++++++++++++ src/view/birthday.rs | 11 ++ src/view/mod.rs | 386 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/view/name.rs | 171 ++++++++++++++++++++++ src/view/photo.rs | 10 ++ src/view/telephone.rs | 183 ++++++++++++++++++++++++ 11 files changed, 1022 insertions(+), 794 deletions(-) delete mode 100644 src/address.rs delete mode 100644 src/name.rs create mode 100644 src/util.rs create mode 100644 src/view/address.rs create mode 100644 src/view/birthday.rs create mode 100644 src/view/mod.rs create mode 100644 src/view/name.rs create mode 100644 src/view/photo.rs create mode 100644 src/view/telephone.rs diff --git a/Cargo.toml b/Cargo.toml index 0603273..346d7c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ edition = "2018" crate-type = ["cdylib", "rlib"] [dependencies] -yew = "0.17.4" wasm-bindgen = "0.2.68" js-sys = "0.3.45" console_error_panic_hook = "0.1.6" @@ -21,6 +20,10 @@ vcard = "0.4.7" genpdf = { path = "../genpdf-rs" } qrcodegen = "1.6.0" +[dependencies.yew] +version = "0.17.4" +features = ["services"] + [dependencies.chrono] version = "0.4.19" default-features = false diff --git a/src/address.rs b/src/address.rs deleted file mode 100644 index d048dc0..0000000 --- a/src/address.rs +++ /dev/null @@ -1,239 +0,0 @@ -use yew::prelude::*; -use vcard::properties; -use vcard::parameters; -use vcard::values::{self, text}; -use std::collections::HashSet; - -#[derive(Clone)] -pub struct Address { - pub post_office_box: String, - pub extension: String, - pub street: String, - pub locality: String, - pub region: String, - pub code: String, - pub country: String, - address_type: AddressType, -} - -impl Address { - pub fn new_with_type(address_type: AddressType) -> Self { - Self { - post_office_box: String::new(), - extension: String::new(), - street: String::new(), - locality: String::new(), - region: String::new(), - code: String::new(), - country: String::new(), - address_type - } - } - pub fn to_vcard_address(&self) -> properties::Address { - let address_value = values::address_value::AddressValue::from_components( - match self.post_office_box.is_empty() { - true => None, - false => Some(text::Component::from_str(&self.post_office_box).unwrap()), - }, - match self.extension.is_empty() { - true => None, - false => Some(text::Component::from_str(&self.extension).unwrap()), - }, - match self.street.is_empty() { - true => None, - false => Some(text::Component::from_str(&self.street).unwrap()), - }, - match self.locality.is_empty() { - true => None, - false => Some(text::Component::from_str(&self.locality).unwrap()), - }, - match self.region.is_empty() { - true => None, - false => Some(text::Component::from_str(&self.region).unwrap()), - }, - match self.code.is_empty() { - true => None, - false => Some(text::Component::from_str(&self.code).unwrap()), - }, - match self.country.is_empty() { - true => None, - false => Some(text::Component::from_str(&self.country).unwrap()), - }, - ); - - let mut address = properties::Address::from_address_value(address_value); - - let type_values = { - let mut type_values = HashSet::new(); - - type_values.insert( - match self.address_type { - AddressType::Home => values::type_value::TypeValue::Home, - AddressType::Work => values::type_value::TypeValue::Work, - } - ); - - vcard::Set::from_hash_set(type_values).unwrap() - }; - - address.typ = Some(parameters::typ::Type::from_type_values(type_values)); - - address - } -} - -#[derive(Clone, Copy, PartialEq)] -pub enum AddressType { - Home, - Work, -} - -impl AddressType { - pub fn to_str(&self) -> &str { - match self { - AddressType::Home => "Home", - AddressType::Work => "Work", - } - } -} - -pub struct AddressView { - link: ComponentLink, - value: Address, - oninput: Callback
, -} - -pub enum Msg { - UpdatePostOfficeBox(String), - UpdateExtension(String), - UpdateStreet(String), - UpdateLocality(String), - UpdateRegion(String), - UpdateCode(String), - UpdateCountry(String), -} - -#[derive(Clone, PartialEq, Properties)] -pub struct Props { - pub oninput: Callback
, - pub address_type: AddressType, - //pub errors: Vec, -} - -impl Component for AddressView { - type Message = Msg; - type Properties = Props; - fn create(props: ::Properties, link: yew::html::Scope) -> Self { - Self { - link, - value: Address::new_with_type(props.address_type), - oninput: props.oninput, - } - } - fn update(&mut self, msg: ::Message) -> bool { - match msg { - Msg::UpdatePostOfficeBox(b) => self.value.post_office_box = b, - Msg::UpdateExtension(e) => self.value.extension = e, - Msg::UpdateStreet(s) => self.value.street = s, - Msg::UpdateLocality(l) => self.value.locality = l, - Msg::UpdateRegion(r) => self.value.region = r, - Msg::UpdateCode(p) => self.value.code = p, - Msg::UpdateCountry(c) => self.value.country = c, - }; - self.oninput.emit(self.value.clone()); - true - } - fn change(&mut self, props: ::Properties) -> bool { - self.oninput = props.oninput; - self.value.address_type = props.address_type; - true - } - fn view(&self) -> yew::virtual_dom::VNode { - html!{ -
-

{ format!("{} Address", self.value.address_type.to_str()) }

- -
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
-
- } - } -} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 30d6d59..6982920 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,382 +1,22 @@ #![recursion_limit="1024"] extern crate wee_alloc; extern crate console_error_panic_hook; -use std::collections::HashSet; -use name::{NameView,Name}; -use address::{AddressView,Address,AddressType}; -use genpdf::Element as _; -use genpdf::{elements, style, fonts}; -use qrcodegen::QrCode; -use qrcodegen::QrCodeEcc; use wasm_bindgen::prelude::*; -use yew::prelude::*; -use vcard::{VCard, VCardError}; +use yew::prelude::App; use std::panic; - -mod name; -mod address; +use view::MainView; // Use `wee_alloc` as the global allocator. #[global_allocator] static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; +mod view; +mod util; + fn init() { panic::set_hook(Box::new(console_error_panic_hook::hook)); } -#[derive(Clone)] -pub struct Download { - pub file_name: String, - pub content: String, - pub mime_type: MimeType, -} - -impl Download { - pub fn as_data_link(&self) -> String { - let data = base64::encode(&*self.content); - let uri_component: String = js_sys::encode_uri_component(&data).into(); - - format!("data:{};base64,{}", self.mime_type.as_text(), uri_component) - } -} - -#[derive(Clone, Copy)] -pub enum MimeType { - PDF, - VCard, - SVG, -} - -impl MimeType { - pub fn as_text(&self) -> &str { - match self { - MimeType::PDF => "application/pdf", - MimeType::VCard => "text/vcard", - MimeType::SVG => "image/svg+xml", - } - } -} - -#[derive(Clone, Copy)] -pub enum DownloadOption { - PDF, - VCard, - QrCode, -} - -pub struct MainView { - link: ComponentLink, - error: Vec, - name: Name, - work_address: Address, - home_address: Address, - download: Option, - selected_option: DownloadOption, -} - -pub enum Msg { - UpdateName(Name), - UpdateHomeAddress(Address), - UpdateWorkAddress(Address), - 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(), - work_address: Address::new_with_type(AddressType::Work), - home_address: Address::new_with_type(AddressType::Home), - 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::UpdateHomeAddress(value) => { - self.home_address = value; - self.link.send_message(Msg::Generate(self.selected_option)); - }, - Msg::UpdateWorkAddress(value) => { - self.work_address = 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!{ -