mirror of
https://gitlab.gnome.org/World/Authenticator.git
synced 2025-03-04 08:44:40 +01:00
accounts: bind add dialog
This commit is contained in:
parent
2ba7e0f54d
commit
5c9dc36e1b
19 changed files with 200 additions and 340 deletions
|
@ -5,7 +5,6 @@
|
|||
|
||||
<!-- Accounts -->
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="add_account.ui">resources/ui/add_account.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="accounts_list.ui">resources/ui/accounts_list.ui</file>
|
||||
|
||||
<!-- Providers -->
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="provider_row.ui">resources/ui/provider_row.ui</file>
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
.providers-list {
|
||||
background-color: @theme_base_bg;
|
||||
background-color: @theme_base_bg;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.provider-row {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.provider-row:hover {
|
||||
background-color: @theme_base_bg;
|
||||
}
|
||||
|
||||
.provider-row:active {
|
||||
background: @theme_base_bg;
|
||||
box-shadow: none;
|
||||
}
|
||||
.provider-row .title-2 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.account-row {
|
||||
padding: 12px;
|
||||
}
|
||||
|
|
|
@ -1,33 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkPopoverMenu" id="more_actions_popover">
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="valign">center</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="edit_btn">
|
||||
<property name="receives_default">False</property>
|
||||
<property name="margin-left">6</property>
|
||||
<property name="margin-right">6</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<property name="text" translatable="yes">Edit</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkModelButton" id="delete_btn">
|
||||
<property name="receives_default">False</property>
|
||||
<property name="margin-left">6</property>
|
||||
<property name="margin-right">6</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<property name="text" translatable="yes">Delete</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<menu id="account-menu">
|
||||
<item>
|
||||
<attribute name="label">Edit</attribute>
|
||||
<attribute name="action">account.edit</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Delete</attribute>
|
||||
<attribute name="action">account.delete</attribute>
|
||||
</item>
|
||||
</menu>
|
||||
<object class="GtkListBoxRow" id="account_row">
|
||||
<property name="can_focus">True</property>
|
||||
<property name="valign">center</property>
|
||||
|
@ -35,46 +17,10 @@
|
|||
<child>
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkMenuButton" id="more_actions_btn">
|
||||
<property name="receives_default">False</property>
|
||||
<object class="GtkLabel" id="username_label">
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="popover">more_actions_popover</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="more_actions_img">
|
||||
<property name="icon-name">view-more-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="image-button"/>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="copy_btn">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Copy PIN to clipboard</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="relief">none</property>
|
||||
<child>
|
||||
<object class="GtkStack" id="copy_btn_stack">
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="copy_img">
|
||||
<property name="icon-name">edit-copy-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage" id="ok_image">
|
||||
<property name="icon-name">emblem-ok-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
<property name="ellipsize">end</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
@ -87,10 +33,46 @@
|
|||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="username_label">
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="ellipsize">end</property>
|
||||
<object class="GtkBox">
|
||||
<property name="hexpand">True</property>
|
||||
<property name="halign">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="copy_btn">
|
||||
<property name="receives_default">True</property>
|
||||
<property name="tooltip_text" translatable="yes">Copy PIN to clipboard</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkStack" id="copy_btn_stack">
|
||||
<property name="halign">center</property>
|
||||
<property name="valign">center</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="copy_img">
|
||||
<property name="icon-name">edit-copy-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkImage" id="ok_image">
|
||||
<property name="icon-name">emblem-ok-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="image-button" />
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkMenuButton">
|
||||
<property name="receives_default">False</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="menu-model">account-menu</property>
|
||||
<property name="icon-name">view-more-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="linked" />
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkBox" id="accounts_list">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="pixel_size">96</property>
|
||||
<property name="icon-name">image-missing-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="provider_name">
|
||||
<property name="label" translatable="yes">Some random provider</property>
|
||||
<style>
|
||||
<class name="provider-name"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkListBox" id="listbox">
|
||||
<property name="selection_mode">none</property>
|
||||
<style>
|
||||
<class name="frame"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
|
@ -16,6 +16,14 @@
|
|||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkListBox" id="accounts_list">
|
||||
<property name="vexpand">True</property>
|
||||
<style>
|
||||
<class name="content" />
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
|
|
|
@ -7,10 +7,14 @@
|
|||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="vexpand">True</property>
|
||||
<property name="min-content-width">340</property>
|
||||
<child>
|
||||
<object class="HdyClamp">
|
||||
<child>
|
||||
<object class="GtkListBox" id="providers_list">
|
||||
<property name="selection-mode">none</property>
|
||||
<property name="margin-start">6</property>
|
||||
<property name="margin-end">6</property>
|
||||
<child type="placeholder">
|
||||
<object class="GtkBox">
|
||||
<property name="halign">center</property>
|
||||
|
|
|
@ -54,6 +54,16 @@
|
|||
<child>
|
||||
<object class="GtkBox" id="container">
|
||||
<property name="vexpand">True</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkSearchBar" id="search_bar">
|
||||
<child>
|
||||
<object class="GtkSearchEntry" id="search_entry">
|
||||
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::config;
|
||||
use crate::models::Account;
|
||||
use crate::models::{Account, Provider, ProvidersModel};
|
||||
use crate::widgets::{AddAccountDialog, View, Window};
|
||||
use gio::prelude::*;
|
||||
use glib::subclass;
|
||||
|
@ -7,18 +7,19 @@ use glib::subclass::prelude::*;
|
|||
use glib::translate::*;
|
||||
use gtk::prelude::*;
|
||||
use gtk::subclass::prelude::{ApplicationImpl, ApplicationImplExt, GtkApplicationImpl};
|
||||
use std::cell::RefCell;
|
||||
use std::env;
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use glib::{Receiver, Sender};
|
||||
pub enum Action {
|
||||
ViewAccounts,
|
||||
AccountCreated(Account),
|
||||
AccountCreated(Account, Provider),
|
||||
OpenAddAccountDialog,
|
||||
}
|
||||
|
||||
pub struct ApplicationPrivate {
|
||||
window: RefCell<Option<Window>>,
|
||||
model: Rc<ProvidersModel>,
|
||||
sender: Sender<Action>,
|
||||
receiver: RefCell<Option<Receiver<Action>>>,
|
||||
}
|
||||
|
@ -34,11 +35,13 @@ impl ObjectSubclass for ApplicationPrivate {
|
|||
fn new() -> Self {
|
||||
let (sender, r) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
|
||||
let receiver = RefCell::new(Some(r));
|
||||
let model = Rc::new(ProvidersModel::new());
|
||||
|
||||
Self {
|
||||
window: RefCell::new(None),
|
||||
sender,
|
||||
receiver,
|
||||
model,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +137,7 @@ impl Application {
|
|||
|
||||
fn create_window(&self) -> Window {
|
||||
let self_ = ApplicationPrivate::from_instance(self);
|
||||
let window = Window::new(self_.sender.clone(), &self.clone());
|
||||
let window = Window::new(self_.model.clone(), self_.sender.clone(), &self.clone());
|
||||
|
||||
window
|
||||
}
|
||||
|
@ -143,12 +146,13 @@ impl Application {
|
|||
let self_ = ApplicationPrivate::from_instance(self);
|
||||
match action {
|
||||
Action::OpenAddAccountDialog => {
|
||||
let dialog = AddAccountDialog::new(self_.sender.clone());
|
||||
let dialog = AddAccountDialog::new(self_.model.clone(), self_.sender.clone());
|
||||
//dialog.widget.set_transient_for(Some(&self_.window));
|
||||
dialog.widget.show();
|
||||
}
|
||||
Action::ViewAccounts => (), //self.set_view(View::Accounts),
|
||||
Action::AccountCreated(account) => {
|
||||
Action::AccountCreated(account, provider) => {
|
||||
self_.model.add_account(&account, &provider);
|
||||
println!("{:#?}", account);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -44,14 +44,12 @@ sources = files(
|
|||
'helpers/mod.rs',
|
||||
'helpers/qrcode.rs',
|
||||
'models/account.rs',
|
||||
'models/accounts.rs',
|
||||
'models/database.rs',
|
||||
'models/favicon.rs',
|
||||
'models/mod.rs',
|
||||
'models/provider.rs',
|
||||
'models/providers.rs',
|
||||
'widgets/accounts/add.rs',
|
||||
'widgets/accounts/list.rs',
|
||||
'widgets/accounts/mod.rs',
|
||||
'widgets/providers/list.rs',
|
||||
'widgets/providers/mod.rs',
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
use super::account::Account;
|
||||
use super::provider::Provider;
|
||||
use gio::prelude::*;
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum SortOrder {
|
||||
Asc,
|
||||
Desc,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum SortBy {
|
||||
Name,
|
||||
Date,
|
||||
}
|
||||
|
||||
impl From<&str> for SortBy {
|
||||
fn from(sortby: &str) -> Self {
|
||||
match sortby {
|
||||
"name" => SortBy::Name,
|
||||
"date" => SortBy::Date,
|
||||
_ => SortBy::Name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AccountsModel {
|
||||
pub model: gio::ListStore,
|
||||
sort_order: RefCell<SortOrder>,
|
||||
sort_by: RefCell<SortBy>,
|
||||
provider: Provider,
|
||||
}
|
||||
|
||||
impl AccountsModel {
|
||||
pub fn from_provider(provider: &Provider) -> Self {
|
||||
let gio_model = gio::ListStore::new(Account::static_type());
|
||||
let model = Self {
|
||||
model: gio_model,
|
||||
sort_order: RefCell::new(SortOrder::Desc),
|
||||
sort_by: RefCell::new(SortBy::Name),
|
||||
provider: provider.clone(),
|
||||
};
|
||||
model.init();
|
||||
model
|
||||
}
|
||||
|
||||
fn init(&self) {
|
||||
// fill in the accounts from the database
|
||||
/*let accounts = database::get_accounts_by_provider(self.provider.clone()).unwrap();
|
||||
|
||||
for account in accounts.into_iter() {
|
||||
self.add_account(&account);
|
||||
}*/
|
||||
}
|
||||
|
||||
fn add_account(&self, account: &Account) {
|
||||
let sort_by = self.sort_by.clone();
|
||||
let sort_order = self.sort_order.clone();
|
||||
self.model.insert_sorted(account, move |a, b| {
|
||||
Self::accounts_cmp(a, b, sort_by.borrow().clone(), sort_order.borrow().clone())
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get_count(&self) -> u32 {
|
||||
self.model.get_n_items()
|
||||
}
|
||||
|
||||
pub fn set_sorting(&self, sort_by: Option<SortBy>, sort_order: Option<SortOrder>) {
|
||||
let sort_by = match sort_by {
|
||||
Some(sort_by) => {
|
||||
self.sort_by.replace(sort_by.clone());
|
||||
sort_by
|
||||
}
|
||||
None => self.sort_by.borrow().clone(),
|
||||
};
|
||||
|
||||
let sort_order = match sort_order {
|
||||
Some(sort_order) => {
|
||||
self.sort_order.replace(sort_order.clone());
|
||||
sort_order
|
||||
}
|
||||
None => self.sort_order.borrow().clone(),
|
||||
};
|
||||
self.model
|
||||
.sort(move |a, b| Self::accounts_cmp(a, b, sort_by.clone(), sort_order.clone()));
|
||||
}
|
||||
|
||||
fn accounts_cmp(
|
||||
a: &glib::Object,
|
||||
b: &glib::Object,
|
||||
sort_by: SortBy,
|
||||
sort_order: SortOrder,
|
||||
) -> std::cmp::Ordering {
|
||||
let mut account_a: &Account = a.downcast_ref::<Account>().unwrap();
|
||||
let mut account_b: &Account = b.downcast_ref::<Account>().unwrap();
|
||||
|
||||
if sort_order == SortOrder::Desc {
|
||||
let tmp = account_a;
|
||||
account_a = account_b;
|
||||
account_b = tmp;
|
||||
}
|
||||
/*match sort_by {
|
||||
SortBy::Name => account_a.get_title().cmp(&account_b.get_title()),
|
||||
SortBy::Date => account_a.get_created_at().cmp(&account_b.get_created_at()),
|
||||
}*/
|
||||
account_a.name().cmp(&account_b.name())
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
mod account;
|
||||
mod accounts;
|
||||
mod algorithm;
|
||||
pub mod database;
|
||||
mod favicon;
|
||||
|
@ -7,7 +6,6 @@ mod provider;
|
|||
mod providers;
|
||||
|
||||
pub use self::account::Account;
|
||||
pub use self::accounts::AccountsModel;
|
||||
pub use self::algorithm::Algorithm;
|
||||
pub use self::favicon::{FaviconError, FaviconScrapper};
|
||||
pub use self::provider::Provider;
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::schema::providers;
|
|||
use anyhow::Result;
|
||||
use diesel::QueryDsl;
|
||||
use diesel::RunQueryDsl;
|
||||
use gio::prelude::*;
|
||||
use gio::FileExt;
|
||||
use glib::subclass;
|
||||
use glib::subclass::prelude::*;
|
||||
|
@ -47,7 +48,7 @@ pub struct ProviderPriv {
|
|||
pub website: RefCell<Option<String>>,
|
||||
pub help_url: RefCell<Option<String>>,
|
||||
pub image_uri: RefCell<Option<String>>,
|
||||
pub accounts: RefCell<Vec<Account>>,
|
||||
pub accounts: gio::ListStore,
|
||||
}
|
||||
|
||||
static PROPERTIES: [subclass::Property; 8] = [
|
||||
|
@ -58,17 +59,11 @@ static PROPERTIES: [subclass::Property; 8] = [
|
|||
glib::ParamSpec::string(name, "name", "Name", None, glib::ParamFlags::READWRITE)
|
||||
}),
|
||||
subclass::Property("accounts", |name| {
|
||||
glib::ParamSpec::value_array(
|
||||
glib::ParamSpec::object(
|
||||
name,
|
||||
"accounts",
|
||||
"accounts",
|
||||
&glib::ParamSpec::object(
|
||||
"account",
|
||||
"account",
|
||||
"account",
|
||||
Account::static_type(),
|
||||
glib::ParamFlags::READWRITE,
|
||||
),
|
||||
gio::ListModel::static_type(),
|
||||
glib::ParamFlags::READWRITE,
|
||||
)
|
||||
}),
|
||||
|
@ -142,7 +137,7 @@ impl ObjectSubclass for ProviderPriv {
|
|||
image_uri: RefCell::new(None),
|
||||
algorithm: RefCell::new(Algorithm::OTP.to_string()),
|
||||
period: Cell::new(30),
|
||||
accounts: RefCell::new(Vec::new()),
|
||||
accounts: gio::ListStore::new(Account::static_type()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -272,7 +267,7 @@ impl Provider {
|
|||
.map(From::from)
|
||||
.map(|p: Provider| {
|
||||
let accounts = Account::load(&p).unwrap();
|
||||
p.set_accounts(accounts);
|
||||
accounts.iter().for_each(|a| p.add_account(a));
|
||||
p
|
||||
})
|
||||
.collect::<Vec<Provider>>();
|
||||
|
@ -375,13 +370,20 @@ impl Provider {
|
|||
|
||||
pub fn has_accounts(&self) -> bool {
|
||||
let priv_ = ProviderPriv::from_instance(self);
|
||||
!priv_.accounts.borrow().is_empty()
|
||||
priv_.accounts.get_n_items() != 0
|
||||
}
|
||||
|
||||
fn set_accounts(&self, accounts: Vec<Account>) {
|
||||
pub fn add_account(&self, account: &Account) {
|
||||
let priv_ = ProviderPriv::from_instance(self);
|
||||
priv_.accounts.borrow_mut().clone_from(&accounts);
|
||||
priv_.accounts.append(account);
|
||||
}
|
||||
|
||||
pub fn accounts(&self) -> &gio::ListStore {
|
||||
let priv_ = ProviderPriv::from_instance(self);
|
||||
&priv_.accounts
|
||||
}
|
||||
|
||||
fn remove_account(&self, account: &Account) {}
|
||||
}
|
||||
|
||||
impl From<DiProvider> for Provider {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use super::account::Account;
|
||||
use super::provider::Provider;
|
||||
use gio::prelude::*;
|
||||
use glib::StaticType;
|
||||
|
@ -53,10 +54,26 @@ impl ProvidersModel {
|
|||
}
|
||||
|
||||
pub fn add_provider(&self, provider: &Provider) {
|
||||
//let accounts_model = AccountsModel::from_provider(&provider);
|
||||
self.model.append(provider);
|
||||
}
|
||||
|
||||
pub fn add_account(&self, account: &Account, provider: &Provider) {
|
||||
let mut found = false;
|
||||
for pos in 0..self.count() {
|
||||
let obj = self.model.get_object(pos).unwrap();
|
||||
let p = obj.downcast_ref::<Provider>().unwrap();
|
||||
if p.id() == provider.id() {
|
||||
found = true;
|
||||
p.add_account(account);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
provider.add_account(account);
|
||||
self.add_provider(provider);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count(&self) -> u32 {
|
||||
self.model.get_n_items()
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ pub struct AddAccountDialog {
|
|||
}
|
||||
|
||||
impl AddAccountDialog {
|
||||
pub fn new(global_sender: Sender<Action>) -> Rc<Self> {
|
||||
pub fn new(model: Rc<ProvidersModel>, global_sender: Sender<Action>) -> Rc<Self> {
|
||||
let builder = gtk::Builder::from_resource("/com/belmoussaoui/Authenticator/add_account.ui");
|
||||
get_widget!(builder, libhandy::Window, add_dialog);
|
||||
|
||||
|
@ -44,7 +44,7 @@ impl AddAccountDialog {
|
|||
sender,
|
||||
receiver,
|
||||
actions,
|
||||
model: Rc::new(ProvidersModel::new()),
|
||||
model,
|
||||
selected_provider: Rc::new(RefCell::new(None)),
|
||||
});
|
||||
|
||||
|
@ -71,7 +71,7 @@ impl AddAccountDialog {
|
|||
token_entry.connect_changed(validate_entries);
|
||||
}
|
||||
|
||||
fn scan_qr(&self) {
|
||||
fn scan_qr(&self) -> Result<()> {
|
||||
qrcode::screenshot_area(
|
||||
clone!(@strong self.builder as builder, @strong self.model as model,
|
||||
@strong self.sender as sender => move |screenshot| {
|
||||
|
@ -86,8 +86,8 @@ impl AddAccountDialog {
|
|||
}
|
||||
}
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn save(&self) -> Result<()> {
|
||||
|
@ -123,7 +123,10 @@ impl AddAccountDialog {
|
|||
.unwrap();
|
||||
|
||||
let account = Account::create(&username, &token, provider.id())?;
|
||||
send!(self.global_sender, Action::AccountCreated(account));
|
||||
send!(
|
||||
self.global_sender,
|
||||
Action::AccountCreated(account, provider)
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -235,9 +238,13 @@ impl AddAccountDialog {
|
|||
}
|
||||
AddAccountAction::SetProvider(p) => self.set_provider(p),
|
||||
AddAccountAction::Save => {
|
||||
self.save().unwrap();
|
||||
if self.save().is_ok() {
|
||||
self.widget.close();
|
||||
}
|
||||
}
|
||||
AddAccountAction::ScanQR => {
|
||||
self.scan_qr();
|
||||
}
|
||||
AddAccountAction::ScanQR => self.scan_qr(),
|
||||
};
|
||||
glib::Continue(true)
|
||||
}
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
use gtk::prelude::*;
|
||||
|
||||
use glib::Sender;
|
||||
|
||||
use crate::application::Action;
|
||||
use crate::models::{Account, AccountsModel, Provider};
|
||||
use crate::widgets::accounts::AccountRow;
|
||||
|
||||
pub struct AccountsList<'a> {
|
||||
pub widget: gtk::Box,
|
||||
builder: gtk::Builder,
|
||||
sender: Sender<Action>,
|
||||
model: &'a AccountsModel,
|
||||
provider: &'a Provider,
|
||||
}
|
||||
|
||||
/*
|
||||
ProvidersList -> Vec<AccountsList>
|
||||
*/
|
||||
impl<'a> AccountsList<'a> {
|
||||
pub fn new(model: &'a AccountsModel, provider: &'a Provider, sender: Sender<Action>) -> Self {
|
||||
let builder =
|
||||
gtk::Builder::from_resource("/com/belmoussaoui/Authenticator/accounts_list.ui");
|
||||
get_widget!(builder, gtk::Box, accounts_list);
|
||||
|
||||
let accounts = Self {
|
||||
widget: accounts_list,
|
||||
builder,
|
||||
sender,
|
||||
model,
|
||||
provider,
|
||||
};
|
||||
accounts.init();
|
||||
accounts
|
||||
}
|
||||
|
||||
fn init(&self) {
|
||||
get_widget!(self.builder, gtk::Label, provider_name);
|
||||
provider_name.set_text(&self.provider.name());
|
||||
|
||||
get_widget!(self.builder, gtk::ListBox, listbox);
|
||||
listbox.bind_model(
|
||||
Some(&self.model.model),
|
||||
Some(Box::new(
|
||||
clone!(@strong self.sender as sender => move |account: &glib::Object| {
|
||||
let account: &Account = account
|
||||
.downcast_ref::<Account>()
|
||||
.unwrap();
|
||||
let row = AccountRow::new(account, sender.clone());
|
||||
/*row.set_on_click_callback(move |_, _| {
|
||||
// sender.send(Action::LoadChapter(chapter.clone())).unwrap();
|
||||
Inhibit(false)
|
||||
});*/
|
||||
row.widget.upcast::<gtk::Widget>()
|
||||
}),
|
||||
)),
|
||||
);
|
||||
|
||||
listbox.set_header_func(Some(Box::new(
|
||||
move |row1: >k::ListBoxRow, row2: Option<>k::ListBoxRow>| {
|
||||
if row2.is_some() {
|
||||
let separator = gtk::Separator::new(gtk::Orientation::Horizontal);
|
||||
row1.set_header(Some(&separator));
|
||||
}
|
||||
},
|
||||
)));
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
mod add;
|
||||
mod list;
|
||||
mod row;
|
||||
|
||||
pub use self::add::AddAccountDialog;
|
||||
pub use self::list::AccountsList;
|
||||
pub use self::row::AccountRow;
|
||||
|
|
|
@ -2,6 +2,6 @@ mod accounts;
|
|||
mod providers;
|
||||
mod window;
|
||||
|
||||
pub use self::accounts::{AccountsList, AddAccountDialog};
|
||||
pub use self::accounts::AddAccountDialog;
|
||||
pub use self::providers::ProvidersList;
|
||||
pub use self::window::{View, Window};
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::application::Action;
|
||||
use crate::models::{Account, Provider, ProvidersModel};
|
||||
use crate::widgets::accounts::AccountRow;
|
||||
use glib::Sender;
|
||||
use gtk::prelude::*;
|
||||
|
||||
use crate::application::Action;
|
||||
use crate::models::{Provider, ProvidersModel};
|
||||
|
||||
pub struct ProvidersList {
|
||||
pub widget: gtk::Box,
|
||||
builder: gtk::Builder,
|
||||
|
@ -36,11 +36,13 @@ impl ProvidersList {
|
|||
|
||||
providers_list.bind_model(
|
||||
Some(&providers_model),
|
||||
Some(Box::new(move |obj| {
|
||||
let provider = obj.downcast_ref::<Provider>().unwrap();
|
||||
let row = ProviderRow::new(provider);
|
||||
row.widget.upcast::<gtk::Widget>()
|
||||
})),
|
||||
Some(Box::new(
|
||||
clone!(@strong self.sender as sender => move |obj| {
|
||||
let provider = obj.downcast_ref::<Provider>().unwrap();
|
||||
let row = ProviderRow::new(provider, sender.clone());
|
||||
row.widget.upcast::<gtk::Widget>()
|
||||
}),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -49,16 +51,18 @@ pub struct ProviderRow<'a> {
|
|||
pub widget: gtk::ListBoxRow,
|
||||
provider: &'a Provider,
|
||||
builder: gtk::Builder,
|
||||
sender: Sender<Action>,
|
||||
}
|
||||
|
||||
impl<'a> ProviderRow<'a> {
|
||||
pub fn new(provider: &'a Provider) -> Self {
|
||||
pub fn new(provider: &'a Provider, sender: Sender<Action>) -> Self {
|
||||
let builder =
|
||||
gtk::Builder::from_resource("/com/belmoussaoui/Authenticator/provider_row.ui");
|
||||
get_widget!(builder, gtk::ListBoxRow, provider_row);
|
||||
let row = Self {
|
||||
widget: provider_row,
|
||||
builder,
|
||||
sender,
|
||||
provider,
|
||||
};
|
||||
row.init();
|
||||
|
@ -72,5 +76,23 @@ impl<'a> ProviderRow<'a> {
|
|||
.bind_property("name", &name, "label")
|
||||
.flags(glib::BindingFlags::DEFAULT | glib::BindingFlags::SYNC_CREATE)
|
||||
.build();
|
||||
|
||||
get_widget!(self.builder, gtk::ListBox, accounts_list);
|
||||
accounts_list.bind_model(
|
||||
Some(self.provider.accounts()),
|
||||
Some(Box::new(
|
||||
clone!(@strong self.sender as sender => move |account: &glib::Object| {
|
||||
let account: &Account = account
|
||||
.downcast_ref::<Account>()
|
||||
.unwrap();
|
||||
let row = AccountRow::new(account, sender.clone());
|
||||
/*row.set_on_click_callback(move |_, _| {
|
||||
// sender.send(Action::LoadChapter(chapter.clone())).unwrap();
|
||||
Inhibit(false)
|
||||
});*/
|
||||
row.widget.upcast::<gtk::Widget>()
|
||||
}),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use glib::{signal::Inhibit, Sender};
|
|||
use gtk::prelude::*;
|
||||
use gtk::subclass::prelude::{WidgetImpl, WindowImpl};
|
||||
use libhandy::prelude::*;
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub enum View {
|
||||
|
@ -34,7 +35,6 @@ impl ObjectSubclass for WindowPrivate {
|
|||
fn new() -> Self {
|
||||
let builder = gtk::Builder::from_resource("/com/belmoussaoui/Authenticator/window.ui");
|
||||
let settings = gio::Settings::new(APP_ID);
|
||||
|
||||
Self { builder, settings }
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ glib_wrapper! {
|
|||
}
|
||||
|
||||
impl Window {
|
||||
pub fn new(sender: Sender<Action>, app: &Application) -> Self {
|
||||
pub fn new(model: Rc<ProvidersModel>, sender: Sender<Action>, app: &Application) -> Self {
|
||||
let window = glib::Object::new(Window::static_type(), &[("application", app)])
|
||||
.unwrap()
|
||||
.downcast::<Window>()
|
||||
|
@ -71,7 +71,7 @@ impl Window {
|
|||
if PROFILE == "Devel" {
|
||||
window.get_style_context().add_class("devel");
|
||||
}
|
||||
window.init(sender.clone());
|
||||
window.init(model, sender.clone());
|
||||
window.setup_actions(sender.clone());
|
||||
window.set_view(View::Accounts); // Start by default in an empty state
|
||||
window
|
||||
|
@ -91,7 +91,7 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
fn init(&self, sender: Sender<Action>) {
|
||||
fn init(&self, model: Rc<ProvidersModel>, sender: Sender<Action>) {
|
||||
let self_ = WindowPrivate::from_instance(self);
|
||||
// load latest window state
|
||||
window_state::load(&self, &self_.settings);
|
||||
|
@ -105,19 +105,18 @@ impl Window {
|
|||
get_widget!(builder, gtk::ShortcutsWindow, shortcuts);
|
||||
self.set_help_overlay(Some(&shortcuts));
|
||||
|
||||
let providers_model = ProvidersModel::new();
|
||||
|
||||
get_widget!(self_.builder, libhandy::Leaflet, deck);
|
||||
let providers_list = ProvidersList::new(&providers_model, sender.clone());
|
||||
let providers_list = ProvidersList::new(&model, sender.clone());
|
||||
get_widget!(self_.builder, gtk::Box, container);
|
||||
container.append(&providers_list.widget);
|
||||
/*get_widget!(self.builder, gtk::Box, providers_container);
|
||||
|
||||
providers_container.append(&providers_list.widget);
|
||||
if providers_list.model.borrow().get_count() != 0 {
|
||||
send!(self.sender, Action::ViewAccounts);
|
||||
}*/
|
||||
get_widget!(self_.builder, gtk::SearchBar, search_bar);
|
||||
get_widget!(self_.builder, gtk::ToggleButton, search_btn);
|
||||
search_btn
|
||||
.bind_property("active", &search_bar, "search-mode-enabled")
|
||||
.flags(glib::BindingFlags::BIDIRECTIONAL | glib::BindingFlags::SYNC_CREATE)
|
||||
.build();
|
||||
|
||||
get_widget!(self_.builder, libhandy::Leaflet, deck);
|
||||
libhandy::ApplicationWindowExt::set_child(self, Some(&deck));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue