195 lines
5.5 KiB
Rust
195 lines
5.5 KiB
Rust
use std::cell::{RefCell, RefMut};
|
|
use std::rc::Rc;
|
|
|
|
use adw::{Clamp, ToolbarView, prelude::*};
|
|
|
|
use adw::{ActionRow, Application, ApplicationWindow, HeaderBar};
|
|
use gtk::{
|
|
Box, Button, CssProvider, Grid, GridLayout, Label, ListBox, Orientation, PasswordEntry,
|
|
SelectionMode,
|
|
};
|
|
|
|
use crate::pipe;
|
|
use glib::clone;
|
|
|
|
fn build_ui(
|
|
app: &Application,
|
|
ctg_pipe: async_channel::Receiver<crate::pipe::CardToGUI>,
|
|
gtc_pipe: async_channel::Sender<crate::pipe::GUIToCard>,
|
|
) {
|
|
let main_box = Box::builder().orientation(Orientation::Vertical).build();
|
|
|
|
let password_grid = Grid::new();
|
|
|
|
let password_mask: Vec<Button> = (0..5)
|
|
.map(|f| {
|
|
Button::builder()
|
|
.name(format!("button_{}", f))
|
|
.icon_name("")
|
|
.can_focus(false)
|
|
.can_target(false)
|
|
.hexpand(true)
|
|
.css_classes(&["cell"][..])
|
|
.build()
|
|
})
|
|
.collect();
|
|
|
|
for i in 0..5 {
|
|
password_grid.attach(&password_mask[i], i as i32, 0, 1, 1);
|
|
}
|
|
|
|
let password_field = PasswordEntry::builder()
|
|
.margin_bottom(12)
|
|
.width_request(5)
|
|
.width_chars(0)
|
|
.css_classes(&["invisible"][..])
|
|
.build();
|
|
|
|
password_grid.attach(&password_field, 0, 0, 5, 1);
|
|
|
|
password_field.connect_changed(move |v| {
|
|
let count = v.text().len();
|
|
for i in 0..5 {
|
|
password_mask[i].set_icon_name(if count > i {
|
|
"window-close-symbolic"
|
|
} else {
|
|
""
|
|
});
|
|
}
|
|
|
|
if count > 5 {
|
|
v.delete_text(5, -1);
|
|
}
|
|
});
|
|
|
|
let info_label = Label::builder()
|
|
.label("...Processing")
|
|
.margin_bottom(12)
|
|
.build();
|
|
|
|
let button = Button::builder().label("Next").sensitive(false).build();
|
|
|
|
main_box.append(&info_label);
|
|
main_box.append(&password_grid);
|
|
main_box.append(&button);
|
|
|
|
let headerbar = HeaderBar::new();
|
|
let toolbar_view = ToolbarView::new();
|
|
toolbar_view.add_top_bar(&headerbar);
|
|
|
|
let c = Clamp::builder()
|
|
.child(&main_box)
|
|
.margin_end(16)
|
|
.margin_start(16)
|
|
.margin_end(16)
|
|
.build();
|
|
toolbar_view.set_content(Some(&c));
|
|
|
|
let window = ApplicationWindow::builder()
|
|
.application(app)
|
|
.title("Log in with DigiD")
|
|
.default_width(350)
|
|
// add content to window
|
|
.content(&toolbar_view)
|
|
.build();
|
|
|
|
password_field.connect_activate(clone!(
|
|
#[weak]
|
|
button,
|
|
move |_| {
|
|
button.emit_clicked();
|
|
}
|
|
));
|
|
|
|
button.connect_clicked(clone!(
|
|
#[weak]
|
|
password_field,
|
|
move |btn| {
|
|
btn.set_sensitive(false);
|
|
let pass = password_field.text().to_string();
|
|
gtc_pipe.send_blocking(pipe::GUIToCard::PIN(pass)).unwrap();
|
|
}
|
|
));
|
|
|
|
gdk::glib::spawn_future_local(clone!(
|
|
#[weak]
|
|
info_label,
|
|
#[weak]
|
|
button,
|
|
#[weak]
|
|
window,
|
|
#[weak]
|
|
app,
|
|
#[weak]
|
|
password_field,
|
|
async move {
|
|
while let Ok(msg) = ctg_pipe.recv().await {
|
|
match msg {
|
|
pipe::CardToGUI::AuthenticationTarget { target } => {
|
|
info_label.set_text(&format!("Enter your PIN to log in to {}", target));
|
|
}
|
|
|
|
pipe::CardToGUI::WaitForCard => {
|
|
button.set_sensitive(false);
|
|
button.set_label("Place your card on the reader.");
|
|
}
|
|
pipe::CardToGUI::ReadyForPIN { message } => {
|
|
let no_special = message.is_none();
|
|
button.set_label(&message.unwrap_or_else(|| String::from("Next")));
|
|
button.set_sensitive(true);
|
|
|
|
if no_special && password_field.text().len() == 5 {
|
|
button.emit_clicked();
|
|
}
|
|
}
|
|
pipe::CardToGUI::ProcessingStep { step: _ } => {}
|
|
pipe::CardToGUI::ProcessingMessage { message } => {
|
|
button.set_label(&message);
|
|
}
|
|
|
|
pipe::CardToGUI::Done => {
|
|
window.close();
|
|
app.quit();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
));
|
|
|
|
window.connect_has_focus_notify(move |f| {
|
|
if f.has_focus() {
|
|
password_field.grab_focus();
|
|
}
|
|
});
|
|
|
|
window.present();
|
|
}
|
|
|
|
pub fn run_gui(
|
|
ctg_pipe_r: async_channel::Receiver<crate::pipe::CardToGUI>,
|
|
gtc_pipe_s: async_channel::Sender<crate::pipe::GUIToCard>,
|
|
) {
|
|
let application = Application::builder()
|
|
.application_id("moe.puck.XeniD")
|
|
.build();
|
|
|
|
let ctg_pipe_r = RefCell::new(Some(ctg_pipe_r));
|
|
let gtc_pipe_s = RefCell::new(Some(gtc_pipe_s));
|
|
|
|
application.connect_activate(move |app| {
|
|
let provider = CssProvider::new();
|
|
provider
|
|
.load_from_string(".cell { margin: 6px; padding: 18px; } .invisible { opacity: 0; }");
|
|
|
|
gtk::style_context_add_provider_for_display(
|
|
&gdk::Display::default().expect("Could not connect to a display."),
|
|
&provider,
|
|
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
|
|
);
|
|
|
|
build_ui(app, ctg_pipe_r.take().unwrap(), gtc_pipe_s.take().unwrap());
|
|
});
|
|
|
|
application.run_with_args::<glib::GString>(&[]);
|
|
}
|