mirror of
https://gitlab.gnome.org/World/Authenticator.git
synced 2025-03-04 08:44:40 +01:00
account edit: allow changing provider
This commit is contained in:
parent
82812d2ed3
commit
7b06e09f20
5 changed files with 139 additions and 21 deletions
|
@ -1,5 +1,16 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<object class="GtkEntryCompletion" id="provider_completion">
|
||||
<property name="minimum-key-length">1</property>
|
||||
<property name="text-column">1</property>
|
||||
<property name="inline-selection">True</property>
|
||||
<child>
|
||||
<object class="GtkCellRendererText" />
|
||||
<attributes>
|
||||
<attribute name="text">1</attribute>
|
||||
</attributes>
|
||||
</child>
|
||||
</object>
|
||||
<template parent="GtkBox" class="AccountDetailsPage">
|
||||
<property name="hexpand">True</property>
|
||||
<property name="vexpand">True</property>
|
||||
|
@ -109,8 +120,31 @@
|
|||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Provider</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="provider_label">
|
||||
<property name="halign">end</property>
|
||||
<object class="GtkStack" id="provider_stack">
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">display</property>
|
||||
<property name="child">
|
||||
<object class="GtkLabel" id="provider_label">
|
||||
<property name="halign">end</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">edit</property>
|
||||
<property name="child">
|
||||
<object class="GtkEntry" id="provider_entry">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
<property name="completion">provider_completion</property>
|
||||
<property name="enable-emoji-completion">True</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
|
@ -336,6 +336,19 @@ impl Account {
|
|||
self.property("provider")
|
||||
}
|
||||
|
||||
pub fn set_provider(&self, provider: &Provider) -> Result<()> {
|
||||
let db = database::connection();
|
||||
let conn = db.get()?;
|
||||
|
||||
let target = accounts::table.filter(accounts::columns::id.eq(self.id() as i32));
|
||||
diesel::update(target)
|
||||
.set(accounts::columns::provider_id.eq(provider.id() as i32))
|
||||
.execute(&conn)?;
|
||||
|
||||
self.set_property("provider", provider);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn counter(&self) -> u32 {
|
||||
self.imp().counter.get()
|
||||
}
|
||||
|
|
|
@ -684,7 +684,7 @@ impl Provider {
|
|||
self.imp().filter_model.set_filter(Some(&filter));
|
||||
}
|
||||
|
||||
pub fn remove_account(&self, account: Account) {
|
||||
pub fn remove_account(&self, account: &Account) {
|
||||
let imp = self.imp();
|
||||
if let Some(pos) = imp.accounts.find_position_by_id(account.id()) {
|
||||
imp.accounts.remove(pos);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::qrcode_paintable::QRCodePaintable;
|
||||
use crate::{
|
||||
models::{Account, OTPMethod},
|
||||
models::{Account, OTPMethod, Provider, ProvidersModel},
|
||||
widgets::UrlRow,
|
||||
};
|
||||
use gettextrs::gettext;
|
||||
|
@ -12,11 +12,14 @@ use gtk::{
|
|||
CompositeTemplate,
|
||||
};
|
||||
mod imp {
|
||||
use crate::widgets::{editable_label::EditableSpin, EditableLabel};
|
||||
use crate::{
|
||||
models::Provider,
|
||||
widgets::{editable_label::EditableSpin, EditableLabel},
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use glib::subclass::{self, Signal};
|
||||
use once_cell::sync::Lazy;
|
||||
use once_cell::sync::{Lazy, OnceCell};
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
|
@ -52,6 +55,14 @@ mod imp {
|
|||
pub edit_stack: TemplateChild<gtk::Stack>,
|
||||
pub qrcode_paintable: QRCodePaintable,
|
||||
pub account: RefCell<Option<Account>>,
|
||||
#[template_child]
|
||||
pub provider_stack: TemplateChild<gtk::Stack>,
|
||||
#[template_child]
|
||||
pub provider_completion: TemplateChild<gtk::EntryCompletion>,
|
||||
#[template_child]
|
||||
pub provider_entry: TemplateChild<gtk::Entry>,
|
||||
pub selected_provider: RefCell<Option<Provider>>,
|
||||
pub providers_model: OnceCell<ProvidersModel>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
|
@ -83,6 +94,7 @@ mod imp {
|
|||
imp.edit_stack.set_visible_child_name("edit");
|
||||
imp.account_label.stop_editing(false);
|
||||
imp.counter_label.stop_editing(false);
|
||||
imp.provider_stack.set_visible_child_name("display");
|
||||
imp.edit_stack.grab_focus();
|
||||
} else {
|
||||
page.activate_action("win.back", None).unwrap();
|
||||
|
@ -105,13 +117,18 @@ mod imp {
|
|||
impl ObjectImpl for AccountDetailsPage {
|
||||
fn signals() -> &'static [Signal] {
|
||||
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
||||
vec![Signal::builder(
|
||||
"removed",
|
||||
&[Account::static_type().into()],
|
||||
<()>::static_type().into(),
|
||||
)
|
||||
.flags(glib::SignalFlags::ACTION)
|
||||
.build()]
|
||||
vec![
|
||||
Signal::builder(
|
||||
"removed",
|
||||
&[Account::static_type().into()],
|
||||
<()>::static_type().into(),
|
||||
)
|
||||
.flags(glib::SignalFlags::ACTION)
|
||||
.build(),
|
||||
Signal::builder("provider-changed", &[], <()>::static_type().into())
|
||||
.flags(glib::SignalFlags::ACTION)
|
||||
.build(),
|
||||
]
|
||||
});
|
||||
SIGNALS.as_ref()
|
||||
}
|
||||
|
@ -126,6 +143,8 @@ mod imp {
|
|||
self.edit_stack.set_visible_child_name("edit");
|
||||
self.account_label.stop_editing(false);
|
||||
self.counter_label.stop_editing(false);
|
||||
self.provider_stack.set_visible_child_name("display");
|
||||
self.provider_entry.set_text("");
|
||||
self.parent_unmap(widget);
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +166,19 @@ impl AccountDetailsPage {
|
|||
imp.qrcode_picture
|
||||
.set_paintable(Some(&imp.qrcode_paintable));
|
||||
imp.counter_label.set_adjustment(1, u32::MAX);
|
||||
|
||||
imp.provider_completion.connect_match_selected(
|
||||
clone!(@weak self as page => @default-return gtk::Inhibit(false), move |_, store, iter| {
|
||||
let provider_id = store.get::<u32>(iter, 0);
|
||||
let model = page.imp().providers_model.get().unwrap();
|
||||
let provider = model.find_by_id(provider_id);
|
||||
page.set_provider(provider.unwrap_or_else(|| {
|
||||
page.imp().account.borrow().as_ref().unwrap().provider()
|
||||
}));
|
||||
|
||||
gtk::Inhibit(false)
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
fn delete_account(&self) {
|
||||
|
@ -176,9 +208,23 @@ impl AccountDetailsPage {
|
|||
let qr_code = account.qr_code();
|
||||
imp.qrcode_paintable.set_qrcode(qr_code);
|
||||
|
||||
let provider = account.provider();
|
||||
|
||||
if account.provider().method() == OTPMethod::HOTP {
|
||||
imp.counter_label.set_text(account.counter());
|
||||
}
|
||||
self.set_provider(account.provider());
|
||||
imp.account_label.set_text(&account.name());
|
||||
imp.account.replace(Some(account.clone()));
|
||||
}
|
||||
|
||||
pub fn set_providers_model(&self, model: ProvidersModel) {
|
||||
self.imp()
|
||||
.provider_completion
|
||||
.set_model(Some(&model.completion_model()));
|
||||
self.imp().providers_model.set(model).unwrap();
|
||||
}
|
||||
|
||||
fn set_provider(&self, provider: Provider) {
|
||||
let imp = self.imp();
|
||||
imp.provider_label.set_text(&provider.name());
|
||||
imp.algorithm_label
|
||||
.set_text(&provider.algorithm().to_locale_string());
|
||||
|
@ -187,7 +233,6 @@ impl AccountDetailsPage {
|
|||
if provider.method() == OTPMethod::HOTP {
|
||||
imp.counter_row.show();
|
||||
imp.period_row.hide();
|
||||
imp.counter_label.set_text(account.counter());
|
||||
} else {
|
||||
imp.counter_row.hide();
|
||||
imp.period_row.show();
|
||||
|
@ -200,13 +245,13 @@ impl AccountDetailsPage {
|
|||
} else {
|
||||
imp.help_row.hide();
|
||||
}
|
||||
if let Some(ref website) = account.provider().website() {
|
||||
if let Some(ref website) = provider.website() {
|
||||
imp.website_row.set_uri(website);
|
||||
imp.website_row.show();
|
||||
} else {
|
||||
imp.website_row.hide();
|
||||
}
|
||||
imp.account.replace(Some(account.clone()));
|
||||
imp.selected_provider.replace(Some(provider));
|
||||
}
|
||||
|
||||
fn set_edit_mode(&self) {
|
||||
|
@ -214,7 +259,10 @@ impl AccountDetailsPage {
|
|||
imp.edit_stack.set_visible_child_name("save");
|
||||
imp.account_label.start_editing();
|
||||
imp.counter_label.start_editing();
|
||||
|
||||
imp.provider_stack.set_visible_child_name("edit");
|
||||
if let Some(account) = imp.account.borrow().as_ref() {
|
||||
imp.provider_entry.set_text(&account.provider().name());
|
||||
}
|
||||
imp.account_label.grab_focus();
|
||||
}
|
||||
|
||||
|
@ -223,10 +271,22 @@ impl AccountDetailsPage {
|
|||
imp.edit_stack.set_visible_child_name("edit");
|
||||
imp.account_label.stop_editing(true);
|
||||
imp.counter_label.stop_editing(true);
|
||||
imp.provider_stack.set_visible_child_name("display");
|
||||
|
||||
if let Some(account) = imp.account.borrow().as_ref() {
|
||||
account.set_name(&imp.account_label.text())?;
|
||||
|
||||
if let Some(selected_provider) = imp.selected_provider.borrow().as_ref() {
|
||||
let current_provider = account.provider();
|
||||
if selected_provider.id() != current_provider.id() {
|
||||
selected_provider.add_account(account);
|
||||
current_provider.remove_account(account);
|
||||
account.set_provider(selected_provider)?;
|
||||
imp.provider_entry.set_text(&selected_provider.name());
|
||||
self.emit_by_name::<()>("provider-changed", &[]);
|
||||
}
|
||||
}
|
||||
|
||||
let old_counter = account.counter();
|
||||
account.set_counter(imp.counter_label.value())?;
|
||||
// regenerate the otp value if the counter value was changed
|
||||
|
|
|
@ -199,7 +199,7 @@ impl Window {
|
|||
fn init(&self, model: ProvidersModel, app: &Application) {
|
||||
let imp = self.imp();
|
||||
imp.model.set(model.clone()).unwrap();
|
||||
imp.providers.set_model(model);
|
||||
imp.providers.set_model(model.clone());
|
||||
imp.providers.connect_local(
|
||||
"shared",
|
||||
false,
|
||||
|
@ -268,6 +268,17 @@ impl Window {
|
|||
title_stack.set_visible_child_name("title");
|
||||
}
|
||||
}));
|
||||
|
||||
imp.account_details.set_providers_model(model);
|
||||
|
||||
imp.account_details.connect_local(
|
||||
"provider-changed",
|
||||
false,
|
||||
clone!(@weak self as window => @default-return None, move |_| {
|
||||
window.providers().refilter();
|
||||
None
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
fn setup_actions(&self, app: &Application) {
|
||||
|
@ -364,7 +375,7 @@ impl Window {
|
|||
let account = args[1].get::<Account>().unwrap();
|
||||
let provider = account.provider();
|
||||
account.delete().unwrap();
|
||||
provider.remove_account(account);
|
||||
provider.remove_account(&account);
|
||||
win.providers().refilter();
|
||||
win.set_view(View::Accounts);
|
||||
None
|
||||
|
|
Loading…
Add table
Reference in a new issue