Add wasm live rendering of the Qr-Code only svg
This commit is contained in:
parent
a5cfdeff54
commit
6b0daecd31
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -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",
|
||||||
|
@ -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" }
|
||||||
|
@ -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!()],
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -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![
|
||||||
|
Loading…
Reference in New Issue
Block a user