summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjelemux <jeremias.weber@protonmail.com>2021-02-03 07:08:49 +0100
committerjelemux <jeremias.weber@protonmail.com>2021-02-03 07:08:49 +0100
commit51bf8e89ce07864b70d7138bbc3958faf499cc67 (patch)
tree31e870adb0bcd539135059613e05a0f31e08e987
parent94a0e361e180223adf2bc9760c8810dfa3c2681f (diff)
downloadwasm-card-51bf8e89ce07864b70d7138bbc3958faf499cc67.tar.gz
wasm-card-51bf8e89ce07864b70d7138bbc3958faf499cc67.tar.bz2
now it compiles
-rw-r--r--Cargo.toml3
-rw-r--r--snippets103
-rw-r--r--src/view/address.rs29
-rw-r--r--src/view/main.rs281
-rw-r--r--src/view/name.rs57
-rw-r--r--src/view/telephone.rs29
-rw-r--r--src/viewmodel/address.rs2
-rw-r--r--src/viewmodel/mod.rs2
-rw-r--r--src/viewmodel/name.rs4
-rw-r--r--src/viewmodel/telephone.rs15
-rw-r--r--src/viewmodel/vcard.rs32
11 files changed, 399 insertions, 158 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 34eb65f..34281a3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -14,12 +14,13 @@ wasm-bindgen = "0.2.68"
js-sys = "0.3.45"
console_error_panic_hook = "0.1.6"
wee_alloc = "0.4.5"
-yew-state = "^0.4"
+yewtil = "0.3.2"
printpdf = "0.3.3"
base64 = "0.13.0"
vobject = "^0.7"
genpdf = { path = "../genpdf-rs" }
qrcodegen = "1.6.0"
+boolinator = "2.4.0"
[dependencies.yew]
version = "0.17.4"
diff --git a/snippets b/snippets
new file mode 100644
index 0000000..dc4e601
--- /dev/null
+++ b/snippets
@@ -0,0 +1,103 @@
+
+
+ match self.vcard_data.get_mut() {
+ Some(vcard_builder) => *vcard_builder = 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)
+ ),
+ None => (),
+ };
+
+ --------------------------------------------------------------
+
+ 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")
+ }
+
+ match self.vcard_data.get_mut() {
+ Some(vcard_builder) => *vcard_builder = vcard_builder.with_adr(
+ parameters!("TYPE" => types),
+ address.post_office_box.is_empty().then(|| address.post_office_box),
+ address.extension.is_empty().then(|| address.extension),
+ address.street.is_empty().then(|| address.street),
+ address.locality.is_empty().then(|| address.locality),
+ address.region.is_empty().then(|| address.region),
+ address.code.is_empty().then(|| address.code),
+ address.country.is_empty().then(|| address.country),
+ ),
+ None => (),
+ };
+
+ ----------------------------------------------------------------
+
+ 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")
+ }
+
+ match self.vcard_data.get_mut() {
+ Some(vcard_builder) => *vcard_builder = vcard_builder.with_tel(
+ parameters!("TYPE" => types),
+ telephone.number,
+ ),
+ None => (),
+ }; \ No newline at end of file
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();
diff --git a/src/viewmodel/address.rs b/src/viewmodel/address.rs
index 61bd464..6fd3173 100644
--- a/src/viewmodel/address.rs
+++ b/src/viewmodel/address.rs
@@ -1,7 +1,7 @@
use super::*;
use crate::view::address::*;
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct Address {
pub post_office_box: String,
pub extension: String,
diff --git a/src/viewmodel/mod.rs b/src/viewmodel/mod.rs
index cc25d68..de433de 100644
--- a/src/viewmodel/mod.rs
+++ b/src/viewmodel/mod.rs
@@ -1,7 +1,7 @@
use yew::prelude::*;
-use vobject::Property;
use crate::view::VCardPropertyInputComponent;
+pub mod vcard;
pub mod address;
pub mod name;
pub mod telephone;
diff --git a/src/viewmodel/name.rs b/src/viewmodel/name.rs
index 26beaa1..a88e07f 100644
--- a/src/viewmodel/name.rs
+++ b/src/viewmodel/name.rs
@@ -1,7 +1,7 @@
use super::*;
use crate::view::name::*;
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct Name {
pub prefix: String,
pub first_name: String,
@@ -70,7 +70,7 @@ impl VCardPropertyInputObject<NameView> for Name {
impl Name {
pub fn generate_fn(&self) -> String {
- let full_name = String::new();
+ let mut full_name = String::new();
full_name.push_str(&self.prefix);
if !self.first_name.is_empty() {
diff --git a/src/viewmodel/telephone.rs b/src/viewmodel/telephone.rs
index e5f63f0..6c930a2 100644
--- a/src/viewmodel/telephone.rs
+++ b/src/viewmodel/telephone.rs
@@ -1,11 +1,9 @@
-use std::collections::HashSet;
use super::*;
use crate::view::telephone::*;
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct Telephone {
pub number: String,
- pub extension: String,
pub work: bool,
pub home: bool,
pub text: bool,
@@ -21,7 +19,6 @@ impl VCardPropertyInputObject<TelephoneView> for Telephone {
fn new() -> Self {
Self {
number: String::new(),
- extension: String::new(),
work: false,
home: false,
text: false,
@@ -42,13 +39,6 @@ impl VCardPropertyInputObject<TelephoneView> for Telephone {
oninput: link.callback(|e: InputData| Msg::UpdateNumber(e.value)),
value: self.number.clone(),
},
- VCardPropertyInputField::Text{
- label: "Extension".to_string(),
- id: Some("extension".to_string()),
- placeholder: None,
- oninput: link.callback(|e: InputData| Msg::UpdateExtension(e.value)),
- value: self.extension.clone(),
- },
VCardPropertyInputField::CheckBox{
label: "Work".to_string(),
id: Some("work".to_string()),
@@ -106,7 +96,6 @@ impl VCardPropertyInputObject<TelephoneView> for Telephone {
]
}
fn is_empty(&self) -> bool {
- self.number.is_empty() &&
- self.extension.is_empty()
+ self.number.is_empty()
}
} \ No newline at end of file
diff --git a/src/viewmodel/vcard.rs b/src/viewmodel/vcard.rs
new file mode 100644
index 0000000..2d415b7
--- /dev/null
+++ b/src/viewmodel/vcard.rs
@@ -0,0 +1,32 @@
+use yewtil::ptr::Irc;
+use crate::viewmodel::telephone::Telephone;
+use crate::viewmodel::address::Address;
+use crate::viewmodel::name::Name;
+
+#[derive(Clone, Debug)]
+pub struct VCardData {
+ pub names: Vec<Irc<Name>>,
+ pub addresses: Vec<Irc<Address>>,
+ pub telephones: Vec<Irc<Telephone>>,
+}
+
+macro_rules! make_vec_adder_fn {
+ ( $fnname:ident $property:ident $($arg_name:ident : $arg_type:ty),* ) => {
+ pub fn $fnname(&mut self, $( $arg_name : $arg_type ),*) {
+ $(self.$property.push($arg_name);)*
+ }
+ };
+}
+
+impl VCardData {
+ pub fn new() -> Self {
+ Self {
+ names: Vec::new(),
+ addresses: Vec::new(),
+ telephones: Vec::new(),
+ }
+ }
+ make_vec_adder_fn!( add_name names name: Irc<Name> );
+ make_vec_adder_fn!( add_address addresses address: Irc<Address> );
+ make_vec_adder_fn!( add_telephone telephones telephone: Irc<Telephone> );
+} \ No newline at end of file