summaryrefslogtreecommitdiff
path: root/src/view
diff options
context:
space:
mode:
Diffstat (limited to 'src/view')
-rw-r--r--src/view/address.rs103
-rw-r--r--src/view/dates.rs75
-rw-r--r--src/view/main.rs42
-rw-r--r--src/view/mod.rs82
-rw-r--r--src/view/name.rs95
-rw-r--r--src/view/organizational.rs84
-rw-r--r--src/view/property_group.rs81
-rw-r--r--src/view/telephone.rs105
-rw-r--r--src/view/weak_links.rs33
9 files changed, 138 insertions, 562 deletions
diff --git a/src/view/address.rs b/src/view/address.rs
deleted file mode 100644
index 57ea7e4..0000000
--- a/src/view/address.rs
+++ /dev/null
@@ -1,103 +0,0 @@
-use super::VCardPropertyInputComponent;
-use crate::view::InputProps;
-use crate::viewmodel::address::*;
-use crate::viewmodel::Error;
-use crate::viewmodel::VCardPropertyInputObject;
-use yew::prelude::*;
-use yewtil::NeqAssign;
-
-type Props = InputProps<Address, AddressView>;
-
-/// View Component for a `address` field
-///
-/// # Examples
-///
-/// ```compile_fail
-/// let html = html!{
-/// <AddressView weak_link=some_weak_component_link
-/// generated=self.link.callback(
-/// |n: Irc<Address>|
-/// Msg::GeneratedAddress(some_address)
-/// )
-/// />
-/// };
-/// ```
-#[derive(Clone, PartialEq)]
-pub struct AddressView {
- props: Props,
- value: Address,
- error: Option<Error>,
-}
-
-pub enum Msg {
- UpdatePostOfficeBox(String),
- UpdateExtension(String),
- UpdateStreet(String),
- UpdateLocality(String),
- UpdateRegion(String),
- UpdateCode(String),
- UpdateCountry(String),
- ToggleWork,
- ToggleHome,
-
- Generate,
-}
-
-impl VCardPropertyInputComponent<Address> for AddressView {
- fn get_input_object(&self) -> Address {
- self.value.clone()
- }
- fn get_title(&self) -> String {
- "Address".to_string()
- }
- fn get_error(&self) -> Option<Error> {
- self.error.clone()
- }
-}
-
-impl Component for AddressView {
- type Message = Msg;
- type Properties = Props;
- fn create(props: <Self as yew::Component>::Properties, link: yew::html::Scope<Self>) -> Self {
- props.weak_link.borrow_mut().replace(link);
- Self {
- props,
- value: Address::new(),
- error: None,
- }
- }
- fn update(&mut self, msg: <Self as yew::Component>::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,
- Msg::ToggleWork => self.value.work = !self.value.work,
- Msg::ToggleHome => self.value.home = !self.value.home,
- Msg::Generate => {
- self.props.generated.emit(self.value.clone());
- }
- };
- true
- }
- fn change(&mut self, props: <Self as yew::Component>::Properties) -> bool {
- self.props.neq_assign(props)
- }
- fn view(&self) -> yew::virtual_dom::VNode {
- let link = self.props.weak_link.borrow().clone().unwrap();
-
- html! {
- <div class="box">
- { self.render_error() }
-
- <h3 class="subtitle">{ self.get_title() }</h3>
-
- { self.get_input_object().render(&link) }
-
- </div>
- }
- }
-}
diff --git a/src/view/dates.rs b/src/view/dates.rs
deleted file mode 100644
index b2a6dd3..0000000
--- a/src/view/dates.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use super::VCardPropertyInputComponent;
-use crate::view::InputProps;
-use crate::viewmodel::dates::*;
-use crate::viewmodel::Error;
-use crate::viewmodel::VCardPropertyInputObject;
-use yew::prelude::*;
-use yewtil::NeqAssign;
-
-type Props = InputProps<Dates, DatesView>;
-
-#[derive(Clone, PartialEq)]
-pub struct DatesView {
- props: Props,
- value: Dates,
- error: Option<Error>,
-}
-
-pub enum Msg {
- UpdateAnniversary(String),
- UpdateBirthday(String),
-
- Generate,
-}
-
-impl VCardPropertyInputComponent<Dates> for DatesView {
- fn get_input_object(&self) -> Dates {
- self.value.clone()
- }
- fn get_title(&self) -> std::string::String {
- "Dates".to_string()
- }
- fn get_error(&self) -> std::option::Option<Error> {
- self.error.clone()
- }
-}
-
-impl Component for DatesView {
- type Message = Msg;
- type Properties = Props;
- fn create(props: <Self as yew::Component>::Properties, link: yew::html::Scope<Self>) -> Self {
- props.weak_link.borrow_mut().replace(link);
- Self {
- props,
- value: Dates::new(),
- error: None,
- }
- }
- fn update(&mut self, msg: <Self as yew::Component>::Message) -> bool {
- match msg {
- Msg::UpdateAnniversary(a) => self.value.anniversary = a,
- Msg::UpdateBirthday(b) => self.value.birthday = b,
- Msg::Generate => {
- self.props.generated.emit(self.value.clone());
- }
- };
- true
- }
- fn change(&mut self, props: <Self as yew::Component>::Properties) -> bool {
- self.props.neq_assign(props)
- }
- fn view(&self) -> yew::virtual_dom::VNode {
- let link = self.props.weak_link.borrow().clone().unwrap();
-
- html! {
- <div class="box">
- { self.render_error() }
-
- <h3 class="subtitle">{ self.get_title() }</h3>
-
- { self.get_input_object().render(&link) }
-
- </div>
- }
- }
-}
diff --git a/src/view/main.rs b/src/view/main.rs
index 196afa0..d35fb59 100644
--- a/src/view/main.rs
+++ b/src/view/main.rs
@@ -1,18 +1,14 @@
-use super::address::{self, AddressView};
-use super::dates::{self, DatesView};
-use super::name::{self, NameView};
-use super::WeakComponentLink;
-use crate::view::organizational::{self, OrganizationalView};
-use crate::view::telephone::{self, TelephoneView};
-use crate::viewmodel::address::Address;
-use crate::viewmodel::dates::Dates;
-use crate::viewmodel::name::Name;
-use crate::viewmodel::organizational::Organizational;
-use crate::viewmodel::telephone::Telephone;
-use crate::viewmodel::utility::*;
-use crate::viewmodel::vcard::VCardData;
-use crate::viewmodel::Error;
-use crate::viewmodel::VCardPropertyInputObject;
+use crate::view::property_group::PropertyGroupInputComponent;
+use crate::view::weak_links::WeakComponentLink;
+use crate::model::address::*;
+use crate::model::dates::*;
+use crate::model::name::*;
+use crate::model::organizational::*;
+use crate::model::telephone::*;
+use crate::model::utility::*;
+use crate::model::vcard::VCardData;
+use crate::model::Error;
+use crate::model::VCardPropertyInputObject;
use boolinator::Boolinator;
use chrono::prelude::*;
use genpdf::Element as _;
@@ -25,6 +21,12 @@ use yew::prelude::*;
use yew::services::ConsoleService;
use yewtil::ptr::Mrc;
+type NameView = PropertyGroupInputComponent<Name, NameMsg>;
+type AddressView = PropertyGroupInputComponent<Address, AddressMsg>;
+type DatesView = PropertyGroupInputComponent<Dates, DatesMsg>;
+type OrganizationalView = PropertyGroupInputComponent<Organizational, OrganizationalMsg>;
+type TelephoneView = PropertyGroupInputComponent<Telephone, TelephoneMsg>;
+
pub struct MainView {
link: ComponentLink<Self>,
error: Option<Error>,
@@ -117,27 +119,27 @@ impl Component for MainView {
{
for name_link in self.name_links.iter() {
let name_link = name_link.borrow().clone().unwrap();
- name_link.send_message(name::Msg::Generate);
+ 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(address::Msg::Generate);
+ 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(telephone::Msg::Generate);
+ telephone_link.send_message(TelephoneMsg::Generate);
}
for dates_link in self.dates_links.iter() {
let dates_link = dates_link.borrow().clone().unwrap();
- dates_link.send_message(dates::Msg::Generate)
+ dates_link.send_message(DatesMsg::Generate)
}
for organizational_links in self.organizational_links.iter() {
let organizational_link = organizational_links.borrow().clone().unwrap();
- organizational_link.send_message(organizational::Msg::Generate)
+ organizational_link.send_message(OrganizationalMsg::Generate)
}
}
/*
diff --git a/src/view/mod.rs b/src/view/mod.rs
index cbff0fd..691f19a 100644
--- a/src/view/mod.rs
+++ b/src/view/mod.rs
@@ -1,81 +1,3 @@
-use crate::viewmodel::*;
-use std::cell::RefCell;
-use std::ops::Deref;
-use std::rc::Rc;
-use yew::prelude::*;
-
-pub mod address;
-pub mod dates;
pub mod main;
-pub mod name;
-pub mod organizational;
-pub mod telephone;
-
-#[derive(Clone, PartialEq, Properties)]
-pub struct InputProps<O, C>
-where
- O: VCardPropertyInputObject<C> + Clone,
- C: VCardPropertyInputComponent<O> + Clone,
-{
- pub generated: Callback<O>,
- pub weak_link: WeakComponentLink<C>,
-}
-
-/// Trait for types that represent an input component for a vcard property.
-pub trait VCardPropertyInputComponent<T: VCardPropertyInputObject<Self>>:
- Component + Clone + PartialEq
-{
- /// Returns the object containing the input data.
- fn get_input_object(&self) -> T;
- /// Getter function for the title of the component
- fn get_title(&self) -> String;
- /// Getter function for an eventual error.
- fn get_error(&self) -> Option<Error>;
- /// Returns the error as `Html`
- fn render_error(&self) -> Html {
- html! {
- <>
- {
- if self.get_error().is_some() {
- html!{
- <div class="notification is-danger is-light">
- { self.get_error().unwrap().msg }
- </div>
- }
- } else {
- html!{}
- }
- }
- </>
- }
- }
-}
-
-/// Weak link; Useful for being able to have a list of subcomponents.
-pub struct WeakComponentLink<COMP: Component>(Rc<RefCell<Option<ComponentLink<COMP>>>>);
-
-impl<COMP: Component> Clone for WeakComponentLink<COMP> {
- fn clone(&self) -> Self {
- Self(Rc::clone(&self.0))
- }
-}
-
-impl<COMP: Component> Default for WeakComponentLink<COMP> {
- fn default() -> Self {
- Self(Rc::default())
- }
-}
-
-impl<COMP: Component> Deref for WeakComponentLink<COMP> {
- type Target = Rc<RefCell<Option<ComponentLink<COMP>>>>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl<COMP: Component> PartialEq for WeakComponentLink<COMP> {
- fn eq(&self, other: &Self) -> bool {
- Rc::ptr_eq(&self.0, &other.0)
- }
-}
+pub mod property_group;
+pub mod weak_links;
diff --git a/src/view/name.rs b/src/view/name.rs
deleted file mode 100644
index 4b7089b..0000000
--- a/src/view/name.rs
+++ /dev/null
@@ -1,95 +0,0 @@
-use super::VCardPropertyInputComponent;
-use crate::view::InputProps;
-use crate::viewmodel::name::*;
-use crate::viewmodel::Error;
-use crate::viewmodel::VCardPropertyInputObject;
-use yew::prelude::*;
-use yewtil::NeqAssign;
-
-type Props = InputProps<Name, NameView>;
-
-/// View Component for a `name` field
-///
-/// # Examples
-///
-/// ```compile_fail
-/// let html = html!{
-/// <NameView weak_link=some_weak_component_link
-/// generated=self.link.callback(
-/// |n: Irc<Name>|
-/// Msg::GeneratedName(some_name)
-/// )
-/// />
-/// };
-/// ```
-#[derive(Clone, PartialEq)]
-pub struct NameView {
- props: Props,
- value: Name,
- error: Option<Error>,
-}
-
-pub enum Msg {
- UpdatePrefix(String),
- UpdateFirstName(String),
- UpdateMiddleName(String),
- UpdateLastName(String),
- UpdateSuffix(String),
-
- Generate,
-}
-
-impl VCardPropertyInputComponent<Name> for NameView {
- fn get_input_object(&self) -> Name {
- self.value.clone()
- }
- fn get_title(&self) -> String {
- "Name".to_string()
- }
- fn get_error(&self) -> Option<Error> {
- self.error.clone()
- }
-}
-
-impl Component for NameView {
- type Message = Msg;
- type Properties = Props;
- fn create(props: <Self as yew::Component>::Properties, link: yew::html::Scope<Self>) -> Self {
- props.weak_link.borrow_mut().replace(link);
- Self {
- props,
- value: 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,
- Msg::Generate => {
- self.props.generated.emit(self.value.clone());
- }
- };
- true
- }
- fn change(&mut self, props: <Self as yew::Component>::Properties) -> bool {
- self.props.neq_assign(props)
- }
- fn view(&self) -> yew::virtual_dom::VNode {
- let link = self.props.weak_link.borrow().clone().unwrap();
-
- html! {
- <div class="box">
- { self.render_error() }
-
- <h3 class="subtitle">{ self.get_title() }</h3>
-
- { self.get_input_object().render(&link) }
-
- </div>
- }
- }
-}
diff --git a/src/view/organizational.rs b/src/view/organizational.rs
deleted file mode 100644
index 7f2ca69..0000000
--- a/src/view/organizational.rs
+++ /dev/null
@@ -1,84 +0,0 @@
-use super::VCardPropertyInputComponent;
-use crate::view::InputProps;
-use crate::viewmodel::organizational::*;
-use crate::viewmodel::utility::File;
-use crate::viewmodel::Error;
-use crate::viewmodel::VCardPropertyInputObject;
-use yew::prelude::*;
-use yewtil::NeqAssign;
-
-type Props = InputProps<Organizational, OrganizationalView>;
-
-#[derive(Clone, PartialEq)]
-pub struct OrganizationalView {
- props: Props,
- value: Organizational,
- error: Option<Error>,
-}
-
-pub enum Msg {
- UpdateOrg(String),
- UpdateLogo(Option<File>),
- UpdateTitle(String),
- UpdateRole(String),
- UpdateMember(String),
- UpdateRelated(String),
-
- Generate,
-}
-
-impl VCardPropertyInputComponent<Organizational> for OrganizationalView {
- fn get_input_object(&self) -> Organizational {
- self.value.clone()
- }
- fn get_title(&self) -> std::string::String {
- "Organizational".to_string()
- }
- fn get_error(&self) -> std::option::Option<Error> {
- self.error.clone()
- }
-}
-
-impl Component for OrganizationalView {
- type Message = Msg;
- type Properties = Props;
- fn create(props: <Self as yew::Component>::Properties, link: yew::html::Scope<Self>) -> Self {
- props.weak_link.borrow_mut().replace(link);
- Self {
- props,
- value: Organizational::new(),
- error: None,
- }
- }
- fn update(&mut self, msg: <Self as yew::Component>::Message) -> bool {
- match msg {
- Msg::UpdateOrg(o) => self.value.org = o,
- Msg::UpdateLogo(l) => self.value.logo = l,
- Msg::UpdateTitle(t) => self.value.title = t,
- Msg::UpdateRole(r) => self.value.role = r,
- Msg::UpdateMember(m) => self.value.member = m,
- Msg::UpdateRelated(r) => self.value.related = r,
- Msg::Generate => {
- self.props.generated.emit(self.value.clone());
- }
- };
- true
- }
- fn change(&mut self, props: <Self as yew::Component>::Properties) -> bool {
- self.props.neq_assign(props)
- }
- fn view(&self) -> yew::virtual_dom::VNode {
- let link = self.props.weak_link.borrow().clone().unwrap();
-
- html! {
- <div class="box">
- { self.render_error() }
-
- <h3 class="subtitle">{ self.get_title() }</h3>
-
- { self.get_input_object().render(&link) }
-
- </div>
- }
- }
-}
diff --git a/src/view/property_group.rs b/src/view/property_group.rs
new file mode 100644
index 0000000..9c86e80
--- /dev/null
+++ b/src/view/property_group.rs
@@ -0,0 +1,81 @@
+use crate::model::*;
+use crate::view::weak_links::WeakComponentLink;
+use yew::prelude::*;
+use yewtil::NeqAssign;
+
+#[derive(Clone, PartialEq, Properties)]
+pub struct InputProps<
+ O: 'static + VCardPropertyInputObject<M> + Clone,
+ M: 'static + PartialEq + Clone,
+> {
+ pub generated: Callback<O>,
+ pub weak_link: WeakComponentLink<PropertyGroupInputComponent<O, M>>,
+}
+
+#[derive(Clone, PartialEq)]
+pub struct PropertyGroupInputComponent<
+ O: 'static + VCardPropertyInputObject<M>,
+ M: 'static + PartialEq + Clone,
+> {
+ pub props: InputProps<O, M>,
+ pub value: O,
+ pub error: Option<Error>,
+}
+
+impl<O: 'static + VCardPropertyInputObject<M>, M: 'static + PartialEq + Clone> Component
+ for PropertyGroupInputComponent<O, M>
+{
+ type Message = M;
+ type Properties = InputProps<O, M>;
+ fn create(props: <Self as yew::Component>::Properties, link: yew::html::Scope<Self>) -> Self {
+ props.weak_link.borrow_mut().replace(link);
+ Self {
+ props,
+ value: O::new(),
+ error: None,
+ }
+ }
+ fn update(&mut self, msg: <Self as yew::Component>::Message) -> bool {
+ self.value.update(self.props.clone(), msg)
+ }
+ fn change(&mut self, props: <Self as yew::Component>::Properties) -> bool {
+ self.props.neq_assign(props)
+ }
+ fn view(&self) -> yew::virtual_dom::VNode {
+ let link = self.props.weak_link.borrow().clone().unwrap();
+
+ html! {
+ <div class="box">
+ { self.render_error() }
+
+ <h3 class="subtitle">{ self.value.get_title() }</h3>
+
+ { self.value.render(&link) }
+
+ </div>
+ }
+ }
+}
+
+impl<O: VCardPropertyInputObject<M>, M: 'static + PartialEq + Clone>
+ PropertyGroupInputComponent<O, M>
+{
+ /// Returns the error as `Html`
+ fn render_error(&self) -> Html {
+ html! {
+ <>
+ {
+ if self.error.is_some() {
+ html!{
+ <div class="notification is-danger is-light">
+ { self.error.clone().unwrap().msg }
+ </div>
+ }
+ } else {
+ html!{}
+ }
+ }
+ </>
+ }
+ }
+}
diff --git a/src/view/telephone.rs b/src/view/telephone.rs
deleted file mode 100644
index 68389ba..0000000
--- a/src/view/telephone.rs
+++ /dev/null
@@ -1,105 +0,0 @@
-use super::VCardPropertyInputComponent;
-use crate::view::InputProps;
-use crate::viewmodel::telephone::*;
-use crate::viewmodel::Error;
-use crate::viewmodel::VCardPropertyInputObject;
-use yew::prelude::*;
-use yewtil::NeqAssign;
-
-type Props = InputProps<Telephone, TelephoneView>;
-
-/// View Component for a `telephone` field
-///
-/// # Examples
-///
-/// ```compile_fail
-/// let html = html!{
-/// <TelephoneView weak_link=some_weak_component_link
-/// generated=self.link.callback(
-/// |n: Irc<Telephone>|
-/// Msg::GeneratedTelephone(some_telephone)
-/// )
-/// />
-/// };
-/// ```
-#[derive(Clone, PartialEq)]
-pub struct TelephoneView {
- props: Props,
- value: Telephone,
- error: Option<Error>,
-}
-
-pub enum Msg {
- UpdateNumber(String),
- ToggleWork,
- ToggleHome,
- ToggleText,
- ToggleVoice,
- ToggleFax,
- ToggleCell,
- ToggleVideo,
- TogglePager,
- ToggleTextPhone,
-
- Generate,
-}
-
-impl VCardPropertyInputComponent<Telephone> for TelephoneView {
- fn get_input_object(&self) -> Telephone {
- self.value.clone()
- }
- fn get_title(&self) -> String {
- "Telephone".to_string()
- }
- fn get_error(&self) -> Option<Error> {
- self.error.clone()
- }
-}
-
-impl Component for TelephoneView {
- type Message = Msg;
- type Properties = Props;
- fn create(props: <Self as yew::Component>::Properties, link: yew::html::Scope<Self>) -> Self {
- props.weak_link.borrow_mut().replace(link);
- Self {
- props,
- value: 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::ToggleWork => self.value.work = !self.value.work,
- Msg::ToggleHome => self.value.home = !self.value.home,
- Msg::ToggleText => self.value.text = !self.value.text,
- Msg::ToggleVoice => self.value.voice = !self.value.voice,
- Msg::ToggleFax => self.value.fax = !self.value.fax,
- Msg::ToggleCell => self.value.cell = !self.value.cell,
- Msg::ToggleVideo => self.value.video = !self.value.video,
- 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.clone());
- }
- };
- true
- }
- fn change(&mut self, props: <Self as yew::Component>::Properties) -> bool {
- self.props.neq_assign(props)
- }
- fn view(&self) -> yew::virtual_dom::VNode {
- let link = self.props.weak_link.borrow().clone().unwrap();
-
- html! {
- <div class="box">
- { self.render_error() }
-
- <h3 class="subtitle">{ self.get_title() }</h3>
-
- { self.get_input_object().render(&link) }
-
- </div>
- }
- }
-}
diff --git a/src/view/weak_links.rs b/src/view/weak_links.rs
new file mode 100644
index 0000000..689c3c4
--- /dev/null
+++ b/src/view/weak_links.rs
@@ -0,0 +1,33 @@
+use std::cell::RefCell;
+use std::ops::Deref;
+use std::rc::Rc;
+use yew::prelude::*;
+
+/// Weak link; Useful for being able to have a list of subcomponents.
+pub struct WeakComponentLink<COMP: Component>(Rc<RefCell<Option<ComponentLink<COMP>>>>);
+
+impl<COMP: Component> Clone for WeakComponentLink<COMP> {
+ fn clone(&self) -> Self {
+ Self(Rc::clone(&self.0))
+ }
+}
+
+impl<COMP: Component> Default for WeakComponentLink<COMP> {
+ fn default() -> Self {
+ Self(Rc::default())
+ }
+}
+
+impl<COMP: Component> Deref for WeakComponentLink<COMP> {
+ type Target = Rc<RefCell<Option<ComponentLink<COMP>>>>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<COMP: Component> PartialEq for WeakComponentLink<COMP> {
+ fn eq(&self, other: &Self) -> bool {
+ Rc::ptr_eq(&self.0, &other.0)
+ }
+}