mirror of
https://gitlab.gnome.org/World/Authenticator.git
synced 2025-03-04 08:44:40 +01:00
providers: move out of preferences
This commit is contained in:
parent
ddddb97c5f
commit
f55900272c
20 changed files with 606 additions and 180 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -282,6 +282,7 @@ dependencies = [
|
||||||
"quick-xml",
|
"quick-xml",
|
||||||
"secret-service",
|
"secret-service",
|
||||||
"surf",
|
"surf",
|
||||||
|
"unicase",
|
||||||
"url",
|
"url",
|
||||||
"zbar-rust",
|
"zbar-rust",
|
||||||
]
|
]
|
||||||
|
|
|
@ -21,6 +21,7 @@ url = "2.1"
|
||||||
zbar-rust = "0.0"
|
zbar-rust = "0.0"
|
||||||
secret-service = "1.1"
|
secret-service = "1.1"
|
||||||
once_cell = "1.5"
|
once_cell = "1.5"
|
||||||
|
unicase = "2.6"
|
||||||
|
|
||||||
[dependencies.gtk]
|
[dependencies.gtk]
|
||||||
git = "https://github.com/gtk-rs/gtk4-rs"
|
git = "https://github.com/gtk-rs/gtk4-rs"
|
||||||
|
|
|
@ -9,7 +9,9 @@
|
||||||
<file compressed="true" preprocess="xml-stripblanks" alias="account_row.ui">resources/ui/account_row.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks" alias="account_row.ui">resources/ui/account_row.ui</file>
|
||||||
|
|
||||||
<!-- Providers -->
|
<!-- Providers -->
|
||||||
|
<file compressed="true" preprocess="xml-stripblanks" alias="provider_page.ui">resources/ui/provider_page.ui</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks" alias="provider_row.ui">resources/ui/provider_row.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks" alias="provider_row.ui">resources/ui/provider_row.ui</file>
|
||||||
|
<file compressed="true" preprocess="xml-stripblanks" alias="providers_all.ui">resources/ui/providers_all.ui</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">providers_list.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks">providers_list.ui</file>
|
||||||
|
|
||||||
<!-- UI Files -->
|
<!-- UI Files -->
|
||||||
|
@ -18,8 +20,6 @@
|
||||||
<file>window.ui</file>
|
<file>window.ui</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">preferences.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks">preferences.ui</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks">preferences_password_page.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks">preferences_password_page.ui</file>
|
||||||
<file compressed="true" preprocess="xml-stripblanks" alias="preferences_provider_page.ui">resources/ui/preferences_provider_page.ui</file>
|
|
||||||
<file compressed="true" preprocess="xml-stripblanks" alias="preferences_providers_page.ui">resources/ui/preferences_providers_page.ui</file>
|
|
||||||
|
|
||||||
<file compressed="true" preprocess="xml-stripblanks" alias="provider_image.ui">resources/ui/provider_image.ui</file>
|
<file compressed="true" preprocess="xml-stripblanks" alias="provider_image.ui">resources/ui/provider_image.ui</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
|
|
|
@ -50,8 +50,6 @@
|
||||||
<property name="margin-top">12</property>
|
<property name="margin-top">12</property>
|
||||||
<property name="margin-bottom">12</property>
|
<property name="margin-bottom">12</property>
|
||||||
<property name="vexpand">True</property>
|
<property name="vexpand">True</property>
|
||||||
<property name="maximum-size">400</property>
|
|
||||||
<property name="tightening-threshold">400</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox" id="main_container">
|
<object class="GtkBox" id="main_container">
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<interface>
|
|
||||||
<object class="HdyPreferencesPage" id="providers_page">
|
|
||||||
<property name="icon-name">package-x-generic-symbolic</property>
|
|
||||||
<property name="title">Providers</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkScrolledWindow">
|
|
||||||
<child>
|
|
||||||
<object class="HdyClampScrollable">
|
|
||||||
<property name="vexpand">True</property>
|
|
||||||
<property name="hexpand">True</property>
|
|
||||||
<child>
|
|
||||||
<object class="GtkListView" id="providers_list">
|
|
||||||
<property name="vexpand">true</property>
|
|
||||||
<property name="single_click_activate">True</property>
|
|
||||||
<style>
|
|
||||||
<class name="content" />
|
|
||||||
</style>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</child>
|
|
||||||
</object>
|
|
||||||
</interface>
|
|
|
@ -9,10 +9,11 @@
|
||||||
<widgets>
|
<widgets>
|
||||||
<widget name="period_spinbutton"/>
|
<widget name="period_spinbutton"/>
|
||||||
<widget name="provider_website_entry"/>
|
<widget name="provider_website_entry"/>
|
||||||
|
<widget name="provider_help_entry"/>
|
||||||
<widget name="name_entry"/>
|
<widget name="name_entry"/>
|
||||||
</widgets>
|
</widgets>
|
||||||
</object>
|
</object>
|
||||||
<object class="GtkBox" id="provider_page">
|
<template parent="GtkBox" class="ProviderPage">
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
<property name="hexpand">True</property>
|
<property name="hexpand">True</property>
|
||||||
<child>
|
<child>
|
||||||
|
@ -20,6 +21,8 @@
|
||||||
<property name="show-title-buttons">False</property>
|
<property name="show-title-buttons">False</property>
|
||||||
<property name="title-widget">
|
<property name="title-widget">
|
||||||
<object class="GtkLabel" id="title">
|
<object class="GtkLabel" id="title">
|
||||||
|
<property name="wrap">True</property>
|
||||||
|
<property name="ellipsize">end</property>
|
||||||
<style>
|
<style>
|
||||||
<class name="title" />
|
<class name="title" />
|
||||||
</style>
|
</style>
|
||||||
|
@ -28,7 +31,7 @@
|
||||||
<child type="start">
|
<child type="start">
|
||||||
<object class="GtkButton" id="back_btn">
|
<object class="GtkButton" id="back_btn">
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="action_name">preferences.close_page</property>
|
<property name="action_name">providers.back</property>
|
||||||
<property name="icon-name">go-previous-symbolic</property>
|
<property name="icon-name">go-previous-symbolic</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
@ -37,7 +40,7 @@
|
||||||
<property name="label" translatable="yes">Save</property>
|
<property name="label" translatable="yes">Save</property>
|
||||||
<property name="sensitive">False</property>
|
<property name="sensitive">False</property>
|
||||||
<property name="receives_default">True</property>
|
<property name="receives_default">True</property>
|
||||||
<property name="action_name">provider.save</property>
|
<property name="action_name">providers.save</property>
|
||||||
<style>
|
<style>
|
||||||
<class name="suggested-action"/>
|
<class name="suggested-action"/>
|
||||||
</style>
|
</style>
|
||||||
|
@ -51,8 +54,6 @@
|
||||||
<property name="margin-top">12</property>
|
<property name="margin-top">12</property>
|
||||||
<property name="margin-bottom">12</property>
|
<property name="margin-bottom">12</property>
|
||||||
<property name="vexpand">True</property>
|
<property name="vexpand">True</property>
|
||||||
<property name="maximum-size">400</property>
|
|
||||||
<property name="tightening-threshold">400</property>
|
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkBox" id="main_container">
|
<object class="GtkBox" id="main_container">
|
||||||
<property name="orientation">vertical</property>
|
<property name="orientation">vertical</property>
|
||||||
|
@ -113,7 +114,21 @@
|
||||||
<property name="valign">center</property>
|
<property name="valign">center</property>
|
||||||
<property name="hexpand">True</property>
|
<property name="hexpand">True</property>
|
||||||
<property name="input_purpose">url</property>
|
<property name="input_purpose">url</property>
|
||||||
<property name="enable_emoji_completion">True</property>
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="HdyActionRow">
|
||||||
|
<property name="activatable_widget">provider_help_entry</property>
|
||||||
|
<property name="title" translatable="yes">Help URL</property>
|
||||||
|
<property name="subtitle" translatable="yes">How to setup Two-Factor Authentication</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkEntry" id="provider_help_entry">
|
||||||
|
<property name="halign">end</property>
|
||||||
|
<property name="valign">center</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<property name="input_purpose">url</property>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
@ -151,5 +166,5 @@
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</template>
|
||||||
</interface>
|
</interface>
|
79
data/resources/ui/providers_all.ui
Normal file
79
data/resources/ui/providers_all.ui
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<interface>
|
||||||
|
<template parent="HdyWindow" class="ProvidersDialog">
|
||||||
|
<property name="modal">True</property>
|
||||||
|
<property name="title" translatable="yes">Providers</property>
|
||||||
|
<property name="default-width">360</property>
|
||||||
|
<property name="default-height">600</property>
|
||||||
|
<child>
|
||||||
|
<object class="HdyLeaflet" id="deck">
|
||||||
|
<property name="can-unfold">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="HdyLeafletPage">
|
||||||
|
<property name="name">providers</property>
|
||||||
|
<property name="child">
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkHeaderBar">
|
||||||
|
<property name="show-title-buttons">True</property>
|
||||||
|
<child type="start">
|
||||||
|
<object class="GtkButton" id="add_btn">
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="action_name">providers.add</property>
|
||||||
|
<property name="icon-name">list-add-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="end">
|
||||||
|
<object class="GtkToggleButton" id="search_btn">
|
||||||
|
<property name="receives_default">True</property>
|
||||||
|
<property name="icon-name">system-search-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<style>
|
||||||
|
<class name="titlebar"/>
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkScrolledWindow">
|
||||||
|
<property name="min-content-width">340</property>
|
||||||
|
<property name="min-content-height">400</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkSearchBar" id="search_bar">
|
||||||
|
<child>
|
||||||
|
<object class="GtkSearchEntry" id="search_entry">
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="HdyClampScrollable">
|
||||||
|
<property name="vexpand">True</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkListView" id="providers_list">
|
||||||
|
<property name="vexpand">true</property>
|
||||||
|
<property name="single_click_activate">True</property>
|
||||||
|
<style>
|
||||||
|
<class name="content" />
|
||||||
|
</style>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</template>
|
||||||
|
</interface>
|
|
@ -1,6 +1,10 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<interface>
|
<interface>
|
||||||
<menu id="menu">
|
<menu id="menu">
|
||||||
|
<item>
|
||||||
|
<attribute name="label">_Providers</attribute>
|
||||||
|
<attribute name="action">app.providers</attribute>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<attribute name="label">_Lock the application</attribute>
|
<attribute name="label">_Lock the application</attribute>
|
||||||
<attribute name="action">app.lock</attribute>
|
<attribute name="action">app.lock</attribute>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::config;
|
use crate::config;
|
||||||
use crate::helpers::Keyring;
|
use crate::helpers::Keyring;
|
||||||
use crate::models::{Account, Provider, ProvidersModel};
|
use crate::models::{Account, Provider, ProvidersModel};
|
||||||
use crate::widgets::{AccountAddDialog, PreferencesWindow, View, Window};
|
use crate::widgets::{AccountAddDialog, PreferencesWindow, ProvidersDialog, View, Window};
|
||||||
use gio::prelude::*;
|
use gio::prelude::*;
|
||||||
use glib::subclass::prelude::*;
|
use glib::subclass::prelude::*;
|
||||||
use glib::{subclass, WeakRef};
|
use glib::{subclass, WeakRef};
|
||||||
|
@ -149,6 +149,17 @@ impl ApplicationImpl for ApplicationPrivate {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
action!(
|
||||||
|
app,
|
||||||
|
"providers",
|
||||||
|
clone!(@strong app, @weak self.model as model => move |_, _| {
|
||||||
|
let window = app.get_active_window().unwrap();
|
||||||
|
let providers = ProvidersDialog::new(model);
|
||||||
|
providers.set_transient_for(Some(&window));
|
||||||
|
providers.show();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
action!(
|
action!(
|
||||||
app,
|
app,
|
||||||
"lock",
|
"lock",
|
||||||
|
@ -159,10 +170,12 @@ impl ApplicationImpl for ApplicationPrivate {
|
||||||
app.bind_property("can-be-locked", &get_action!(app, @lock), "enabled")
|
app.bind_property("can-be-locked", &get_action!(app, @lock), "enabled")
|
||||||
.flags(glib::BindingFlags::DEFAULT | glib::BindingFlags::SYNC_CREATE)
|
.flags(glib::BindingFlags::DEFAULT | glib::BindingFlags::SYNC_CREATE)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
app.bind_property("locked", &get_action!(app, @preferences), "enabled")
|
app.bind_property("locked", &get_action!(app, @preferences), "enabled")
|
||||||
.flags(glib::BindingFlags::INVERT_BOOLEAN | glib::BindingFlags::SYNC_CREATE)
|
.flags(glib::BindingFlags::INVERT_BOOLEAN | glib::BindingFlags::SYNC_CREATE)
|
||||||
.build();
|
.build();
|
||||||
|
app.bind_property("locked", &get_action!(app, @providers), "enabled")
|
||||||
|
.flags(glib::BindingFlags::INVERT_BOOLEAN | glib::BindingFlags::SYNC_CREATE)
|
||||||
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate(&self, app: &Self::Type) {
|
fn activate(&self, app: &Self::Type) {
|
||||||
|
@ -181,10 +194,12 @@ impl ApplicationImpl for ApplicationPrivate {
|
||||||
app.set_resource_base_path(Some("/com/belmoussaoui/Authenticator"));
|
app.set_resource_base_path(Some("/com/belmoussaoui/Authenticator"));
|
||||||
app.set_accels_for_action("app.quit", &["<primary>q"]);
|
app.set_accels_for_action("app.quit", &["<primary>q"]);
|
||||||
app.set_accels_for_action("app.lock", &["<primary>l"]);
|
app.set_accels_for_action("app.lock", &["<primary>l"]);
|
||||||
|
app.set_accels_for_action("app.providers", &["<primary>p"]);
|
||||||
app.set_accels_for_action("app.preferences", &["<primary>comma"]);
|
app.set_accels_for_action("app.preferences", &["<primary>comma"]);
|
||||||
app.set_accels_for_action("win.show-help-overlay", &["<primary>question"]);
|
app.set_accels_for_action("win.show-help-overlay", &["<primary>question"]);
|
||||||
app.set_accels_for_action("win.search", &["<primary>f"]);
|
app.set_accels_for_action("win.search", &["<primary>f"]);
|
||||||
app.set_accels_for_action("win.add-account", &["<primary>n"]);
|
app.set_accels_for_action("win.add-account", &["<primary>n"]);
|
||||||
|
|
||||||
app.set_locked(has_set_password);
|
app.set_locked(has_set_password);
|
||||||
app.set_can_be_locked(has_set_password);
|
app.set_can_be_locked(has_set_password);
|
||||||
let receiver = self.receiver.borrow_mut().take().unwrap();
|
let receiver = self.receiver.borrow_mut().take().unwrap();
|
||||||
|
|
|
@ -44,6 +44,7 @@ sources = files(
|
||||||
'helpers/mod.rs',
|
'helpers/mod.rs',
|
||||||
'helpers/qrcode.rs',
|
'helpers/qrcode.rs',
|
||||||
'models/account.rs',
|
'models/account.rs',
|
||||||
|
'models/algorithm.rs',
|
||||||
'models/database.rs',
|
'models/database.rs',
|
||||||
'models/favicon.rs',
|
'models/favicon.rs',
|
||||||
'models/mod.rs',
|
'models/mod.rs',
|
||||||
|
@ -52,14 +53,14 @@ sources = files(
|
||||||
'widgets/accounts/add.rs',
|
'widgets/accounts/add.rs',
|
||||||
'widgets/accounts/mod.rs',
|
'widgets/accounts/mod.rs',
|
||||||
'widgets/accounts/row.rs',
|
'widgets/accounts/row.rs',
|
||||||
'widgets/providers/list.rs',
|
|
||||||
'widgets/providers/mod.rs',
|
|
||||||
'widgets/providers/row.rs',
|
|
||||||
'widgets/preferences/mod.rs',
|
'widgets/preferences/mod.rs',
|
||||||
'widgets/preferences/password_page.rs',
|
'widgets/preferences/password_page.rs',
|
||||||
'widgets/preferences/provider_page.rs',
|
|
||||||
'widgets/preferences/providers_page.rs',
|
|
||||||
'widgets/preferences/window.rs',
|
'widgets/preferences/window.rs',
|
||||||
|
'widgets/providers/all.rs',
|
||||||
|
'widgets/providers/list.rs',
|
||||||
|
'widgets/providers/mod.rs',
|
||||||
|
'widgets/providers/page.rs',
|
||||||
|
'widgets/providers/row.rs',
|
||||||
'widgets/mod.rs',
|
'widgets/mod.rs',
|
||||||
'widgets/window.rs',
|
'widgets/window.rs',
|
||||||
'application.rs',
|
'application.rs',
|
||||||
|
|
|
@ -10,7 +10,6 @@ pub enum Algorithm {
|
||||||
OTP = 0,
|
OTP = 0,
|
||||||
#[genum(name = "HOTP")]
|
#[genum(name = "HOTP")]
|
||||||
HOTP = 1,
|
HOTP = 1,
|
||||||
#[genum(name = "Steam")]
|
|
||||||
Steam = 2,
|
Steam = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ use gtk::FilterListModelExt;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
|
use unicase::UniCase;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
#[derive(Insertable)]
|
#[derive(Insertable)]
|
||||||
|
@ -250,7 +251,7 @@ impl Provider {
|
||||||
let provider1 = obj1.downcast_ref::<Provider>().unwrap();
|
let provider1 = obj1.downcast_ref::<Provider>().unwrap();
|
||||||
let provider2 = obj2.downcast_ref::<Provider>().unwrap();
|
let provider2 = obj2.downcast_ref::<Provider>().unwrap();
|
||||||
|
|
||||||
provider1.name().cmp(&provider2.name())
|
UniCase::new(provider1.name()).cmp(&UniCase::new(provider2.name()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load() -> Result<Vec<Self>> {
|
pub fn load() -> Result<Vec<Self>> {
|
||||||
|
|
|
@ -5,5 +5,5 @@ 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::ProvidersList;
|
pub use self::providers::{ProvidersDialog, ProvidersList};
|
||||||
pub use self::window::{View, Window};
|
pub use self::window::{View, Window};
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
mod password_page;
|
mod password_page;
|
||||||
mod provider_page;
|
|
||||||
mod providers_page;
|
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
pub use window::PreferencesWindow;
|
pub use window::PreferencesWindow;
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
use crate::models::{Algorithm, Provider};
|
|
||||||
use glib::translate::ToGlib;
|
|
||||||
use gtk::prelude::*;
|
|
||||||
use libhandy::{ComboRowExt, EnumListModelExt};
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub struct ProviderPage {
|
|
||||||
pub widget: gtk::Box,
|
|
||||||
builder: gtk::Builder,
|
|
||||||
algorithms_model: libhandy::EnumListModel,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProviderPage {
|
|
||||||
pub fn new() -> Rc<Self> {
|
|
||||||
let builder = gtk::Builder::from_resource(
|
|
||||||
"/com/belmoussaoui/Authenticator/preferences_provider_page.ui",
|
|
||||||
);
|
|
||||||
get_widget!(builder, gtk::Box, provider_page);
|
|
||||||
let algorithms_model = libhandy::EnumListModel::new(Algorithm::static_type());
|
|
||||||
|
|
||||||
let page = Rc::new(Self {
|
|
||||||
widget: provider_page,
|
|
||||||
builder,
|
|
||||||
algorithms_model,
|
|
||||||
});
|
|
||||||
page.init();
|
|
||||||
page
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_provider(&self, provider: Provider) {
|
|
||||||
get_widget!(self.builder, gtk::Entry, @name_entry).set_text(&provider.name());
|
|
||||||
get_widget!(self.builder, gtk::SpinButton, @period_spinbutton)
|
|
||||||
.set_value(provider.period() as f64);
|
|
||||||
|
|
||||||
if let Some(ref website) = provider.website() {
|
|
||||||
get_widget!(self.builder, gtk::Entry, @provider_website_entry).set_text(website);
|
|
||||||
}
|
|
||||||
|
|
||||||
get_widget!(self.builder, gtk::Stack, @image_stack).set_visible_child_name("loading");
|
|
||||||
get_widget!(self.builder, gtk::Spinner, @spinner).start();
|
|
||||||
|
|
||||||
get_widget!(self.builder, libhandy::ComboRow, algorithm_comborow);
|
|
||||||
algorithm_comborow.set_selected(
|
|
||||||
self.algorithms_model
|
|
||||||
.find_position(provider.algorithm().to_glib()),
|
|
||||||
);
|
|
||||||
|
|
||||||
/*let sender = self.sender.clone();
|
|
||||||
spawn!(async move {
|
|
||||||
if let Ok(file) = p.favicon().await {
|
|
||||||
send!(sender, AddAccountAction::SetIcon(file));
|
|
||||||
}
|
|
||||||
});*/
|
|
||||||
|
|
||||||
get_widget!(self.builder, gtk::Label, title);
|
|
||||||
title.set_text(&format!("Editing provider: {}", provider.name()));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(&self) {
|
|
||||||
get_widget!(self.builder, libhandy::ComboRow, algorithm_comborow);
|
|
||||||
algorithm_comborow.set_model(Some(&self.algorithms_model));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
use crate::models::{Provider, ProvidersModel};
|
|
||||||
use gio::ListModelExt;
|
|
||||||
use gtk::prelude::*;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub struct ProvidersPage {
|
|
||||||
pub widget: libhandy::PreferencesPage,
|
|
||||||
builder: gtk::Builder,
|
|
||||||
model: Rc<ProvidersModel>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ProvidersPage {
|
|
||||||
pub fn new(model: Rc<ProvidersModel>) -> Rc<Self> {
|
|
||||||
let builder = gtk::Builder::from_resource(
|
|
||||||
"/com/belmoussaoui/Authenticator/preferences_providers_page.ui",
|
|
||||||
);
|
|
||||||
get_widget!(builder, libhandy::PreferencesPage, providers_page);
|
|
||||||
|
|
||||||
let page = Rc::new(Self {
|
|
||||||
widget: providers_page,
|
|
||||||
builder,
|
|
||||||
model,
|
|
||||||
});
|
|
||||||
page.init();
|
|
||||||
page
|
|
||||||
}
|
|
||||||
|
|
||||||
fn init(&self) {
|
|
||||||
get_widget!(self.builder, gtk::ListView, providers_list);
|
|
||||||
|
|
||||||
let factory = gtk::SignalListItemFactory::new();
|
|
||||||
factory.connect_bind(|_, list_item| {
|
|
||||||
let item = list_item.get_item().unwrap();
|
|
||||||
let provider = item.downcast_ref::<Provider>().unwrap();
|
|
||||||
let row = Row::new(provider);
|
|
||||||
list_item.set_child(Some(&row.widget));
|
|
||||||
});
|
|
||||||
providers_list.set_factory(Some(&factory));
|
|
||||||
|
|
||||||
let selection_model = gtk::NoSelection::new(Some(&self.model.model));
|
|
||||||
providers_list.set_model(Some(&selection_model));
|
|
||||||
|
|
||||||
providers_list.connect_activate(move |listview, pos| {
|
|
||||||
let model = listview.get_model().unwrap();
|
|
||||||
let provider = model
|
|
||||||
.get_object(pos)
|
|
||||||
.unwrap()
|
|
||||||
.downcast::<Provider>()
|
|
||||||
.unwrap();
|
|
||||||
// send!(sender, PreferencesAction::EditProvider(provider));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Row<'a> {
|
|
||||||
pub widget: libhandy::ActionRow,
|
|
||||||
provider: &'a Provider,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Row<'a> {
|
|
||||||
pub fn new(provider: &'a Provider) -> Self {
|
|
||||||
let widget = libhandy::ActionRowBuilder::new()
|
|
||||||
.title(&provider.name())
|
|
||||||
.build();
|
|
||||||
Self { widget, provider }
|
|
||||||
}
|
|
||||||
}
|
|
311
src/widgets/providers/all.rs
Normal file
311
src/widgets/providers/all.rs
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
use super::{ProviderPage, ProviderPageMode};
|
||||||
|
use crate::models::{Provider, ProvidersModel};
|
||||||
|
use gio::prelude::*;
|
||||||
|
use gio::subclass::ObjectSubclass;
|
||||||
|
use gio::ListModelExt;
|
||||||
|
use glib::subclass::prelude::*;
|
||||||
|
use glib::{glib_object_subclass, glib_wrapper};
|
||||||
|
use gtk::{prelude::*, CompositeTemplate};
|
||||||
|
use libhandy::{LeafletExt, LeafletPageExt};
|
||||||
|
use row::ProviderActionRow;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
use glib::subclass;
|
||||||
|
use gtk::subclass::prelude::*;
|
||||||
|
use libhandy::subclass::window::WindowImpl as HdyWindowImpl;
|
||||||
|
|
||||||
|
#[derive(CompositeTemplate)]
|
||||||
|
pub struct ProvidersDialog {
|
||||||
|
#[template_child(id = "providers_list")]
|
||||||
|
pub providers_list: TemplateChild<gtk::ListView>,
|
||||||
|
#[template_child(id = "deck")]
|
||||||
|
pub deck: TemplateChild<libhandy::Leaflet>,
|
||||||
|
#[template_child(id = "search_entry")]
|
||||||
|
pub search_entry: TemplateChild<gtk::SearchEntry>,
|
||||||
|
#[template_child(id = "search_bar")]
|
||||||
|
pub search_bar: TemplateChild<gtk::SearchBar>,
|
||||||
|
#[template_child(id = "search_btn")]
|
||||||
|
pub search_btn: TemplateChild<gtk::ToggleButton>,
|
||||||
|
pub page: ProviderPage,
|
||||||
|
pub actions: gio::SimpleActionGroup,
|
||||||
|
pub filter_model: gtk::FilterListModel,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectSubclass for ProvidersDialog {
|
||||||
|
const NAME: &'static str = "ProvidersDialog";
|
||||||
|
type Type = super::ProvidersDialog;
|
||||||
|
type ParentType = libhandy::Window;
|
||||||
|
type Instance = subclass::simple::InstanceStruct<Self>;
|
||||||
|
type Class = subclass::simple::ClassStruct<Self>;
|
||||||
|
|
||||||
|
glib_object_subclass!();
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
let filter_model =
|
||||||
|
gtk::FilterListModel::new(gtk::NONE_FILTER_LIST_MODEL, gtk::NONE_FILTER);
|
||||||
|
Self {
|
||||||
|
deck: TemplateChild::default(),
|
||||||
|
providers_list: TemplateChild::default(),
|
||||||
|
search_entry: TemplateChild::default(),
|
||||||
|
search_bar: TemplateChild::default(),
|
||||||
|
search_btn: TemplateChild::default(),
|
||||||
|
page: ProviderPage::new(),
|
||||||
|
actions: gio::SimpleActionGroup::new(),
|
||||||
|
filter_model,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.set_template_from_resource("/com/belmoussaoui/Authenticator/providers_all.ui");
|
||||||
|
Self::bind_template_children(klass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for ProvidersDialog {
|
||||||
|
fn constructed(&self, obj: &Self::Type) {
|
||||||
|
obj.init_template();
|
||||||
|
self.parent_constructed(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl WidgetImpl for ProvidersDialog {}
|
||||||
|
impl WindowImpl for ProvidersDialog {}
|
||||||
|
impl HdyWindowImpl for ProvidersDialog {}
|
||||||
|
}
|
||||||
|
glib_wrapper! {
|
||||||
|
pub struct ProvidersDialog(ObjectSubclass<imp::ProvidersDialog>) @extends gtk::Widget, gtk::Window, libhandy::Window;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProvidersDialog {
|
||||||
|
pub fn new(model: Rc<ProvidersModel>) -> Self {
|
||||||
|
let dialog = glib::Object::new(Self::static_type(), &[])
|
||||||
|
.expect("Failed to create ProvidersDialog")
|
||||||
|
.downcast::<ProvidersDialog>()
|
||||||
|
.expect("Created object is of wrong type");
|
||||||
|
|
||||||
|
dialog.setup_widgets(model);
|
||||||
|
dialog.setup_actions();
|
||||||
|
dialog
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_widgets(&self, model: Rc<ProvidersModel>) {
|
||||||
|
let self_ = imp::ProvidersDialog::from_instance(self);
|
||||||
|
|
||||||
|
self_.filter_model.set_model(Some(&model.model));
|
||||||
|
self_
|
||||||
|
.search_bar
|
||||||
|
.get()
|
||||||
|
.bind_property("search-mode-enabled", &self_.search_btn.get(), "active")
|
||||||
|
.flags(glib::BindingFlags::BIDIRECTIONAL | glib::BindingFlags::SYNC_CREATE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
self_.search_entry.get().connect_search_changed(
|
||||||
|
clone!(@weak self as dialog => move |entry| {
|
||||||
|
let text = entry.get_text().unwrap().to_string();
|
||||||
|
dialog.search(text);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let search_btn = self_.search_btn.get();
|
||||||
|
|
||||||
|
self_
|
||||||
|
.search_btn
|
||||||
|
.get()
|
||||||
|
.bind_property("active", &self_.search_bar.get(), "search-mode-enabled")
|
||||||
|
.flags(glib::BindingFlags::BIDIRECTIONAL | glib::BindingFlags::SYNC_CREATE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let factory = gtk::SignalListItemFactory::new();
|
||||||
|
factory.connect_bind(|_, list_item| {
|
||||||
|
let item = list_item.get_item().unwrap();
|
||||||
|
let provider = item.clone().downcast::<Provider>().unwrap();
|
||||||
|
let row = ProviderActionRow::new(provider);
|
||||||
|
list_item.set_child(Some(&row));
|
||||||
|
});
|
||||||
|
self_.providers_list.get().set_factory(Some(&factory));
|
||||||
|
|
||||||
|
let selection_model = gtk::NoSelection::new(Some(&self_.filter_model));
|
||||||
|
self_.providers_list.get().set_model(Some(&selection_model));
|
||||||
|
|
||||||
|
self_.providers_list.get().connect_activate(
|
||||||
|
clone!(@weak self as dialog => move |listview, pos| {
|
||||||
|
let model = listview.get_model().unwrap();
|
||||||
|
let provider = model
|
||||||
|
.get_object(pos)
|
||||||
|
.unwrap()
|
||||||
|
.downcast::<Provider>()
|
||||||
|
.unwrap();
|
||||||
|
dialog.edit_provider(provider);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let deck_page = self_.deck.get().add(&self_.page).unwrap();
|
||||||
|
deck_page.set_name("provider");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_actions(&self) {
|
||||||
|
let self_ = imp::ProvidersDialog::from_instance(self);
|
||||||
|
|
||||||
|
let deck = self_.deck.get();
|
||||||
|
let search_bar = self_.search_bar.get();
|
||||||
|
action!(
|
||||||
|
self_.actions,
|
||||||
|
"search",
|
||||||
|
clone!(@weak search_bar => move |_,_| {
|
||||||
|
search_bar.set_search_mode(!search_bar.get_search_mode());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
action!(
|
||||||
|
self_.actions,
|
||||||
|
"back",
|
||||||
|
clone!(@weak deck => move |_ , _| {
|
||||||
|
deck.set_visible_child_name("providers");
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
action!(
|
||||||
|
self_.actions,
|
||||||
|
"add",
|
||||||
|
clone!(@weak self as dialog => move |_, _| {
|
||||||
|
dialog.add_provider();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
self.insert_action_group("providers", Some(&self_.actions));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search(&self, text: String) {
|
||||||
|
let self_ = imp::ProvidersDialog::from_instance(self);
|
||||||
|
|
||||||
|
let providers_filter = gtk::CustomFilter::new(Some(Box::new(move |object| {
|
||||||
|
let provider = object.downcast_ref::<Provider>().unwrap();
|
||||||
|
provider
|
||||||
|
.name()
|
||||||
|
.to_ascii_lowercase()
|
||||||
|
.contains(&text.to_ascii_lowercase())
|
||||||
|
})));
|
||||||
|
self_.filter_model.set_filter(Some(&providers_filter));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_provider(&self) {
|
||||||
|
let self_ = imp::ProvidersDialog::from_instance(self);
|
||||||
|
self_.deck.get().set_visible_child_name("provider");
|
||||||
|
self_.page.set_mode(ProviderPageMode::Create);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn edit_provider(&self, provider: Provider) {
|
||||||
|
let self_ = imp::ProvidersDialog::from_instance(self);
|
||||||
|
self_.deck.get().set_visible_child_name("provider");
|
||||||
|
self_.page.set_provider(provider);
|
||||||
|
self_.page.set_mode(ProviderPageMode::Edit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod row {
|
||||||
|
use super::*;
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
use glib::subclass;
|
||||||
|
use gtk::subclass::prelude::*;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
static PROPERTIES: [subclass::Property; 1] = [subclass::Property("provider", |name| {
|
||||||
|
glib::ParamSpec::object(
|
||||||
|
name,
|
||||||
|
"Provider",
|
||||||
|
"The Provider",
|
||||||
|
Provider::static_type(),
|
||||||
|
glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
|
||||||
|
)
|
||||||
|
})];
|
||||||
|
|
||||||
|
pub struct ProviderActionRow {
|
||||||
|
pub provider: RefCell<Option<Provider>>,
|
||||||
|
pub actions: gio::SimpleActionGroup,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectSubclass for ProviderActionRow {
|
||||||
|
const NAME: &'static str = "ProviderActionRow";
|
||||||
|
type Type = super::ProviderActionRow;
|
||||||
|
type ParentType = libhandy::ActionRow;
|
||||||
|
type Instance = subclass::simple::InstanceStruct<Self>;
|
||||||
|
type Class = subclass::simple::ClassStruct<Self>;
|
||||||
|
|
||||||
|
glib_object_subclass!();
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
let actions = gio::SimpleActionGroup::new();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
actions,
|
||||||
|
provider: RefCell::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.install_properties(&PROPERTIES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for ProviderActionRow {
|
||||||
|
fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
|
||||||
|
let prop = &PROPERTIES[id];
|
||||||
|
|
||||||
|
match *prop {
|
||||||
|
subclass::Property("provider", ..) => {
|
||||||
|
let provider = value
|
||||||
|
.get()
|
||||||
|
.expect("type conformity checked by `Object::set_property`");
|
||||||
|
self.provider.replace(provider);
|
||||||
|
}
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
|
||||||
|
let prop = &PROPERTIES[id];
|
||||||
|
match *prop {
|
||||||
|
subclass::Property("provider", ..) => self.provider.borrow().to_value(),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn constructed(&self, obj: &Self::Type) {
|
||||||
|
obj.init_template();
|
||||||
|
obj.setup_widgets();
|
||||||
|
self.parent_constructed(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl WidgetImpl for ProviderActionRow {}
|
||||||
|
impl ListBoxRowImpl for ProviderActionRow {}
|
||||||
|
impl libhandy::subclass::action_row::ActionRowImpl for ProviderActionRow {}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib_wrapper! {
|
||||||
|
pub struct ProviderActionRow(ObjectSubclass<imp::ProviderActionRow>) @extends gtk::Widget, gtk::ListBoxRow, libhandy::ActionRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ProviderActionRow {
|
||||||
|
pub fn new(provider: Provider) -> Self {
|
||||||
|
glib::Object::new(Self::static_type(), &[("provider", &provider)])
|
||||||
|
.expect("Failed to create ProviderActionRow")
|
||||||
|
.downcast::<ProviderActionRow>()
|
||||||
|
.expect("Created object is of wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn provider(&self) -> Provider {
|
||||||
|
let provider = self.get_property("provider").unwrap();
|
||||||
|
provider.get::<Provider>().unwrap().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_widgets(&self) {
|
||||||
|
let self_ = imp::ProviderActionRow::from_instance(self);
|
||||||
|
|
||||||
|
self.provider()
|
||||||
|
.bind_property("name", self, "title")
|
||||||
|
.flags(glib::BindingFlags::DEFAULT | glib::BindingFlags::SYNC_CREATE)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,8 @@
|
||||||
|
mod all;
|
||||||
mod list;
|
mod list;
|
||||||
|
mod page;
|
||||||
mod row;
|
mod row;
|
||||||
|
pub use self::all::ProvidersDialog;
|
||||||
pub use self::list::ProvidersList;
|
pub use self::list::ProvidersList;
|
||||||
|
pub use self::page::{ProviderPage, ProviderPageMode};
|
||||||
pub use self::row::ProviderRow;
|
pub use self::row::ProviderRow;
|
||||||
|
|
156
src/widgets/providers/page.rs
Normal file
156
src/widgets/providers/page.rs
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
use crate::models::{Algorithm, Provider};
|
||||||
|
use gio::subclass::ObjectSubclass;
|
||||||
|
use glib::subclass::prelude::*;
|
||||||
|
use glib::translate::ToGlib;
|
||||||
|
use glib::{glib_object_subclass, glib_wrapper};
|
||||||
|
use gtk::{prelude::*, CompositeTemplate};
|
||||||
|
use libhandy::{ComboRowExt, EnumListModelExt};
|
||||||
|
|
||||||
|
pub enum ProviderPageMode {
|
||||||
|
Create,
|
||||||
|
Edit,
|
||||||
|
}
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
use glib::subclass;
|
||||||
|
use gtk::subclass::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug, CompositeTemplate)]
|
||||||
|
pub struct ProviderPage {
|
||||||
|
#[template_child(id = "name_entry")]
|
||||||
|
pub name_entry: TemplateChild<gtk::Entry>,
|
||||||
|
#[template_child(id = "period_spinbutton")]
|
||||||
|
pub period_spinbutton: TemplateChild<gtk::SpinButton>,
|
||||||
|
#[template_child(id = "provider_website_entry")]
|
||||||
|
pub provider_website_entry: TemplateChild<gtk::Entry>,
|
||||||
|
#[template_child(id = "provider_help_entry")]
|
||||||
|
pub provider_help_entry: TemplateChild<gtk::Entry>,
|
||||||
|
#[template_child(id = "image_stack")]
|
||||||
|
pub image_stack: TemplateChild<gtk::Stack>,
|
||||||
|
#[template_child(id = "spinner")]
|
||||||
|
pub spinner: TemplateChild<gtk::Spinner>,
|
||||||
|
#[template_child(id = "algorithm_comborow")]
|
||||||
|
pub algorithm_comborow: TemplateChild<libhandy::ComboRow>,
|
||||||
|
#[template_child(id = "title")]
|
||||||
|
pub title: TemplateChild<gtk::Label>,
|
||||||
|
pub algorithms_model: libhandy::EnumListModel,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectSubclass for ProviderPage {
|
||||||
|
const NAME: &'static str = "ProviderPage";
|
||||||
|
type Type = super::ProviderPage;
|
||||||
|
type ParentType = gtk::Box;
|
||||||
|
type Instance = subclass::simple::InstanceStruct<Self>;
|
||||||
|
type Class = subclass::simple::ClassStruct<Self>;
|
||||||
|
|
||||||
|
glib_object_subclass!();
|
||||||
|
|
||||||
|
fn new() -> Self {
|
||||||
|
let algorithms_model = libhandy::EnumListModel::new(Algorithm::static_type());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
name_entry: TemplateChild::default(),
|
||||||
|
period_spinbutton: TemplateChild::default(),
|
||||||
|
provider_website_entry: TemplateChild::default(),
|
||||||
|
provider_help_entry: TemplateChild::default(),
|
||||||
|
image_stack: TemplateChild::default(),
|
||||||
|
spinner: TemplateChild::default(),
|
||||||
|
algorithm_comborow: TemplateChild::default(),
|
||||||
|
title: TemplateChild::default(),
|
||||||
|
algorithms_model,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.set_template_from_resource("/com/belmoussaoui/Authenticator/provider_page.ui");
|
||||||
|
Self::bind_template_children(klass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for ProviderPage {
|
||||||
|
fn constructed(&self, obj: &Self::Type) {
|
||||||
|
obj.init_template();
|
||||||
|
obj.setup_widgets();
|
||||||
|
self.parent_constructed(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl WidgetImpl for ProviderPage {}
|
||||||
|
impl BoxImpl for ProviderPage {}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib_wrapper! {
|
||||||
|
pub struct ProviderPage(ObjectSubclass<imp::ProviderPage>) @extends gtk::Widget, gtk::Box;
|
||||||
|
}
|
||||||
|
impl ProviderPage {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
glib::Object::new(Self::static_type(), &[])
|
||||||
|
.expect("Failed to create ProviderPage")
|
||||||
|
.downcast::<ProviderPage>()
|
||||||
|
.expect("Created object is of wrong type")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_provider(&self, provider: Provider) {
|
||||||
|
let self_ = imp::ProviderPage::from_instance(self);
|
||||||
|
self_.name_entry.get().set_text(&provider.name());
|
||||||
|
self_
|
||||||
|
.period_spinbutton
|
||||||
|
.get()
|
||||||
|
.set_value(provider.period() as f64);
|
||||||
|
|
||||||
|
if let Some(ref website) = provider.website() {
|
||||||
|
self_.provider_website_entry.get().set_text(website);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref website) = provider.help_url() {
|
||||||
|
self_.provider_help_entry.get().set_text(website);
|
||||||
|
}
|
||||||
|
|
||||||
|
self_.image_stack.get().set_visible_child_name("loading");
|
||||||
|
self_.spinner.get().start();
|
||||||
|
|
||||||
|
self_.algorithm_comborow.get().set_selected(
|
||||||
|
self_
|
||||||
|
.algorithms_model
|
||||||
|
.find_position(provider.algorithm().to_glib()),
|
||||||
|
);
|
||||||
|
|
||||||
|
/*let sender = self.sender.clone();
|
||||||
|
spawn!(async move {
|
||||||
|
if let Ok(file) = p.favicon().await {
|
||||||
|
send!(sender, AddAccountAction::SetIcon(file));
|
||||||
|
}
|
||||||
|
});*/
|
||||||
|
|
||||||
|
self_
|
||||||
|
.title
|
||||||
|
.get()
|
||||||
|
.set_text(&format!("Editing provider: {}", provider.name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_widgets(&self) {
|
||||||
|
let self_ = imp::ProviderPage::from_instance(self);
|
||||||
|
self_
|
||||||
|
.algorithm_comborow
|
||||||
|
.get()
|
||||||
|
.set_model(Some(&self_.algorithms_model));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_mode(&self, mode: ProviderPageMode) {
|
||||||
|
let self_ = imp::ProviderPage::from_instance(self);
|
||||||
|
match mode {
|
||||||
|
ProviderPageMode::Create => {
|
||||||
|
self_.title.get().set_label("New Provider");
|
||||||
|
self_.name_entry.get().set_text("");
|
||||||
|
self_.period_spinbutton.get().set_value(30_f64);
|
||||||
|
self_.provider_website_entry.get().set_text("");
|
||||||
|
self_.provider_help_entry.get().set_text("");
|
||||||
|
|
||||||
|
self_.image_stack.get().set_visible_child_name("image");
|
||||||
|
self_.spinner.get().stop();
|
||||||
|
self_.algorithm_comborow.get().set_selected(0);
|
||||||
|
}
|
||||||
|
ProviderPageMode::Edit => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -175,7 +175,6 @@ impl Window {
|
||||||
"gtk-application-prefer-dark-theme",
|
"gtk-application-prefer-dark-theme",
|
||||||
gio::SettingsBindFlags::DEFAULT,
|
gio::SettingsBindFlags::DEFAULT,
|
||||||
);
|
);
|
||||||
self.set_default_size(360, 600);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_actions(&self, app: &Application, sender: Sender<Action>) {
|
fn setup_actions(&self, app: &Application, sender: Sender<Action>) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue