Add wasm live rendering of the Qr-Code only svg

This commit is contained in:
Dietrich 2021-05-30 14:33:23 +02:00 committed by Franz Dietrich
parent a5cfdeff54
commit 6b0daecd31
4 changed files with 49 additions and 23 deletions

1
Cargo.lock generated
View File

@ -465,6 +465,7 @@ version = "0.3.1"
dependencies = [ dependencies = [
"enum-map", "enum-map",
"fluent 0.15.0", "fluent 0.15.0",
"qrcode",
"seed", "seed",
"serde", "serde",
"shared", "shared",

View File

@ -23,5 +23,6 @@ unic-langid = "0.9"
strum_macros = "0.20" strum_macros = "0.20"
strum = "0.20" strum = "0.20"
enum-map = "1" enum-map = "1"
qrcode = "0.12"
shared = { path = "../shared" } shared = { path = "../shared" }

View File

@ -4,14 +4,9 @@ pub mod pages;
use pages::list_links; use pages::list_links;
use pages::list_users; use pages::list_users;
use seed::attrs; use seed::{attrs, button, div, input, label, log, prelude::*, App, Url, C};
use seed::button;
use seed::input;
use seed::label;
use seed::{div, log, prelude::*, App, Url, C};
use shared::apirequests::users::LoginUser; use shared::apirequests::users::LoginUser;
use shared::datatypes::Loadable; use shared::datatypes::{Loadable, User};
use shared::datatypes::User;
use crate::i18n::{I18n, Lang}; use crate::i18n::{I18n, Lang};
@ -23,13 +18,14 @@ fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
orders.subscribe(Msg::UrlChanged); orders.subscribe(Msg::UrlChanged);
orders.send_msg(Msg::GetLoggedUser); orders.send_msg(Msg::GetLoggedUser);
log!(url); log!(&url);
let lang = I18n::new(Lang::EnUS); let lang = I18n::new(Lang::EnUS);
Model { Model {
index: 0, index: 0,
base_url: Url::new().add_path_part("app"), base_url: Url::new().add_path_part("app"),
current_url: url.clone(),
page: Page::init(url, orders, lang.clone()), page: Page::init(url, orders, lang.clone()),
i18n: lang, i18n: lang,
user: Loadable::Data(None), user: Loadable::Data(None),
@ -46,6 +42,7 @@ fn init(url: Url, orders: &mut impl Orders<Msg>) -> Model {
struct Model { struct Model {
index: usize, index: usize,
base_url: Url, base_url: Url,
current_url: Url,
page: Page, page: Page,
i18n: i18n::I18n, i18n: i18n::I18n,
user: Loadable<User>, user: Loadable<User>,
@ -100,6 +97,7 @@ pub enum Msg {
UserReceived(User), UserReceived(User),
NoMessage, NoMessage,
NotAuthenticated, NotAuthenticated,
Logout,
Login, Login,
UsernameChanged(String), UsernameChanged(String),
PasswordChanged(String), PasswordChanged(String),
@ -122,31 +120,38 @@ fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
} }
Msg::NoMessage => (), Msg::NoMessage => (),
Msg::GetLoggedUser => { Msg::GetLoggedUser => {
orders.skip(); // No need to rerender model.user = Loadable::Loading;
orders.perform_cmd(async { orders.perform_cmd(async {
// create request // create request
let request = unwrap_or_return!( let request = unwrap_or_return!(
Request::new("/admin/json/get_logged_user/") Request::new("/admin/json/get_logged_user/")
.method(Method::Post) .method(Method::Post)
.json(&()), .json(&()),
Msg::NotAuthenticated Msg::Logout
); );
// perform and get response // perform and get response
let response = unwrap_or_return!(fetch(request).await, Msg::NotAuthenticated); let response = unwrap_or_return!(fetch(request).await, Msg::Logout);
// validate response status // validate response status
let response = unwrap_or_return!(response.check_status(), Msg::NotAuthenticated); let response = unwrap_or_return!(response.check_status(), Msg::Logout);
let user: User = unwrap_or_return!(response.json().await, Msg::NotAuthenticated); let user: User = unwrap_or_return!(response.json().await, Msg::Logout);
Msg::UserReceived(user) Msg::UserReceived(user)
}); });
} }
Msg::UserReceived(user) => model.user = Loadable::Data(Some(user)), Msg::UserReceived(user) => {
model.user = Loadable::Data(Some(user));
model.page = Page::init(model.current_url.clone(), orders, model.i18n.clone());
}
Msg::NotAuthenticated => { Msg::NotAuthenticated => {
if model.user.is_some() { if model.user.is_some() {
model.user = Loadable::Data(None); model.user = Loadable::Data(None);
logout(orders) logout(orders)
} }
} }
Msg::Logout => {
model.user = Loadable::Data(None);
logout(orders)
}
Msg::Login => login_user(model, orders), Msg::Login => login_user(model, orders),
Msg::UsernameChanged(s) => model.login_data.username = s, Msg::UsernameChanged(s) => model.login_data.username = s,
Msg::PasswordChanged(s) => model.login_data.password = s, Msg::PasswordChanged(s) => model.login_data.password = s,
@ -162,7 +167,7 @@ fn logout(orders: &mut impl Orders<Msg>) {
} }
fn login_user(model: &mut Model, orders: &mut impl Orders<Msg>) { fn login_user(model: &mut Model, orders: &mut impl Orders<Msg>) {
orders.skip(); // No need to rerender model.user = Loadable::Loading;
let data = model.login_data.clone(); let data = model.login_data.clone();
orders.perform_cmd(async { orders.perform_cmd(async {
@ -245,13 +250,13 @@ impl<'a> Urls<'a> {
fn view(model: &Model) -> Node<Msg> { fn view(model: &Model) -> Node<Msg> {
div![ div![
C!["page"], C!["page"],
if let Some(ref user) = *model.user { match model.user {
div![ Loadable::Data(Some(ref user)) => div![
navigation::navigation(&model.i18n, &model.base_url, user), navigation::navigation(&model.i18n, &model.base_url, user),
view_content(&model.page, &model.base_url) view_content(&model.page, &model.base_url)
] ],
} else { Loadable::Data(None) => view_login(&model.i18n, model),
view_login(&model.i18n, model) Loadable::Loading => div![C!("lds-ellipsis"), div!(), div!(), div!(), div!()],
} }
] ]
} }

View File

@ -2,9 +2,10 @@ use std::cell::RefCell;
use enum_map::EnumMap; use enum_map::EnumMap;
use fluent::fluent_args; use fluent::fluent_args;
use qrcode::{render::svg, QrCode};
use seed::{ use seed::{
a, attrs, button, div, h1, img, input, log, prelude::*, section, span, table, td, th, tr, Url, a, attrs, button, div, h1, img, input, log, prelude::*, raw, section, span, table, td, th, tr,
C, Url, C,
}; };
use shared::{ use shared::{
@ -508,7 +509,7 @@ fn view_link_table_filter_input<F: Fn(&str) -> String>(model: &Model, t: F) -> N
] ]
} }
/// display a single link /// display a single table row containing one link
fn view_link(l: &FullLink) -> Node<Msg> { fn view_link(l: &FullLink) -> Node<Msg> {
// Ugly hack - this is needed to be able to move the l into the closures... l.clone() in place does not work. // Ugly hack - this is needed to be able to move the l into the closures... l.clone() in place does not work.
let link = LinkDelta::from(l.clone()); let link = LinkDelta::from(l.clone());
@ -598,6 +599,10 @@ fn edit_or_create_link<F: Fn(&str) -> String>(l: &RefCell<LinkDelta>, t: F) -> N
}, },
input_ev(Ev::Input, |s| { Msg::Edit(EditMsg::EditCodeChanged(s)) }), input_ev(Ev::Input, |s| { Msg::Edit(EditMsg::EditCodeChanged(s)) }),
],] ],]
],
tr![
th![t("qr-code")],
td![raw!(&generate_qr_code(&format!("http://{}", &link.code)))]
] ]
], ],
a![ a![
@ -611,6 +616,20 @@ fn edit_or_create_link<F: Fn(&str) -> String>(l: &RefCell<LinkDelta>, t: F) -> N
] ]
} }
fn generate_qr_code(link: &str) -> String {
if let Ok(qr) = QrCode::with_error_correction_level(&link, qrcode::EcLevel::L) {
let svg = qr
.render()
.min_dimensions(100, 100)
.dark_color(svg::Color("#000000"))
.light_color(svg::Color("#ffffff"))
.build();
svg
} else {
"".to_string()
}
}
/// a close button for dialogs /// a close button for dialogs
fn close_button() -> Node<Msg> { fn close_button() -> Node<Msg> {
div![ div![