mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-04-06 05:51:28 +03:00
impl fingerprint ui logic
This commit is contained in:
@@ -274,6 +274,12 @@ impl Cli {
|
|||||||
FrontendEvent::EmulationStatus(s) => {
|
FrontendEvent::EmulationStatus(s) => {
|
||||||
eprintln!("emulation status: {s:?}")
|
eprintln!("emulation status: {s:?}")
|
||||||
}
|
}
|
||||||
|
FrontendEvent::AuthorizedUpdated(keys) => {
|
||||||
|
eprintln!("authorized keys changed:");
|
||||||
|
for key in keys {
|
||||||
|
eprintln!("{key}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,8 @@
|
|||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<property name="halign">center</property>
|
<property name="halign">center</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkButton">
|
<object class="GtkButton" id="confirm_button">
|
||||||
|
<signal name="clicked" handler="handle_confirm" swapped="true"/>
|
||||||
<property name="label" translatable="yes">Confirm</property>
|
<property name="label" translatable="yes">Confirm</property>
|
||||||
<property name="can-shrink">True</property>
|
<property name="can-shrink">True</property>
|
||||||
<style>
|
<style>
|
||||||
|
|||||||
17
lan-mouse-gtk/resources/key_row.ui
Normal file
17
lan-mouse-gtk/resources/key_row.ui
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template class="KeyRow" parent="AdwActionRow">
|
||||||
|
<property name="title">hostname</property>
|
||||||
|
<child type="prefix">
|
||||||
|
<object class="GtkButton" id="delete_button">
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="halign">end</property>
|
||||||
|
<property name="tooltip-text" translatable="yes">enable</property>
|
||||||
|
<property name="icon-name">edit-delete-symbolic</property>
|
||||||
|
<style>
|
||||||
|
<class name="flat"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
</interface>
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
<file compressed="true" preprocess="xml-stripblanks">window.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks">window.ui</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">fingerprint_window.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks">fingerprint_window.ui</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">client_row.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks">client_row.ui</file>
|
||||||
|
<file compressed="true" preprocess="xml-stripblanks">key_row.ui</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
<gresource prefix="/de/feschber/LanMouse/icons">
|
<gresource prefix="/de/feschber/LanMouse/icons">
|
||||||
<file compressed="true" preprocess="xml-stripblanks">de.feschber.LanMouse.svg</file>
|
<file compressed="true" preprocess="xml-stripblanks">de.feschber.LanMouse.svg</file>
|
||||||
|
|||||||
@@ -240,7 +240,7 @@
|
|||||||
<signal name="clicked" handler="handle_add_cert_fingerprint" swapped="true"/>
|
<signal name="clicked" handler="handle_add_cert_fingerprint" swapped="true"/>
|
||||||
<property name="child">
|
<property name="child">
|
||||||
<object class="AdwButtonContent">
|
<object class="AdwButtonContent">
|
||||||
<property name="icon-name">list-add-symbolic</property>
|
<property name="icon-name">auth-fingerprint-symbolic</property>
|
||||||
<property name="label" translatable="yes">Add</property>
|
<property name="label" translatable="yes">Add</property>
|
||||||
</object>
|
</object>
|
||||||
</property>
|
</property>
|
||||||
@@ -250,10 +250,10 @@
|
|||||||
</object>
|
</object>
|
||||||
</property>
|
</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkListBox" id="fingerprint_list">
|
<object class="GtkListBox" id="authorized_list">
|
||||||
<property name="selection-mode">none</property>
|
<property name="selection-mode">none</property>
|
||||||
<child type="placeholder">
|
<child type="placeholder">
|
||||||
<object class="AdwActionRow">
|
<object class="AdwActionRow" id="authorized_placeholder">
|
||||||
<property name="title">no fingerprints!</property>
|
<property name="title">no fingerprints!</property>
|
||||||
<property name="subtitle">add a public key fingerprint via the + button</property>
|
<property name="subtitle">add a public key fingerprint via the + button</property>
|
||||||
</object>
|
</object>
|
||||||
|
|||||||
@@ -1,13 +1,7 @@
|
|||||||
mod imp;
|
mod imp;
|
||||||
|
|
||||||
use adw::prelude::*;
|
use glib::Object;
|
||||||
use adw::subclass::prelude::*;
|
use gtk::{gio, glib};
|
||||||
use glib::{clone, Object};
|
|
||||||
use gtk::{
|
|
||||||
gio,
|
|
||||||
glib::{self, closure_local},
|
|
||||||
ListBox, NoSelection,
|
|
||||||
};
|
|
||||||
|
|
||||||
glib::wrapper! {
|
glib::wrapper! {
|
||||||
pub struct FingerprintWindow(ObjectSubclass<imp::FingerprintWindow>)
|
pub struct FingerprintWindow(ObjectSubclass<imp::FingerprintWindow>)
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
use adw::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use glib::subclass::InitializingObject;
|
use glib::subclass::InitializingObject;
|
||||||
use gtk::{glib, template_callbacks, CompositeTemplate, Entry};
|
use gtk::{
|
||||||
|
glib::{self, subclass::Signal},
|
||||||
|
template_callbacks, Button, CompositeTemplate, Text,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(CompositeTemplate, Default)]
|
#[derive(CompositeTemplate, Default)]
|
||||||
#[template(resource = "/de/feschber/LanMouse/fingerprint_window.ui")]
|
#[template(resource = "/de/feschber/LanMouse/fingerprint_window.ui")]
|
||||||
pub struct FingerprintWindow {
|
pub struct FingerprintWindow {
|
||||||
// #[template_child]
|
#[template_child]
|
||||||
// pub fingerprint_entry: TemplateChild<Entry>,
|
pub text: TemplateChild<Text>,
|
||||||
|
#[template_child]
|
||||||
|
pub confirm_button: TemplateChild<Button>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
@@ -29,13 +37,21 @@ impl ObjectSubclass for FingerprintWindow {
|
|||||||
|
|
||||||
#[template_callbacks]
|
#[template_callbacks]
|
||||||
impl FingerprintWindow {
|
impl FingerprintWindow {
|
||||||
// #[template_callback]
|
#[template_callback]
|
||||||
// fn handle_confirm() {}
|
fn handle_confirm(&self, _button: Button) {
|
||||||
|
let fp = self.text.text().to_string();
|
||||||
|
self.obj().emit_by_name("confirm-clicked", &[&fp])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectImpl for FingerprintWindow {
|
impl ObjectImpl for FingerprintWindow {
|
||||||
fn constructed(&self) {
|
fn signals() -> &'static [Signal] {
|
||||||
self.parent_constructed();
|
static SIGNALS: OnceLock<Vec<Signal>> = OnceLock::new();
|
||||||
|
SIGNALS.get_or_init(|| {
|
||||||
|
vec![Signal::builder("confirm-clicked")
|
||||||
|
.param_types([String::static_type()])
|
||||||
|
.build()]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
18
lan-mouse-gtk/src/key_object.rs
Normal file
18
lan-mouse-gtk/src/key_object.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
mod imp;
|
||||||
|
|
||||||
|
use adw::subclass::prelude::*;
|
||||||
|
use gtk::glib::{self, Object};
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct KeyObject(ObjectSubclass<imp::KeyObject>);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyObject {
|
||||||
|
pub fn new(fp: String) -> Self {
|
||||||
|
Object::builder().property("fingerprint", fp).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_fingerprint(&self) -> String {
|
||||||
|
self.imp().fingerprint.borrow().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
22
lan-mouse-gtk/src/key_object/imp.rs
Normal file
22
lan-mouse-gtk/src/key_object/imp.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use glib::Properties;
|
||||||
|
use gtk::glib;
|
||||||
|
use gtk::prelude::*;
|
||||||
|
use gtk::subclass::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Properties, Default)]
|
||||||
|
#[properties(wrapper_type = super::KeyObject)]
|
||||||
|
pub struct KeyObject {
|
||||||
|
#[property(name = "fingerprint", get, set, type = String)]
|
||||||
|
pub fingerprint: RefCell<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for KeyObject {
|
||||||
|
const NAME: &'static str = "KeyObject";
|
||||||
|
type Type = super::KeyObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::derived_properties]
|
||||||
|
impl ObjectImpl for KeyObject {}
|
||||||
36
lan-mouse-gtk/src/key_row.rs
Normal file
36
lan-mouse-gtk/src/key_row.rs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
mod imp;
|
||||||
|
|
||||||
|
use adw::prelude::*;
|
||||||
|
use adw::subclass::prelude::*;
|
||||||
|
use gtk::glib::{self, Object};
|
||||||
|
|
||||||
|
use super::KeyObject;
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct KeyRow(ObjectSubclass<imp::KeyRow>)
|
||||||
|
@extends gtk::ListBoxRow, gtk::Widget, adw::PreferencesRow, adw::ExpanderRow,
|
||||||
|
@implements gtk::Accessible, gtk::Actionable, gtk::Buildable, gtk::ConstraintTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyRow {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Object::builder().build()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind(&self, key_object: &KeyObject) {
|
||||||
|
let mut bindings = self.imp().bindings.borrow_mut();
|
||||||
|
|
||||||
|
let title_binding = key_object
|
||||||
|
.bind_property("fingerprint", self, "title")
|
||||||
|
.sync_create()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
bindings.push(title_binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unbind(&self) {
|
||||||
|
for binding in self.imp().bindings.borrow_mut().drain(..) {
|
||||||
|
binding.unbind();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
lan-mouse-gtk/src/key_row/imp.rs
Normal file
68
lan-mouse-gtk/src/key_row/imp.rs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
use adw::subclass::prelude::*;
|
||||||
|
use adw::{prelude::*, ActionRow};
|
||||||
|
use glib::{subclass::InitializingObject, Binding};
|
||||||
|
use gtk::glib::clone;
|
||||||
|
use gtk::glib::subclass::Signal;
|
||||||
|
use gtk::{glib, Button, CompositeTemplate};
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
#[derive(CompositeTemplate, Default)]
|
||||||
|
#[template(resource = "/de/feschber/LanMouse/key_row.ui")]
|
||||||
|
pub struct KeyRow {
|
||||||
|
#[template_child]
|
||||||
|
pub delete_button: TemplateChild<gtk::Button>,
|
||||||
|
pub bindings: RefCell<Vec<Binding>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for KeyRow {
|
||||||
|
// `NAME` needs to match `class` attribute of template
|
||||||
|
const NAME: &'static str = "KeyRow";
|
||||||
|
const ABSTRACT: bool = false;
|
||||||
|
|
||||||
|
type Type = super::KeyRow;
|
||||||
|
type ParentType = ActionRow;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.bind_template();
|
||||||
|
klass.bind_template_callbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instance_init(obj: &InitializingObject<Self>) {
|
||||||
|
obj.init_template();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for KeyRow {
|
||||||
|
fn constructed(&self) {
|
||||||
|
self.parent_constructed();
|
||||||
|
self.delete_button.connect_clicked(clone!(
|
||||||
|
#[weak(rename_to = row)]
|
||||||
|
self,
|
||||||
|
move |button| {
|
||||||
|
row.handle_delete(button);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signals() -> &'static [glib::subclass::Signal] {
|
||||||
|
static SIGNALS: OnceLock<Vec<Signal>> = OnceLock::new();
|
||||||
|
SIGNALS.get_or_init(|| vec![Signal::builder("request-delete").build()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gtk::template_callbacks]
|
||||||
|
impl KeyRow {
|
||||||
|
#[template_callback]
|
||||||
|
fn handle_delete(&self, _button: &Button) {
|
||||||
|
self.obj().emit_by_name::<()>("request-delete", &[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetImpl for KeyRow {}
|
||||||
|
impl BoxImpl for KeyRow {}
|
||||||
|
impl ListBoxRowImpl for KeyRow {}
|
||||||
|
impl PreferencesRowImpl for KeyRow {}
|
||||||
|
impl ActionRowImpl for KeyRow {}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
mod client_object;
|
mod client_object;
|
||||||
mod client_row;
|
mod client_row;
|
||||||
mod fingerprint_window;
|
mod fingerprint_window;
|
||||||
|
mod key_object;
|
||||||
|
mod key_row;
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
use std::{env, process, str};
|
use std::{env, process, str};
|
||||||
@@ -16,6 +18,7 @@ use gtk::{
|
|||||||
use gtk::{gio, glib, prelude::ApplicationExt};
|
use gtk::{gio, glib, prelude::ApplicationExt};
|
||||||
|
|
||||||
use self::client_object::ClientObject;
|
use self::client_object::ClientObject;
|
||||||
|
use self::key_object::KeyObject;
|
||||||
|
|
||||||
pub fn run() -> glib::ExitCode {
|
pub fn run() -> glib::ExitCode {
|
||||||
log::debug!("running gtk frontend");
|
log::debug!("running gtk frontend");
|
||||||
@@ -133,6 +136,9 @@ fn build_ui(app: &Application) {
|
|||||||
FrontendEvent::EmulationStatus(s) => {
|
FrontendEvent::EmulationStatus(s) => {
|
||||||
window.set_emulation(s.into());
|
window.set_emulation(s.into());
|
||||||
}
|
}
|
||||||
|
FrontendEvent::AuthorizedUpdated(keys) => {
|
||||||
|
window.set_authorized_keys(keys);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
mod imp;
|
mod imp;
|
||||||
|
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use adw::subclass::prelude::*;
|
use adw::subclass::prelude::*;
|
||||||
use glib::{clone, Object};
|
use glib::{clone, Object};
|
||||||
use gtk::{
|
use gtk::{
|
||||||
gio,
|
gio,
|
||||||
glib::{self, closure_local},
|
glib::{self, closure_local},
|
||||||
ListBox, NoSelection, Widget,
|
ListBox, NoSelection,
|
||||||
};
|
};
|
||||||
|
|
||||||
use lan_mouse_ipc::{
|
use lan_mouse_ipc::{
|
||||||
@@ -14,7 +16,7 @@ use lan_mouse_ipc::{
|
|||||||
DEFAULT_PORT,
|
DEFAULT_PORT,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::fingerprint_window::FingerprintWindow;
|
use crate::{fingerprint_window::FingerprintWindow, key_object::KeyObject, key_row::KeyRow};
|
||||||
|
|
||||||
use super::{client_object::ClientObject, client_row::ClientRow};
|
use super::{client_object::ClientObject, client_row::ClientRow};
|
||||||
|
|
||||||
@@ -44,10 +46,55 @@ impl Window {
|
|||||||
.expect("Could not get clients")
|
.expect("Could not get clients")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn authorized(&self) -> gio::ListStore {
|
||||||
|
self.imp()
|
||||||
|
.authorized
|
||||||
|
.borrow()
|
||||||
|
.clone()
|
||||||
|
.expect("Could not get authorized")
|
||||||
|
}
|
||||||
|
|
||||||
fn client_by_idx(&self, idx: u32) -> Option<ClientObject> {
|
fn client_by_idx(&self, idx: u32) -> Option<ClientObject> {
|
||||||
self.clients().item(idx).map(|o| o.downcast().unwrap())
|
self.clients().item(idx).map(|o| o.downcast().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn authorized_by_idx(&self, idx: u32) -> Option<KeyObject> {
|
||||||
|
self.authorized().item(idx).map(|o| o.downcast().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_authorized(&self) {
|
||||||
|
let store = gio::ListStore::new::<KeyObject>();
|
||||||
|
self.imp().authorized.replace(Some(store));
|
||||||
|
let selection_model = NoSelection::new(Some(self.authorized()));
|
||||||
|
self.imp().authorized_list.bind_model(
|
||||||
|
Some(&selection_model),
|
||||||
|
clone!(
|
||||||
|
#[weak(rename_to = window)]
|
||||||
|
self,
|
||||||
|
#[upgrade_or_panic]
|
||||||
|
move |obj| {
|
||||||
|
let key_obj = obj.downcast_ref().expect("object of type `KeyObject`");
|
||||||
|
let row = window.create_key_row(key_obj);
|
||||||
|
row.connect_closure(
|
||||||
|
"request-delete",
|
||||||
|
false,
|
||||||
|
closure_local!(
|
||||||
|
#[strong]
|
||||||
|
window,
|
||||||
|
move |row: KeyRow| {
|
||||||
|
if let Some(key_obj) = window.authorized_by_idx(row.index() as u32)
|
||||||
|
{
|
||||||
|
window.request_fingerprint_remove(key_obj.get_fingerprint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
|
row.upcast()
|
||||||
|
}
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn setup_clients(&self) {
|
fn setup_clients(&self) {
|
||||||
let model = gio::ListStore::new::<ClientObject>();
|
let model = gio::ListStore::new::<ClientObject>();
|
||||||
self.imp().clients.replace(Some(model));
|
self.imp().clients.replace(Some(model));
|
||||||
@@ -116,7 +163,8 @@ impl Window {
|
|||||||
/// workaround for a bug in libadwaita that shows an ugly line beneath
|
/// workaround for a bug in libadwaita that shows an ugly line beneath
|
||||||
/// the last element if a placeholder is set.
|
/// the last element if a placeholder is set.
|
||||||
/// https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/6308
|
/// https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/6308
|
||||||
pub fn set_placeholder_visible(&self, visible: bool) {
|
pub fn update_placeholder_visibility(&self) {
|
||||||
|
let visible = self.clients().n_items() == 0;
|
||||||
let placeholder = self.imp().client_placeholder.get();
|
let placeholder = self.imp().client_placeholder.get();
|
||||||
self.imp().client_list.set_placeholder(match visible {
|
self.imp().client_list.set_placeholder(match visible {
|
||||||
true => Some(&placeholder),
|
true => Some(&placeholder),
|
||||||
@@ -124,6 +172,15 @@ impl Window {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_auth_placeholder_visibility(&self) {
|
||||||
|
let visible = self.authorized().n_items() == 0;
|
||||||
|
let placeholder = self.imp().authorized_placeholder.get();
|
||||||
|
self.imp().authorized_list.set_placeholder(match visible {
|
||||||
|
true => Some(&placeholder),
|
||||||
|
false => None,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn setup_icon(&self) {
|
fn setup_icon(&self) {
|
||||||
self.set_icon_name(Some("de.feschber.LanMouse"));
|
self.set_icon_name(Some("de.feschber.LanMouse"));
|
||||||
}
|
}
|
||||||
@@ -134,10 +191,16 @@ impl Window {
|
|||||||
row
|
row
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_key_row(&self, key_object: &KeyObject) -> KeyRow {
|
||||||
|
let row = KeyRow::new();
|
||||||
|
row.bind(key_object);
|
||||||
|
row
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new_client(&self, handle: ClientHandle, client: ClientConfig, state: ClientState) {
|
pub fn new_client(&self, handle: ClientHandle, client: ClientConfig, state: ClientState) {
|
||||||
let client = ClientObject::new(handle, client, state.clone());
|
let client = ClientObject::new(handle, client, state.clone());
|
||||||
self.clients().append(&client);
|
self.clients().append(&client);
|
||||||
self.set_placeholder_visible(false);
|
self.update_placeholder_visibility();
|
||||||
self.update_dns_state(handle, !state.ips.is_empty());
|
self.update_dns_state(handle, !state.ips.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +222,7 @@ impl Window {
|
|||||||
|
|
||||||
self.clients().remove(idx as u32);
|
self.clients().remove(idx as u32);
|
||||||
if self.clients().n_items() == 0 {
|
if self.clients().n_items() == 0 {
|
||||||
self.set_placeholder_visible(true);
|
self.update_placeholder_visibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,6 +354,18 @@ impl Window {
|
|||||||
pub fn open_fingerprint_dialog(&self) {
|
pub fn open_fingerprint_dialog(&self) {
|
||||||
let window = FingerprintWindow::new();
|
let window = FingerprintWindow::new();
|
||||||
window.set_transient_for(Some(self));
|
window.set_transient_for(Some(self));
|
||||||
|
window.connect_closure(
|
||||||
|
"confirm-clicked",
|
||||||
|
false,
|
||||||
|
closure_local!(
|
||||||
|
#[strong(rename_to = parent)]
|
||||||
|
self,
|
||||||
|
move |w: FingerprintWindow, fp: String| {
|
||||||
|
parent.request_fingerprint_add(fp);
|
||||||
|
w.close();
|
||||||
|
}
|
||||||
|
),
|
||||||
|
);
|
||||||
window.present();
|
window.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,6 +373,10 @@ impl Window {
|
|||||||
self.request(FrontendRequest::FingerprintAdd(fp));
|
self.request(FrontendRequest::FingerprintAdd(fp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn request_fingerprint_remove(&self, fp: String) {
|
||||||
|
self.request(FrontendRequest::FingerprintRemove(fp));
|
||||||
|
}
|
||||||
|
|
||||||
pub fn request(&self, request: FrontendRequest) {
|
pub fn request(&self, request: FrontendRequest) {
|
||||||
let mut requester = self.imp().frontend_request_writer.borrow_mut();
|
let mut requester = self.imp().frontend_request_writer.borrow_mut();
|
||||||
let requester = requester.as_mut().unwrap();
|
let requester = requester.as_mut().unwrap();
|
||||||
@@ -331,4 +410,16 @@ impl Window {
|
|||||||
.capture_emulation_group
|
.capture_emulation_group
|
||||||
.set_visible(!capture || !emulation);
|
.set_visible(!capture || !emulation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_authorized_keys(&self, fingerprints: HashSet<String>) {
|
||||||
|
let authorized = self.authorized();
|
||||||
|
// clear list
|
||||||
|
authorized.remove_all();
|
||||||
|
// insert fingerprints
|
||||||
|
for fingerprint in fingerprints {
|
||||||
|
let key_obj = KeyObject::new(fingerprint);
|
||||||
|
authorized.append(&key_obj);
|
||||||
|
}
|
||||||
|
self.update_auth_placeholder_visibility();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ use lan_mouse_ipc::{FrontendRequestWriter, DEFAULT_PORT};
|
|||||||
#[derive(CompositeTemplate, Default)]
|
#[derive(CompositeTemplate, Default)]
|
||||||
#[template(resource = "/de/feschber/LanMouse/window.ui")]
|
#[template(resource = "/de/feschber/LanMouse/window.ui")]
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
#[template_child]
|
||||||
|
pub authorized_placeholder: TemplateChild<ActionRow>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub port_edit_apply: TemplateChild<Button>,
|
pub port_edit_apply: TemplateChild<Button>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
@@ -35,7 +37,10 @@ pub struct Window {
|
|||||||
pub input_emulation_button: TemplateChild<Button>,
|
pub input_emulation_button: TemplateChild<Button>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub input_capture_button: TemplateChild<Button>,
|
pub input_capture_button: TemplateChild<Button>,
|
||||||
|
#[template_child]
|
||||||
|
pub authorized_list: TemplateChild<ListBox>,
|
||||||
pub clients: RefCell<Option<gio::ListStore>>,
|
pub clients: RefCell<Option<gio::ListStore>>,
|
||||||
|
pub authorized: RefCell<Option<gio::ListStore>>,
|
||||||
pub frontend_request_writer: RefCell<Option<FrontendRequestWriter>>,
|
pub frontend_request_writer: RefCell<Option<FrontendRequestWriter>>,
|
||||||
pub port: Cell<u16>,
|
pub port: Cell<u16>,
|
||||||
pub capture_active: Cell<bool>,
|
pub capture_active: Cell<bool>,
|
||||||
@@ -146,6 +151,7 @@ impl ObjectImpl for Window {
|
|||||||
let obj = self.obj();
|
let obj = self.obj();
|
||||||
obj.setup_icon();
|
obj.setup_icon();
|
||||||
obj.setup_clients();
|
obj.setup_clients();
|
||||||
|
obj.setup_authorized();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -197,6 +197,7 @@ pub enum FrontendEvent {
|
|||||||
CaptureStatus(Status),
|
CaptureStatus(Status),
|
||||||
/// emulation status
|
/// emulation status
|
||||||
EmulationStatus(Status),
|
EmulationStatus(Status),
|
||||||
|
AuthorizedUpdated(HashSet<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
|
||||||
|
|||||||
@@ -270,10 +270,16 @@ impl Server {
|
|||||||
|
|
||||||
fn add_authorized_key(&self, key: String) {
|
fn add_authorized_key(&self, key: String) {
|
||||||
self.authorized_keys.borrow_mut().insert(key);
|
self.authorized_keys.borrow_mut().insert(key);
|
||||||
|
self.notify_frontend(FrontendEvent::AuthorizedUpdated(
|
||||||
|
self.authorized_keys.borrow().clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_authorized_key(&self, key: String) {
|
fn remove_authorized_key(&self, key: String) {
|
||||||
self.authorized_keys.borrow_mut().remove(&key);
|
self.authorized_keys.borrow_mut().remove(&key);
|
||||||
|
self.notify_frontend(FrontendEvent::AuthorizedUpdated(
|
||||||
|
self.authorized_keys.borrow().clone(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enumerate(&self) {
|
fn enumerate(&self) {
|
||||||
|
|||||||
Reference in New Issue
Block a user