mirror of
https://gitlab.gnome.org/World/Authenticator.git
synced 2025-03-04 00:34:40 +01:00
Port to new clone! macro
This commit is contained in:
parent
6663f1e399
commit
d5645fb101
14 changed files with 603 additions and 306 deletions
|
@ -72,15 +72,29 @@ mod imp {
|
|||
let window = app.active_window();
|
||||
let preferences = PreferencesWindow::new(model);
|
||||
preferences.set_has_set_password(app.can_be_locked());
|
||||
preferences.connect_restore_completed(clone!(@weak window =>move |_| {
|
||||
window.providers().refilter();
|
||||
window.imp().toast_overlay.add_toast(adw::Toast::new(&gettext("Accounts restored successfully")));
|
||||
}));
|
||||
preferences.connect_has_set_password_notify(clone!(@weak app => move |pref| {
|
||||
app.set_can_be_locked(pref.has_set_password());
|
||||
}));
|
||||
preferences.connect_restore_completed(clone!(
|
||||
#[weak]
|
||||
window,
|
||||
move |_| {
|
||||
window.providers().refilter();
|
||||
window
|
||||
.imp()
|
||||
.toast_overlay
|
||||
.add_toast(adw::Toast::new(&gettext(
|
||||
"Accounts restored successfully",
|
||||
)));
|
||||
}
|
||||
));
|
||||
preferences.connect_has_set_password_notify(clone!(
|
||||
#[weak]
|
||||
app,
|
||||
move |pref| {
|
||||
app.set_can_be_locked(pref.has_set_password());
|
||||
}
|
||||
));
|
||||
preferences.present(Some(&window));
|
||||
}).build();
|
||||
})
|
||||
.build();
|
||||
|
||||
// About
|
||||
let about_action = gio::ActionEntry::builder("about")
|
||||
|
@ -111,9 +125,13 @@ mod imp {
|
|||
let model = &app.imp().model;
|
||||
let window = app.active_window();
|
||||
let providers = ProvidersDialog::new(model);
|
||||
providers.connect_changed(clone!(@weak window => move |_| {
|
||||
window.providers().refilter();
|
||||
}));
|
||||
providers.connect_changed(clone!(
|
||||
#[weak]
|
||||
window,
|
||||
move |_| {
|
||||
window.providers().refilter();
|
||||
}
|
||||
));
|
||||
providers.present(Some(&window));
|
||||
})
|
||||
.build();
|
||||
|
@ -151,21 +169,31 @@ mod imp {
|
|||
}
|
||||
});
|
||||
|
||||
SETTINGS.connect_auto_lock_changed(clone!(@weak app => move |auto_lock| {
|
||||
if auto_lock {
|
||||
app.restart_lock_timeout();
|
||||
} else {
|
||||
app.cancel_lock_timeout();
|
||||
SETTINGS.connect_auto_lock_changed(clone!(
|
||||
#[weak]
|
||||
app,
|
||||
move |auto_lock| {
|
||||
if auto_lock {
|
||||
app.restart_lock_timeout();
|
||||
} else {
|
||||
app.cancel_lock_timeout();
|
||||
}
|
||||
}
|
||||
}));
|
||||
));
|
||||
|
||||
SETTINGS.connect_auto_lock_timeout_changed(clone!(@weak app => move |_| {
|
||||
app.restart_lock_timeout()
|
||||
}));
|
||||
SETTINGS.connect_auto_lock_timeout_changed(clone!(
|
||||
#[weak]
|
||||
app,
|
||||
move |_| app.restart_lock_timeout()
|
||||
));
|
||||
|
||||
spawn(clone!(@strong app => async move {
|
||||
app.start_search_provider().await;
|
||||
}));
|
||||
spawn(clone!(
|
||||
#[strong]
|
||||
app,
|
||||
async move {
|
||||
app.start_search_provider().await;
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
fn activate(&self) {
|
||||
|
@ -331,19 +359,27 @@ impl Application {
|
|||
timeout,
|
||||
None,
|
||||
glib::Priority::HIGH,
|
||||
clone!(@strong tx => move || {
|
||||
let Some(tx) = tx.lock().unwrap().take() else {
|
||||
return glib::ControlFlow::Break;
|
||||
};
|
||||
tx.send(()).unwrap();
|
||||
glib::ControlFlow::Break
|
||||
}),
|
||||
clone!(
|
||||
#[strong]
|
||||
tx,
|
||||
move || {
|
||||
let Some(tx) = tx.lock().unwrap().take() else {
|
||||
return glib::ControlFlow::Break;
|
||||
};
|
||||
tx.send(()).unwrap();
|
||||
glib::ControlFlow::Break
|
||||
}
|
||||
),
|
||||
);
|
||||
spawn(clone!(@strong self as app => async move {
|
||||
if let Ok(()) = rx.await {
|
||||
app.set_is_locked(true);
|
||||
spawn(clone!(
|
||||
#[strong(rename_to = app)]
|
||||
self,
|
||||
async move {
|
||||
if let Ok(()) = rx.await {
|
||||
app.set_is_locked(true);
|
||||
}
|
||||
}
|
||||
}));
|
||||
));
|
||||
id.attach(Some(&glib::MainContext::default()));
|
||||
imp.lock_timeout_id.replace(Some(id));
|
||||
}
|
||||
|
@ -393,9 +429,13 @@ impl Application {
|
|||
};
|
||||
glib::timeout_add_seconds_local_once(
|
||||
provider.period(),
|
||||
glib::clone!(@weak self as app => move || {
|
||||
app.withdraw_notification(&id);
|
||||
}),
|
||||
glib::clone!(
|
||||
#[weak(rename_to = app)]
|
||||
self,
|
||||
move || {
|
||||
app.withdraw_notification(&id);
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
SearchProviderAction::InitialResultSet(terms, sender) => {
|
||||
|
|
|
@ -208,25 +208,30 @@ impl Account {
|
|||
let results = DieselAccount::belonging_to(&dip)
|
||||
.load::<DieselAccount>(&mut conn)?
|
||||
.into_iter()
|
||||
.filter_map(clone!(@strong p => move |account| {
|
||||
match Self::new(
|
||||
account.id as u32,
|
||||
&account.name,
|
||||
&account.token_id,
|
||||
account.counter as u32,
|
||||
&p,
|
||||
None,
|
||||
)
|
||||
{
|
||||
Ok(account) => Some(account),
|
||||
Err(e) => {
|
||||
let name = account.name;
|
||||
let provider = p.name();
|
||||
tracing::error!("Failed to load account '{name}' / '{provider}' with error {e}");
|
||||
None
|
||||
.filter_map(clone!(
|
||||
#[strong]
|
||||
p,
|
||||
move |account| {
|
||||
match Self::new(
|
||||
account.id as u32,
|
||||
&account.name,
|
||||
&account.token_id,
|
||||
account.counter as u32,
|
||||
&p,
|
||||
None,
|
||||
) {
|
||||
Ok(account) => Some(account),
|
||||
Err(e) => {
|
||||
let name = account.name;
|
||||
let provider = p.name();
|
||||
tracing::error!(
|
||||
"Failed to load account '{name}' / '{provider}' with error {e}"
|
||||
);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
));
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
|
|
@ -396,10 +396,16 @@ impl Provider {
|
|||
Method::TOTP | Method::Steam => {
|
||||
let source_id = glib::timeout_add_seconds_local(
|
||||
1,
|
||||
clone!(@weak self as provider => @default-return glib::ControlFlow::Break, move || {
|
||||
provider.tick();
|
||||
glib::ControlFlow::Continue
|
||||
}),
|
||||
clone!(
|
||||
#[weak(rename_to = provider)]
|
||||
self,
|
||||
#[upgrade_or]
|
||||
glib::ControlFlow::Break,
|
||||
move || {
|
||||
provider.tick();
|
||||
glib::ControlFlow::Continue
|
||||
}
|
||||
),
|
||||
);
|
||||
self.imp().tick_callback.replace(Some(source_id));
|
||||
}
|
||||
|
@ -464,15 +470,19 @@ impl Provider {
|
|||
}
|
||||
|
||||
pub fn filter(&self, text: String) {
|
||||
let filter = gtk::CustomFilter::new(
|
||||
glib::clone!(@weak self as provider => @default-return false, move |obj| {
|
||||
let filter = gtk::CustomFilter::new(glib::clone!(
|
||||
#[weak(rename_to = provider)]
|
||||
self,
|
||||
#[upgrade_or]
|
||||
false,
|
||||
move |obj| {
|
||||
let account = obj.downcast_ref::<Account>().unwrap();
|
||||
let account_name = account.name();
|
||||
let provider_name = provider.name();
|
||||
|
||||
Self::tokenize_search(&account_name, &provider_name, &text)
|
||||
}),
|
||||
);
|
||||
}
|
||||
));
|
||||
self.imp().filter_model.set_filter(Some(&filter));
|
||||
}
|
||||
|
||||
|
|
|
@ -120,19 +120,24 @@ mod imp {
|
|||
let provider = aperture::DeviceProvider::instance();
|
||||
self.provider.set(provider.clone()).unwrap();
|
||||
|
||||
self.viewfinder
|
||||
.connect_state_notify(glib::clone!(@weak obj => move |_| {
|
||||
self.viewfinder.connect_state_notify(glib::clone!(
|
||||
#[weak]
|
||||
obj,
|
||||
move |_| {
|
||||
obj.update_viewfinder_state();
|
||||
}));
|
||||
}
|
||||
));
|
||||
obj.update_viewfinder_state();
|
||||
|
||||
self.viewfinder.connect_code_detected(
|
||||
glib::clone!(@weak obj => move|_, code_type, code| {
|
||||
self.viewfinder.connect_code_detected(glib::clone!(
|
||||
#[weak]
|
||||
obj,
|
||||
move |_, code_type, code| {
|
||||
if matches!(code_type, aperture::CodeType::Qr) {
|
||||
obj.emit_by_name::<()>("code-detected", &[&code]);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
));
|
||||
|
||||
let popover = gtk::Popover::new();
|
||||
popover.add_css_class("menu");
|
||||
|
@ -147,34 +152,48 @@ mod imp {
|
|||
.set_child(Some(&camera_row));
|
||||
});
|
||||
let selection = &self.selection;
|
||||
factory.connect_bind(glib::clone!(@weak selection => move |_, item| {
|
||||
let item = item.downcast_ref::<gtk::ListItem>().unwrap();
|
||||
let child = item.child().unwrap();
|
||||
let row = child.downcast_ref::<CameraRow>().unwrap();
|
||||
factory.connect_bind(glib::clone!(
|
||||
#[weak]
|
||||
selection,
|
||||
move |_, item| {
|
||||
let item = item.downcast_ref::<gtk::ListItem>().unwrap();
|
||||
let child = item.child().unwrap();
|
||||
let row = child.downcast_ref::<CameraRow>().unwrap();
|
||||
|
||||
let item = item.item().and_downcast::<aperture::Camera>().unwrap();
|
||||
row.set_label(&item.display_name());
|
||||
let item = item.item().and_downcast::<aperture::Camera>().unwrap();
|
||||
row.set_label(&item.display_name());
|
||||
|
||||
selection.connect_selected_item_notify(glib::clone!(@weak row, @weak item => move |selection| {
|
||||
if let Some(selected_item) = selection.selected_item() {
|
||||
row.set_selected(selected_item == item);
|
||||
} else {
|
||||
row.set_selected(false);
|
||||
}
|
||||
}));
|
||||
}));
|
||||
selection.connect_selected_item_notify(glib::clone!(
|
||||
#[weak]
|
||||
row,
|
||||
#[weak]
|
||||
item,
|
||||
move |selection| {
|
||||
if let Some(selected_item) = selection.selected_item() {
|
||||
row.set_selected(selected_item == item);
|
||||
} else {
|
||||
row.set_selected(false);
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
));
|
||||
let list_view = gtk::ListView::new(Some(self.selection.clone()), Some(factory));
|
||||
popover.set_child(Some(&list_view));
|
||||
|
||||
self.selection.connect_selected_item_notify(
|
||||
glib::clone!(@weak obj, @weak popover => move |selection| {
|
||||
self.selection.connect_selected_item_notify(glib::clone!(
|
||||
#[weak]
|
||||
obj,
|
||||
#[weak]
|
||||
popover,
|
||||
move |selection| {
|
||||
if let Some(selected_item) = selection.selected_item() {
|
||||
let camera = selected_item.downcast_ref::<aperture::Camera>();
|
||||
obj.imp().viewfinder.set_camera(camera);
|
||||
}
|
||||
popover.popdown();
|
||||
}),
|
||||
);
|
||||
}
|
||||
));
|
||||
|
||||
self.camera_selection_button.set_popover(Some(&popover));
|
||||
}
|
||||
|
@ -198,10 +217,16 @@ impl Camera {
|
|||
self.connect_local(
|
||||
"close",
|
||||
false,
|
||||
clone!(@weak self as camera => @default-return None, move |_| {
|
||||
callback(&camera);
|
||||
None
|
||||
}),
|
||||
clone!(
|
||||
#[weak(rename_to = camera)]
|
||||
self,
|
||||
#[upgrade_or]
|
||||
None,
|
||||
move |_| {
|
||||
callback(&camera);
|
||||
None
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -212,11 +237,17 @@ impl Camera {
|
|||
self.connect_local(
|
||||
"code-detected",
|
||||
false,
|
||||
clone!(@weak self as camera => @default-return None, move |args| {
|
||||
let code = args[1].get::<String>().unwrap();
|
||||
callback(&camera, code);
|
||||
None
|
||||
}),
|
||||
clone!(
|
||||
#[weak(rename_to = camera)]
|
||||
self,
|
||||
#[upgrade_or]
|
||||
None,
|
||||
move |args| {
|
||||
let code = args[1].get::<String>().unwrap();
|
||||
callback(&camera, code);
|
||||
None
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -51,11 +51,17 @@ impl ErrorRevealer {
|
|||
imp.revealer.set_reveal_child(true);
|
||||
glib::timeout_add_seconds_local(
|
||||
2,
|
||||
glib::clone!(@weak self as error_revealer => @default-return glib::ControlFlow::Break, move || {
|
||||
error_revealer.imp().revealer.set_reveal_child(false);
|
||||
error_revealer.set_visible(false);
|
||||
glib::ControlFlow::Break
|
||||
}),
|
||||
glib::clone!(
|
||||
#[weak(rename_to = error_revealer)]
|
||||
self,
|
||||
#[upgrade_or]
|
||||
glib::ControlFlow::Break,
|
||||
move || {
|
||||
error_revealer.imp().revealer.set_reveal_child(false);
|
||||
error_revealer.set_visible(false);
|
||||
glib::ControlFlow::Break
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,8 +78,13 @@ impl CameraPage {
|
|||
let src = Rc::new(Cell::new(None));
|
||||
|
||||
src.set(Some(imp.camera.connect_code_detected(clone!(
|
||||
@weak self as camera_page, @strong src, @strong tx
|
||||
=> move |_, code| {
|
||||
#[weak(rename_to = camera_page)]
|
||||
self,
|
||||
#[strong]
|
||||
src,
|
||||
#[strong]
|
||||
tx,
|
||||
move |_, code| {
|
||||
match tx.take().unwrap().send(code) {
|
||||
Ok(()) => (),
|
||||
Err(_) => {
|
||||
|
@ -126,8 +131,13 @@ impl CameraPage {
|
|||
let src = Rc::new(Cell::new(None));
|
||||
|
||||
src.set(Some(imp.camera.connect_code_detected(clone!(
|
||||
@weak self as camera_page, @strong src, @strong tx
|
||||
=> move |_, code| {
|
||||
#[weak(rename_to = camera_page)]
|
||||
self,
|
||||
#[strong]
|
||||
src,
|
||||
#[strong]
|
||||
tx,
|
||||
move |_, code| {
|
||||
match tx.take().unwrap().send(code) {
|
||||
Ok(()) => (),
|
||||
Err(_) => {
|
||||
|
|
|
@ -69,9 +69,13 @@ mod imp {
|
|||
self.status_page.set_icon_name(Some(config::APP_ID));
|
||||
page.reset_validation();
|
||||
// Reset the validation whenever the password state changes
|
||||
page.connect_has_set_password_notify(clone!(@weak page => move |_| {
|
||||
page.reset_validation();
|
||||
}));
|
||||
page.connect_has_set_password_notify(clone!(
|
||||
#[weak]
|
||||
page,
|
||||
move |_| {
|
||||
page.reset_validation();
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,8 +127,11 @@ impl PasswordPage {
|
|||
fn reset_validation(&self) {
|
||||
let imp = self.imp();
|
||||
if self.has_set_password() {
|
||||
imp.current_password_entry
|
||||
.connect_changed(clone!(@weak self as page => move |_| page.validate(None)));
|
||||
imp.current_password_entry.connect_changed(clone!(
|
||||
#[weak(rename_to = page)]
|
||||
self,
|
||||
move |_| page.validate(None)
|
||||
));
|
||||
} else if let Some(handler_id) = imp.default_password_signal.borrow_mut().take() {
|
||||
imp.current_password_entry.disconnect(handler_id);
|
||||
}
|
||||
|
@ -133,18 +140,34 @@ impl PasswordPage {
|
|||
fn setup_actions(&self) {
|
||||
let actions = self.actions();
|
||||
let save_password = gio::ActionEntry::builder("save_password")
|
||||
.activate(clone!(@weak self as page => move |_, _, _| {
|
||||
spawn(clone!(@weak page => async move {
|
||||
page.save().await;
|
||||
}));
|
||||
}))
|
||||
.activate(clone!(
|
||||
#[weak(rename_to = page)]
|
||||
self,
|
||||
move |_, _, _| {
|
||||
spawn(clone!(
|
||||
#[weak]
|
||||
page,
|
||||
async move {
|
||||
page.save().await;
|
||||
}
|
||||
));
|
||||
}
|
||||
))
|
||||
.build();
|
||||
let reset_password = gio::ActionEntry::builder("reset_password")
|
||||
.activate(clone!(@weak self as page => move |_, _, _| {
|
||||
spawn(clone!(@weak page => async move {
|
||||
page.reset_password().await;
|
||||
}));
|
||||
}))
|
||||
.activate(clone!(
|
||||
#[weak(rename_to = page)]
|
||||
self,
|
||||
move |_, _, _| {
|
||||
spawn(clone!(
|
||||
#[weak]
|
||||
page,
|
||||
async move {
|
||||
page.reset_password().await;
|
||||
}
|
||||
));
|
||||
}
|
||||
))
|
||||
.build();
|
||||
actions.add_action_entries([save_password, reset_password]);
|
||||
|
||||
|
|
|
@ -132,10 +132,16 @@ impl PreferencesWindow {
|
|||
self.connect_local(
|
||||
"restore-completed",
|
||||
false,
|
||||
clone!(@weak self as win => @default-return None, move |_| {
|
||||
callback(&win);
|
||||
None
|
||||
}),
|
||||
clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
#[upgrade_or]
|
||||
None,
|
||||
move |_| {
|
||||
callback(&win);
|
||||
None
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -219,14 +225,24 @@ impl PreferencesWindow {
|
|||
}
|
||||
|
||||
let action = gio::ActionEntry::builder(T::IDENTIFIER)
|
||||
.activate(clone!(@weak self as win => move |_, _,_| {
|
||||
spawn(clone!(@weak win => async move {
|
||||
if let Err(err) = win.backup_into_file::<T>(filters).await {
|
||||
tracing::error!("Failed to backup into a file {err}");
|
||||
win.add_toast(adw::Toast::new(&gettext("Failed to create a backup")));
|
||||
}
|
||||
}));
|
||||
}))
|
||||
.activate(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_, _, _| {
|
||||
spawn(clone!(
|
||||
#[weak]
|
||||
win,
|
||||
async move {
|
||||
if let Err(err) = win.backup_into_file::<T>(filters).await {
|
||||
tracing::error!("Failed to backup into a file {err}");
|
||||
win.add_toast(adw::Toast::new(&gettext(
|
||||
"Failed to create a backup",
|
||||
)));
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
))
|
||||
.build();
|
||||
imp.backup_actions.add_action_entries([action]);
|
||||
}
|
||||
|
@ -330,49 +346,94 @@ impl PreferencesWindow {
|
|||
}
|
||||
if T::SCANNABLE {
|
||||
let camera_action = gio::ActionEntry::builder(&format!("{}.camera", T::IDENTIFIER))
|
||||
.activate(clone!(@weak self as win=> move |_, _, _| {
|
||||
win.imp().actions.activate_action("show_camera_page", None);
|
||||
spawn(clone!(@weak win => async move {
|
||||
if let Err(err) = win.restore_from_camera::<T, T::Item>().await {
|
||||
tracing::error!("Failed to restore from camera {err}");
|
||||
win.add_toast(adw::Toast::new(&gettext("Failed to restore from camera")));
|
||||
}
|
||||
}));
|
||||
}))
|
||||
.activate(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_, _, _| {
|
||||
win.imp().actions.activate_action("show_camera_page", None);
|
||||
spawn(clone!(
|
||||
#[weak]
|
||||
win,
|
||||
async move {
|
||||
if let Err(err) = win.restore_from_camera::<T, T::Item>().await {
|
||||
tracing::error!("Failed to restore from camera {err}");
|
||||
win.add_toast(adw::Toast::new(&gettext(
|
||||
"Failed to restore from camera",
|
||||
)));
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
))
|
||||
.build();
|
||||
let screenshot_action =
|
||||
gio::ActionEntry::builder(&format!("{}.screenshot", T::IDENTIFIER))
|
||||
.activate(clone!(@weak self as win => move |_, _, _| {
|
||||
spawn(clone!(@weak win => async move {
|
||||
if let Err(err) = win.restore_from_screenshot::<T, T::Item>().await {
|
||||
tracing::error!("Failed to restore from a screenshot {err}");
|
||||
win.add_toast(adw::Toast::new(&gettext("Failed to restore from a screenshot")));
|
||||
}
|
||||
}));
|
||||
}))
|
||||
.activate(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_, _, _| {
|
||||
spawn(clone!(
|
||||
#[weak]
|
||||
win,
|
||||
async move {
|
||||
if let Err(err) =
|
||||
win.restore_from_screenshot::<T, T::Item>().await
|
||||
{
|
||||
tracing::error!(
|
||||
"Failed to restore from a screenshot {err}"
|
||||
);
|
||||
win.add_toast(adw::Toast::new(&gettext(
|
||||
"Failed to restore from a screenshot",
|
||||
)));
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
))
|
||||
.build();
|
||||
let file_action = gio::ActionEntry::builder(&format!("{}.file", T::IDENTIFIER))
|
||||
.activate(clone!(@weak self as win => move |_, _, _| {
|
||||
spawn(clone!(@weak win => async move {
|
||||
if let Err(err) = win.restore_from_image::<T, T::Item>().await {
|
||||
tracing::error!("Failed to restore from an image {err}");
|
||||
win.add_toast(adw::Toast::new(&gettext("Failed to restore from an image")));
|
||||
}
|
||||
}));
|
||||
}))
|
||||
.activate(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_, _, _| {
|
||||
spawn(clone!(
|
||||
#[weak]
|
||||
win,
|
||||
async move {
|
||||
if let Err(err) = win.restore_from_image::<T, T::Item>().await {
|
||||
tracing::error!("Failed to restore from an image {err}");
|
||||
win.add_toast(adw::Toast::new(&gettext(
|
||||
"Failed to restore from an image",
|
||||
)));
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
))
|
||||
.build();
|
||||
imp.restore_actions
|
||||
.add_action_entries([camera_action, file_action, screenshot_action]);
|
||||
} else {
|
||||
let action = gio::ActionEntry::builder(T::IDENTIFIER)
|
||||
.activate(clone!(@weak self as win => move |_, _, _| {
|
||||
spawn(clone!(@weak win => async move {
|
||||
if let Err(err) = win.restore_from_file::<T, T::Item>(filters).await {
|
||||
tracing::error!("Failed to restore from a file {err}");
|
||||
win.add_toast(adw::Toast::new(&gettext("Failed to restore from a file")));
|
||||
}
|
||||
}));
|
||||
}))
|
||||
.activate(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_, _, _| {
|
||||
spawn(clone!(
|
||||
#[weak]
|
||||
win,
|
||||
async move {
|
||||
if let Err(err) = win.restore_from_file::<T, T::Item>(filters).await
|
||||
{
|
||||
tracing::error!("Failed to restore from a file {err}");
|
||||
win.add_toast(adw::Toast::new(&gettext(
|
||||
"Failed to restore from a file",
|
||||
)));
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
))
|
||||
.build();
|
||||
|
||||
imp.restore_actions.add_action_entries([action]);
|
||||
|
@ -494,42 +555,66 @@ impl PreferencesWindow {
|
|||
fn setup_actions(&self) {
|
||||
let imp = self.imp();
|
||||
|
||||
imp.camera_page
|
||||
.connect_map(clone!(@weak self as win => move |_| {
|
||||
imp.camera_page.connect_map(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_| {
|
||||
win.set_search_enabled(false);
|
||||
}));
|
||||
}
|
||||
));
|
||||
|
||||
imp.camera_page
|
||||
.connect_unmap(clone!(@weak self as win => move |_| {
|
||||
imp.camera_page.connect_unmap(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_| {
|
||||
win.set_search_enabled(true);
|
||||
}));
|
||||
}
|
||||
));
|
||||
|
||||
imp.password_page
|
||||
.connect_map(clone!(@weak self as win => move |_| {
|
||||
imp.password_page.connect_map(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_| {
|
||||
win.set_search_enabled(false);
|
||||
}));
|
||||
}
|
||||
));
|
||||
|
||||
imp.password_page
|
||||
.connect_unmap(clone!(@weak self as win => move |_| {
|
||||
imp.password_page.connect_unmap(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_| {
|
||||
win.set_search_enabled(true);
|
||||
}));
|
||||
}
|
||||
));
|
||||
|
||||
let show_camera_page = gio::ActionEntry::builder("show_camera_page")
|
||||
.activate(clone!(@weak self as win => move |_, _, _| {
|
||||
win.push_subpage(&win.imp().camera_page);
|
||||
}))
|
||||
.activate(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_, _, _| {
|
||||
win.push_subpage(&win.imp().camera_page);
|
||||
}
|
||||
))
|
||||
.build();
|
||||
|
||||
let show_password_page = gio::ActionEntry::builder("show_password_page")
|
||||
.activate(clone!(@weak self as win => move |_, _, _| {
|
||||
win.push_subpage(&win.imp().password_page);
|
||||
}))
|
||||
.activate(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_, _, _| {
|
||||
win.push_subpage(&win.imp().password_page);
|
||||
}
|
||||
))
|
||||
.build();
|
||||
|
||||
let close_page = gio::ActionEntry::builder("close_page")
|
||||
.activate(clone!(@weak self as win => move |_, _, _| {
|
||||
win.pop_subpage();
|
||||
}))
|
||||
.activate(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_, _, _| {
|
||||
win.pop_subpage();
|
||||
}
|
||||
))
|
||||
.build();
|
||||
|
||||
imp.actions
|
||||
|
|
|
@ -92,15 +92,20 @@ mod imp {
|
|||
let obj = self.obj();
|
||||
self.placeholder_page.set_icon_name(Some(config::APP_ID));
|
||||
self.filter_model.set_model(Some(&obj.model()));
|
||||
self.filter_model.connect_items_changed(
|
||||
clone!(@weak obj as dialog => move |model, _, _, _| {
|
||||
self.filter_model.connect_items_changed(clone!(
|
||||
#[weak(rename_to = dialog)]
|
||||
obj,
|
||||
move |model, _, _, _| {
|
||||
if model.n_items() == 0 {
|
||||
dialog.imp().search_stack.set_visible_child_name("no-results");
|
||||
dialog
|
||||
.imp()
|
||||
.search_stack
|
||||
.set_visible_child_name("no-results");
|
||||
} else {
|
||||
dialog.imp().search_stack.set_visible_child_name("results");
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
));
|
||||
|
||||
let sorter = gtk::StringSorter::builder()
|
||||
.ignore_case(true)
|
||||
|
@ -141,10 +146,16 @@ impl ProvidersDialog {
|
|||
self.connect_local(
|
||||
"changed",
|
||||
false,
|
||||
clone!(@weak self as dialog => @default-return None, move |_| {
|
||||
callback(&dialog);
|
||||
None
|
||||
}),
|
||||
clone!(
|
||||
#[weak(rename_to = dialog)]
|
||||
self,
|
||||
#[upgrade_or]
|
||||
None,
|
||||
move |_| {
|
||||
callback(&dialog);
|
||||
None
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -83,10 +83,13 @@ mod imp {
|
|||
self.spinner.start();
|
||||
obj.on_provider_image_changed();
|
||||
}
|
||||
let signal_id =
|
||||
provider.connect_image_uri_notify(clone!(@weak obj as image => move |_| {
|
||||
let signal_id = provider.connect_image_uri_notify(clone!(
|
||||
#[weak(rename_to = image)]
|
||||
obj,
|
||||
move |_| {
|
||||
image.on_provider_image_changed();
|
||||
}));
|
||||
}
|
||||
));
|
||||
self.signal_id.replace(Some(signal_id));
|
||||
return;
|
||||
} else if let (Some(signal_id), Some(provider)) =
|
||||
|
@ -175,38 +178,44 @@ impl ProviderImage {
|
|||
let join_handle = RUNTIME.spawn(future);
|
||||
imp.join_handle.borrow_mut().replace(join_handle);
|
||||
|
||||
spawn(clone!(@weak self as this => async move {
|
||||
let imp = this.imp();
|
||||
imp.was_downloaded.set(true);
|
||||
let image_path = match receiver.await {
|
||||
// TODO: handle network failure and other errors differently
|
||||
Ok(None) => {
|
||||
imp.image.set_icon_name(Some("provider-fallback"));
|
||||
"invalid".to_string()
|
||||
}
|
||||
Ok(Some(cache_name)) => {
|
||||
if imp.size.get() == 32 {
|
||||
imp.image
|
||||
.set_from_file(Some(&FAVICONS_PATH.join(format!("{cache_name}_32x32"))));
|
||||
} else {
|
||||
imp.image
|
||||
.set_from_file(Some(&FAVICONS_PATH.join(format!("{cache_name}_96x96"))));
|
||||
spawn(clone!(
|
||||
#[weak(rename_to = this)]
|
||||
self,
|
||||
async move {
|
||||
let imp = this.imp();
|
||||
imp.was_downloaded.set(true);
|
||||
let image_path = match receiver.await {
|
||||
// TODO: handle network failure and other errors differently
|
||||
Ok(None) => {
|
||||
imp.image.set_icon_name(Some("provider-fallback"));
|
||||
"invalid".to_string()
|
||||
}
|
||||
cache_name
|
||||
Ok(Some(cache_name)) => {
|
||||
if imp.size.get() == 32 {
|
||||
imp.image.set_from_file(Some(
|
||||
&FAVICONS_PATH.join(format!("{cache_name}_32x32")),
|
||||
));
|
||||
} else {
|
||||
imp.image.set_from_file(Some(
|
||||
&FAVICONS_PATH.join(format!("{cache_name}_96x96")),
|
||||
));
|
||||
}
|
||||
cache_name
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to receive data {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let Some(provider) = this.provider() {
|
||||
let guard = provider.freeze_notify();
|
||||
provider.set_image_uri(image_path);
|
||||
drop(guard);
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to receive data {e}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let Some(provider) = this.provider() {
|
||||
let guard = provider.freeze_notify();
|
||||
provider.set_image_uri(image_path);
|
||||
drop(guard);
|
||||
imp.stack.set_visible_child_name("image");
|
||||
imp.spinner.stop();
|
||||
}
|
||||
imp.stack.set_visible_child_name("image");
|
||||
imp.spinner.stop();
|
||||
}));
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,19 +237,28 @@ impl ProviderImage {
|
|||
self.bind_property("size", &*imp.image, "pixel-size")
|
||||
.sync_create()
|
||||
.build();
|
||||
SETTINGS.connect_download_favicons_changed(clone!(@weak self as image => move |state| {
|
||||
if state && !image.imp().was_downloaded.get() {
|
||||
image.fetch();
|
||||
SETTINGS.connect_download_favicons_changed(clone!(
|
||||
#[weak(rename_to = image)]
|
||||
self,
|
||||
move |state| {
|
||||
if state && !image.imp().was_downloaded.get() {
|
||||
image.fetch();
|
||||
}
|
||||
}
|
||||
}));
|
||||
));
|
||||
|
||||
SETTINGS.connect_download_favicons_metered_changed(
|
||||
clone!(@weak self as image => move |state| {
|
||||
SETTINGS.connect_download_favicons_metered_changed(clone!(
|
||||
#[weak(rename_to = image)]
|
||||
self,
|
||||
move |state| {
|
||||
let network_monitor = gio::NetworkMonitor::default();
|
||||
if !image.imp().was_downloaded.get() && (network_monitor.is_network_metered() && state) || !network_monitor.is_network_metered() {
|
||||
image.fetch();
|
||||
}
|
||||
}),
|
||||
);
|
||||
if !image.imp().was_downloaded.get()
|
||||
&& (network_monitor.is_network_metered() && state)
|
||||
|| !network_monitor.is_network_metered()
|
||||
{
|
||||
image.fetch();
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,18 +132,30 @@ impl ProvidersList {
|
|||
|
||||
imp.providers_list.bind_model(
|
||||
Some(&sort_model),
|
||||
clone!(@strong self as list => move |obj| {
|
||||
let provider = obj.downcast_ref::<Provider>().unwrap();
|
||||
let row = ProviderRow::new(provider);
|
||||
row.connect_changed(clone!(@weak list => move |_| {
|
||||
list.refilter();
|
||||
}));
|
||||
row.connect_shared(clone!(@weak list => move |_, account| {
|
||||
list.emit_by_name::<()>("shared", &[&account]);
|
||||
}));
|
||||
clone!(
|
||||
#[strong(rename_to = list)]
|
||||
self,
|
||||
move |obj| {
|
||||
let provider = obj.downcast_ref::<Provider>().unwrap();
|
||||
let row = ProviderRow::new(provider);
|
||||
row.connect_changed(clone!(
|
||||
#[weak]
|
||||
list,
|
||||
move |_| {
|
||||
list.refilter();
|
||||
}
|
||||
));
|
||||
row.connect_shared(clone!(
|
||||
#[weak]
|
||||
list,
|
||||
move |_, account| {
|
||||
list.emit_by_name::<()>("shared", &[&account]);
|
||||
}
|
||||
));
|
||||
|
||||
row.upcast::<gtk::Widget>()
|
||||
}),
|
||||
row.upcast::<gtk::Widget>()
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,10 +93,16 @@ impl ProviderRow {
|
|||
self.connect_local(
|
||||
"changed",
|
||||
false,
|
||||
clone!(@weak self as row => @default-return None, move |_| {
|
||||
callback(&row);
|
||||
None
|
||||
}),
|
||||
clone!(
|
||||
#[weak(rename_to = row)]
|
||||
self,
|
||||
#[upgrade_or]
|
||||
None,
|
||||
move |_| {
|
||||
callback(&row);
|
||||
None
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -107,11 +113,17 @@ impl ProviderRow {
|
|||
self.connect_local(
|
||||
"shared",
|
||||
false,
|
||||
clone!(@weak self as row => @default-return None, move |args| {
|
||||
let account = args[1].get::<Account>().unwrap();
|
||||
callback(&row, account);
|
||||
None
|
||||
}),
|
||||
clone!(
|
||||
#[weak(rename_to = row)]
|
||||
self,
|
||||
#[upgrade_or]
|
||||
None,
|
||||
move |args| {
|
||||
let account = args[1].get::<Account>().unwrap();
|
||||
callback(&row, account);
|
||||
None
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -141,9 +153,13 @@ impl ProviderRow {
|
|||
} else {
|
||||
// Update the progress bar whnever the remaining-time is updated
|
||||
self.tick_progressbar();
|
||||
provider.connect_remaining_time_notify(clone!(@weak self as row => move |_| {
|
||||
row.tick_progressbar();
|
||||
}));
|
||||
provider.connect_remaining_time_notify(clone!(
|
||||
#[weak(rename_to = row)]
|
||||
self,
|
||||
move |_| {
|
||||
row.tick_progressbar();
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
provider
|
||||
|
@ -158,23 +174,39 @@ impl ProviderRow {
|
|||
let sort_model =
|
||||
gtk::SortListModel::new(Some(provider.accounts().clone()), Some(sorter.clone()));
|
||||
|
||||
let create_callback = clone!(@strong self as provider_row, @strong sorter, @strong provider => move |account: &glib::Object| {
|
||||
let account = account.downcast_ref::<Account>().unwrap();
|
||||
let row = AccountRow::new(account);
|
||||
let create_callback = clone!(
|
||||
#[strong(rename_to = provider_row)]
|
||||
self,
|
||||
#[strong]
|
||||
sorter,
|
||||
move |account: &glib::Object| {
|
||||
let account = account.downcast_ref::<Account>().unwrap();
|
||||
let row = AccountRow::new(account);
|
||||
|
||||
row.connect_activated(
|
||||
clone!(@weak account, @weak provider_row => move |_| {
|
||||
provider_row.emit_by_name::<()>("shared", &[&account]);
|
||||
}),
|
||||
);
|
||||
row.connect_activated(clone!(
|
||||
#[weak]
|
||||
account,
|
||||
#[weak]
|
||||
provider_row,
|
||||
move |_| {
|
||||
provider_row.emit_by_name::<()>("shared", &[&account]);
|
||||
}
|
||||
));
|
||||
|
||||
account.connect_name_notify(clone!(@weak provider_row, @weak sorter => move |_| {
|
||||
// Re-sort in case the name was updated
|
||||
sorter.changed(gtk::SorterChange::Different);
|
||||
provider_row.emit_by_name::<()>("changed", &[]);
|
||||
}));
|
||||
row.upcast::<gtk::Widget>()
|
||||
});
|
||||
account.connect_name_notify(clone!(
|
||||
#[weak]
|
||||
provider_row,
|
||||
#[weak]
|
||||
sorter,
|
||||
move |_| {
|
||||
// Re-sort in case the name was updated
|
||||
sorter.changed(gtk::SorterChange::Different);
|
||||
provider_row.emit_by_name::<()>("changed", &[]);
|
||||
}
|
||||
));
|
||||
row.upcast::<gtk::Widget>()
|
||||
}
|
||||
);
|
||||
|
||||
imp.accounts_list
|
||||
.bind_model(Some(&sort_model), create_callback);
|
||||
|
|
|
@ -32,17 +32,21 @@ mod imp {
|
|||
self.parent_constructed();
|
||||
let obj = self.obj();
|
||||
obj.set_activatable(true);
|
||||
obj.connect_activated(clone!(@weak obj as row => move |_| {
|
||||
if let Some(uri) = row.imp().uri.borrow().clone() {
|
||||
spawn(async move {
|
||||
let file = gio::File::for_uri(&uri);
|
||||
let launcher = gtk::FileLauncher::new(Some(&file));
|
||||
if let Err(err) = launcher.launch_future(gtk::Window::NONE).await {
|
||||
tracing::error!("Failed to open URI {err}");
|
||||
}
|
||||
});
|
||||
};
|
||||
}));
|
||||
obj.connect_activated(clone!(
|
||||
#[weak(rename_to = row)]
|
||||
obj,
|
||||
move |_| {
|
||||
if let Some(uri) = row.imp().uri.borrow().clone() {
|
||||
spawn(async move {
|
||||
let file = gio::File::for_uri(&uri);
|
||||
let launcher = gtk::FileLauncher::new(Some(&file));
|
||||
if let Err(err) = launcher.launch_future(gtk::Window::NONE).await {
|
||||
tracing::error!("Failed to open URI {err}");
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
));
|
||||
|
||||
let image_suffix = gtk::Image::from_icon_name("link-symbolic");
|
||||
image_suffix.set_accessible_role(gtk::AccessibleRole::Presentation);
|
||||
|
|
|
@ -129,14 +129,16 @@ mod imp {
|
|||
let win = self.obj();
|
||||
self.providers.set_model(win.model());
|
||||
|
||||
self.providers
|
||||
.model()
|
||||
.connect_items_changed(clone!(@weak win => move |_, _,_,_| {
|
||||
// We do a check on set_view to ensure we always use the right page
|
||||
if !win.app().is_locked() {
|
||||
win.set_view(View::Accounts);
|
||||
self.providers.model().connect_items_changed(clone!(
|
||||
#[weak]
|
||||
win,
|
||||
move |_, _, _, _| {
|
||||
// We do a check on set_view to ensure we always use the right page
|
||||
if !win.app().is_locked() {
|
||||
win.set_view(View::Accounts);
|
||||
}
|
||||
}
|
||||
}));
|
||||
));
|
||||
|
||||
win.set_icon_name(Some(config::APP_ID));
|
||||
self.empty_status_page.set_icon_name(Some(config::APP_ID));
|
||||
|
@ -191,15 +193,19 @@ mod imp {
|
|||
let win = self.obj();
|
||||
let app = win.app();
|
||||
win.action_set_enabled("win.add_account", !app.is_locked());
|
||||
app.connect_is_locked_notify(clone!(@weak win => move |app| {
|
||||
let is_locked = app.is_locked();
|
||||
win.action_set_enabled("win.add_account", !is_locked);
|
||||
if is_locked{
|
||||
win.set_view(View::Login);
|
||||
} else {
|
||||
win.set_view(View::Accounts);
|
||||
};
|
||||
}));
|
||||
app.connect_is_locked_notify(clone!(
|
||||
#[weak]
|
||||
win,
|
||||
move |app| {
|
||||
let is_locked = app.is_locked();
|
||||
win.action_set_enabled("win.add_account", !is_locked);
|
||||
if is_locked {
|
||||
win.set_view(View::Login);
|
||||
} else {
|
||||
win.set_view(View::Accounts);
|
||||
};
|
||||
}
|
||||
));
|
||||
if app.is_locked() {
|
||||
win.set_view(View::Login);
|
||||
}
|
||||
|
@ -274,9 +280,13 @@ impl Window {
|
|||
dialog.set_from_otp_uri(uri);
|
||||
}
|
||||
|
||||
dialog.connect_added(clone!(@weak self as win => move |_| {
|
||||
win.providers().refilter();
|
||||
}));
|
||||
dialog.connect_added(clone!(
|
||||
#[weak(rename_to = win)]
|
||||
self,
|
||||
move |_| {
|
||||
win.providers().refilter();
|
||||
}
|
||||
));
|
||||
dialog.present(Some(self));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue