mirror of
https://gitlab.gnome.org/World/Authenticator.git
synced 2025-03-04 08:44:40 +01:00
add a UrlRow widget & use it
just a wrapper around ActionRow that opens the uri when activated
This commit is contained in:
parent
e927a7bb6b
commit
6be97a815f
7 changed files with 150 additions and 57 deletions
|
@ -138,32 +138,6 @@
|
||||||
<object class="GtkListBox" id="more_list">
|
<object class="GtkListBox" id="more_list">
|
||||||
<property name="visible">False</property>
|
<property name="visible">False</property>
|
||||||
<property name="selection_mode">none</property>
|
<property name="selection_mode">none</property>
|
||||||
<child>
|
|
||||||
<object class="HdyActionRow" id="provider_website_row">
|
|
||||||
<property name="title" translatable="yes">Website</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage">
|
|
||||||
<property name="halign">end</property>
|
|
||||||
<property name="valign">center</property>
|
|
||||||
<property name="hexpand">True</property>
|
|
||||||
<property name="icon-name">link-symbolic</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
|
||||||
<object class="HdyActionRow" id="provider_help_row">
|
|
||||||
<property name="title" translatable="yes">How to setup</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage">
|
|
||||||
<property name="halign">end</property>
|
|
||||||
<property name="valign">center</property>
|
|
||||||
<property name="hexpand">True</property>
|
|
||||||
<property name="icon-name">help-page-symbolic</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="HdyActionRow" id="algorithm_row">
|
<object class="HdyActionRow" id="algorithm_row">
|
||||||
<property name="title" translatable="yes">Algorithm</property>
|
<property name="title" translatable="yes">Algorithm</property>
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
<property name="margin-start">8</property>
|
<property name="margin-start">8</property>
|
||||||
<property name="margin-end">8</property>
|
<property name="margin-end">8</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkListBox">
|
<object class="GtkListBox" id="list">
|
||||||
<property name="selection_mode">none</property>
|
<property name="selection_mode">none</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="HdyActionRow">
|
<object class="HdyActionRow">
|
||||||
|
@ -55,19 +55,6 @@
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<object class="HdyActionRow" id="provider_website_row">
|
|
||||||
<property name="title" translatable="yes">Website</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkImage">
|
|
||||||
<property name="halign">end</property>
|
|
||||||
<property name="valign">center</property>
|
|
||||||
<property name="hexpand">True</property>
|
|
||||||
<property name="icon-name">link-symbolic</property>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
<style>
|
<style>
|
||||||
<class name="content"/>
|
<class name="content"/>
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -73,6 +73,7 @@ sources = files(
|
||||||
'widgets/providers/page.rs',
|
'widgets/providers/page.rs',
|
||||||
'widgets/providers/row.rs',
|
'widgets/providers/row.rs',
|
||||||
'widgets/mod.rs',
|
'widgets/mod.rs',
|
||||||
|
'widgets/url_row.rs',
|
||||||
'widgets/window.rs',
|
'widgets/window.rs',
|
||||||
'application.rs',
|
'application.rs',
|
||||||
'config.rs',
|
'config.rs',
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::helpers::qrcode;
|
use crate::helpers::qrcode;
|
||||||
use crate::models::{Account, OTPMethod, OTPUri, Provider, ProvidersModel};
|
use crate::models::{Account, OTPMethod, OTPUri, Provider, ProvidersModel};
|
||||||
use crate::widgets::{ProviderImage, ProviderImageSize};
|
use crate::widgets::{ProviderImage, ProviderImageSize, UrlRow};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use gio::prelude::*;
|
use gio::prelude::*;
|
||||||
use gio::{subclass::ObjectSubclass, ActionMapExt};
|
use gio::{subclass::ObjectSubclass, ActionMapExt};
|
||||||
|
@ -9,7 +9,6 @@ use glib::subclass::prelude::*;
|
||||||
use glib::{clone, glib_object_subclass, glib_wrapper};
|
use glib::{clone, glib_object_subclass, glib_wrapper};
|
||||||
use gtk::{prelude::*, CompositeTemplate};
|
use gtk::{prelude::*, CompositeTemplate};
|
||||||
use gtk_macros::{action, get_action};
|
use gtk_macros::{action, get_action};
|
||||||
use libhandy::ActionRowExt;
|
|
||||||
use once_cell::sync::OnceCell;
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
|
@ -24,6 +23,8 @@ mod imp {
|
||||||
pub selected_provider: RefCell<Option<Provider>>,
|
pub selected_provider: RefCell<Option<Provider>>,
|
||||||
pub actions: gio::SimpleActionGroup,
|
pub actions: gio::SimpleActionGroup,
|
||||||
pub image: ProviderImage,
|
pub image: ProviderImage,
|
||||||
|
pub provider_website_row: UrlRow,
|
||||||
|
pub provider_help_row: UrlRow,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub main_container: TemplateChild<gtk::Box>,
|
pub main_container: TemplateChild<gtk::Box>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
|
@ -41,10 +42,6 @@ mod imp {
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub method_label: TemplateChild<gtk::Label>,
|
pub method_label: TemplateChild<gtk::Label>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub provider_website_row: TemplateChild<libhandy::ActionRow>,
|
|
||||||
#[template_child]
|
|
||||||
pub provider_help_row: TemplateChild<libhandy::ActionRow>,
|
|
||||||
#[template_child]
|
|
||||||
pub algorithm_label: TemplateChild<gtk::Label>,
|
pub algorithm_label: TemplateChild<gtk::Label>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub counter_row: TemplateChild<libhandy::ActionRow>,
|
pub counter_row: TemplateChild<libhandy::ActionRow>,
|
||||||
|
@ -65,10 +62,14 @@ mod imp {
|
||||||
|
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
let actions = gio::SimpleActionGroup::new();
|
let actions = gio::SimpleActionGroup::new();
|
||||||
|
let provider_website_row = UrlRow::new("Website", "link-symbolic");
|
||||||
|
let provider_help_row = UrlRow::new("How to setup", "help-page-symbolic");
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
actions,
|
actions,
|
||||||
image: ProviderImage::new(ProviderImageSize::Large),
|
image: ProviderImage::new(ProviderImageSize::Large),
|
||||||
|
provider_website_row,
|
||||||
|
provider_help_row,
|
||||||
model: OnceCell::new(),
|
model: OnceCell::new(),
|
||||||
selected_provider: RefCell::new(None),
|
selected_provider: RefCell::new(None),
|
||||||
main_container: TemplateChild::default(),
|
main_container: TemplateChild::default(),
|
||||||
|
@ -79,8 +80,6 @@ mod imp {
|
||||||
digits_label: TemplateChild::default(),
|
digits_label: TemplateChild::default(),
|
||||||
provider_entry: TemplateChild::default(),
|
provider_entry: TemplateChild::default(),
|
||||||
method_label: TemplateChild::default(),
|
method_label: TemplateChild::default(),
|
||||||
provider_website_row: TemplateChild::default(),
|
|
||||||
provider_help_row: TemplateChild::default(),
|
|
||||||
provider_completion: TemplateChild::default(),
|
provider_completion: TemplateChild::default(),
|
||||||
algorithm_label: TemplateChild::default(),
|
algorithm_label: TemplateChild::default(),
|
||||||
counter_row: TemplateChild::default(),
|
counter_row: TemplateChild::default(),
|
||||||
|
@ -246,10 +245,10 @@ impl AccountAddDialog {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ref website) = provider.website() {
|
if let Some(ref website) = provider.website() {
|
||||||
self_.provider_website_row.get().set_subtitle(Some(website));
|
self_.provider_website_row.set_uri(website);
|
||||||
}
|
}
|
||||||
if let Some(ref help_url) = provider.help_url() {
|
if let Some(ref help_url) = provider.help_url() {
|
||||||
self_.provider_help_row.get().set_subtitle(Some(help_url));
|
self_.provider_help_row.set_uri(help_url);
|
||||||
}
|
}
|
||||||
self_.selected_provider.borrow_mut().replace(provider);
|
self_.selected_provider.borrow_mut().replace(provider);
|
||||||
}
|
}
|
||||||
|
@ -291,6 +290,9 @@ impl AccountAddDialog {
|
||||||
.get()
|
.get()
|
||||||
.set_model(Some(&self_.model.get().unwrap().completion_model()));
|
.set_model(Some(&self_.model.get().unwrap().completion_model()));
|
||||||
|
|
||||||
|
self_.more_list.get().prepend(&self_.provider_help_row);
|
||||||
|
self_.more_list.get().prepend(&self_.provider_website_row);
|
||||||
|
|
||||||
self_.main_container.get().prepend(&self_.image);
|
self_.main_container.get().prepend(&self_.image);
|
||||||
|
|
||||||
self_.provider_completion.get().connect_match_selected(
|
self_.provider_completion.get().connect_match_selected(
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use crate::models::Account;
|
use crate::models::Account;
|
||||||
|
use crate::widgets::UrlRow;
|
||||||
use gio::{subclass::ObjectSubclass, FileExt};
|
use gio::{subclass::ObjectSubclass, FileExt};
|
||||||
use glib::subclass::prelude::*;
|
use glib::subclass::prelude::*;
|
||||||
use glib::{glib_object_subclass, glib_wrapper};
|
use glib::{glib_object_subclass, glib_wrapper};
|
||||||
use gtk::{prelude::*, CompositeTemplate};
|
use gtk::{prelude::*, CompositeTemplate};
|
||||||
use libhandy::prelude::*;
|
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -12,14 +12,15 @@ mod imp {
|
||||||
|
|
||||||
#[derive(Debug, CompositeTemplate)]
|
#[derive(Debug, CompositeTemplate)]
|
||||||
pub struct QRCodePage {
|
pub struct QRCodePage {
|
||||||
|
pub website_row: UrlRow,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub image: TemplateChild<gtk::Image>,
|
pub image: TemplateChild<gtk::Image>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub provider_label: TemplateChild<gtk::Label>,
|
pub provider_label: TemplateChild<gtk::Label>,
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub account_label: TemplateChild<gtk::Label>,
|
pub account_label: TemplateChild<gtk::Label>,
|
||||||
#[template_child(id = "provider_website_row")]
|
#[template_child(id = "list")]
|
||||||
pub website_row: TemplateChild<libhandy::ActionRow>,
|
pub listbox: TemplateChild<gtk::ListBox>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectSubclass for QRCodePage {
|
impl ObjectSubclass for QRCodePage {
|
||||||
|
@ -36,7 +37,8 @@ mod imp {
|
||||||
image: TemplateChild::default(),
|
image: TemplateChild::default(),
|
||||||
account_label: TemplateChild::default(),
|
account_label: TemplateChild::default(),
|
||||||
provider_label: TemplateChild::default(),
|
provider_label: TemplateChild::default(),
|
||||||
website_row: TemplateChild::default(),
|
website_row: UrlRow::new("Website", "link-symbolic"),
|
||||||
|
listbox: TemplateChild::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +53,7 @@ mod imp {
|
||||||
impl ObjectImpl for QRCodePage {
|
impl ObjectImpl for QRCodePage {
|
||||||
fn constructed(&self, obj: &Self::Type) {
|
fn constructed(&self, obj: &Self::Type) {
|
||||||
obj.init_template();
|
obj.init_template();
|
||||||
|
obj.setup_widgets();
|
||||||
self.parent_constructed(obj);
|
self.parent_constructed(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,10 +90,16 @@ impl QRCodePage {
|
||||||
.set_text(&account.provider().name());
|
.set_text(&account.provider().name());
|
||||||
|
|
||||||
if let Some(ref website) = account.provider().website() {
|
if let Some(ref website) = account.provider().website() {
|
||||||
self_.website_row.get().set_subtitle(Some(website));
|
self_.website_row.set_uri(website);
|
||||||
self_.website_row.get().show();
|
self_.website_row.show();
|
||||||
} else {
|
} else {
|
||||||
self_.website_row.get().hide();
|
self_.website_row.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setup_widgets(&self) {
|
||||||
|
let self_ = imp::QRCodePage::from_instance(self);
|
||||||
|
|
||||||
|
self_.listbox.get().append(&self_.website_row);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
mod accounts;
|
mod accounts;
|
||||||
mod preferences;
|
mod preferences;
|
||||||
mod providers;
|
mod providers;
|
||||||
|
mod url_row;
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
pub use self::accounts::AccountAddDialog;
|
pub use self::accounts::AccountAddDialog;
|
||||||
pub use self::preferences::PreferencesWindow;
|
pub use self::preferences::PreferencesWindow;
|
||||||
pub use self::providers::{ProviderImage, ProviderImageSize, ProvidersDialog, ProvidersList};
|
pub use self::providers::{ProviderImage, ProviderImageSize, ProvidersDialog, ProvidersList};
|
||||||
|
pub use self::url_row::UrlRow;
|
||||||
pub use self::window::{View, Window};
|
pub use self::window::{View, Window};
|
||||||
|
|
118
src/widgets/url_row.rs
Normal file
118
src/widgets/url_row.rs
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
use gio::subclass::ObjectSubclass;
|
||||||
|
use glib::{clone, glib_wrapper, Cast, ObjectExt, StaticType, ToValue};
|
||||||
|
use gtk::WidgetExt;
|
||||||
|
use libhandy::ActionRowExt;
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
use glib::{glib_object_subclass, subclass};
|
||||||
|
use gtk::subclass::prelude::*;
|
||||||
|
use libhandy::subclass::action_row::ActionRowImpl;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
static PROPERTIES: [subclass::Property; 1] = [subclass::Property("uri", |name| {
|
||||||
|
glib::ParamSpec::string(
|
||||||
|
name,
|
||||||
|
"uri",
|
||||||
|
"The Row URI",
|
||||||
|
None,
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
})];
|
||||||
|
|
||||||
|
pub struct UrlRow {
|
||||||
|
pub uri: RefCell<Option<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectSubclass for UrlRow {
|
||||||
|
const NAME: &'static str = "UrlRow";
|
||||||
|
type Type = super::UrlRow;
|
||||||
|
type ParentType = libhandy::ActionRow;
|
||||||
|
type Instance = subclass::simple::InstanceStruct<Self>;
|
||||||
|
type Class = subclass::simple::ClassStruct<Self>;
|
||||||
|
|
||||||
|
glib_object_subclass!();
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
uri: RefCell::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.install_properties(&PROPERTIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for UrlRow {
|
||||||
|
fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
|
||||||
|
let prop = &PROPERTIES[id];
|
||||||
|
|
||||||
|
match *prop {
|
||||||
|
subclass::Property("uri", ..) => {
|
||||||
|
let uri = value.get().unwrap();
|
||||||
|
self.uri.replace(uri);
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
|
||||||
|
let prop = &PROPERTIES[id];
|
||||||
|
match *prop {
|
||||||
|
subclass::Property("uri", ..) => self.uri.borrow().to_value(),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constructed(&self, obj: &Self::Type) {
|
||||||
|
self.parent_constructed(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl WidgetImpl for UrlRow {}
|
||||||
|
impl ListBoxRowImpl for UrlRow {}
|
||||||
|
impl ActionRowImpl for UrlRow {}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib_wrapper! {
|
||||||
|
pub struct UrlRow(ObjectSubclass<imp::UrlRow>) @extends gtk::Widget, gtk::ListBoxRow, libhandy::ActionRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UrlRow {
|
||||||
|
#[allow(clippy::new_without_default)]
|
||||||
|
pub fn new(title: &str, icon_name: &str) -> Self {
|
||||||
|
let row = glib::Object::new(Self::static_type(), &[])
|
||||||
|
.expect("Failed to create UrlRow")
|
||||||
|
.downcast::<UrlRow>()
|
||||||
|
.expect("Created object is of wrong type");
|
||||||
|
row.setup_widgets(title, icon_name);
|
||||||
|
row
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_widgets(&self, title: &str, icon_name: &str) {
|
||||||
|
self.set_property("title", &title).unwrap();
|
||||||
|
|
||||||
|
let gesture = gtk::GestureClick::new();
|
||||||
|
gesture.connect_pressed(clone!(@weak self as row => move |_,_,_,_| {
|
||||||
|
row.open_uri();
|
||||||
|
}));
|
||||||
|
|
||||||
|
self.add_controller(&gesture);
|
||||||
|
|
||||||
|
let image = gtk::Image::from_icon_name(Some(icon_name));
|
||||||
|
self.add_suffix(&image);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open_uri(&self) {
|
||||||
|
let self_ = imp::UrlRow::from_instance(self);
|
||||||
|
if let Some(ref uri) = *self_.uri.borrow() {
|
||||||
|
gtk::show_uri(gtk::NONE_WINDOW, uri, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_uri(&self, uri: &str) {
|
||||||
|
self.set_subtitle(Some(uri));
|
||||||
|
let self_ = imp::UrlRow::from_instance(self);
|
||||||
|
self_.uri.borrow_mut().replace(uri.to_string());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue