diff --git a/main/data/theme.css b/main/data/theme.css
index 9fc08db8..621cf66f 100644
--- a/main/data/theme.css
+++ b/main/data/theme.css
@@ -21,7 +21,8 @@ window.dino-main .dino-conversation {
background: @theme_base_color;
}
-window.dino-main .dino-conversation undershoot {
+window.dino-main .dino-conversation undershoot,
+window.dino-main .dino-conversation viewport /* Some themes set this */ {
background: none;
}
diff --git a/plugins/omemo/data/contact_details_dialog.ui b/plugins/omemo/data/contact_details_dialog.ui
index 50e19eee..6fb7b6c1 100644
--- a/plugins/omemo/data/contact_details_dialog.ui
+++ b/plugins/omemo/data/contact_details_dialog.ui
@@ -234,6 +234,40 @@
+
+
+
diff --git a/plugins/omemo/src/plugin.vala b/plugins/omemo/src/plugin.vala
index 913d3347..0e740f20 100644
--- a/plugins/omemo/src/plugin.vala
+++ b/plugins/omemo/src/plugin.vala
@@ -83,6 +83,13 @@ public class Plugin : RootInterface, Object {
public void shutdown() {
// Nothing to do
}
+
+ public bool has_new_devices(Account account, Xmpp.Jid jid) {
+ int identity_id = db.identity.get_id(account.id);
+ if (identity_id < 0) return false;
+
+ return db.identity_meta.get_new_devices(identity_id, jid.bare_jid.to_string()).count() > 0;
+ }
}
}
diff --git a/plugins/omemo/src/ui/contact_details_dialog.vala b/plugins/omemo/src/ui/contact_details_dialog.vala
index 463b5cd7..ad43f00e 100644
--- a/plugins/omemo/src/ui/contact_details_dialog.vala
+++ b/plugins/omemo/src/ui/contact_details_dialog.vala
@@ -28,6 +28,7 @@ public class ContactDetailsDialog : Gtk.Dialog {
[GtkChild] private ListBox new_keys_listbox;
[GtkChild] private Box keys_container;
[GtkChild] private ListBox keys_listbox;
+ [GtkChild] private ListBox unused_keys_listbox;
[GtkChild] private Switch auto_accept_switch;
[GtkChild] private Button copy_button;
[GtkChild] private Button show_qrcode_button;
@@ -54,11 +55,17 @@ public class ContactDetailsDialog : Gtk.Dialog {
(get_header_bar() as HeaderBar).set_subtitle(jid.bare_jid.to_string());
}
+ keys_listbox.row_activated.connect(on_key_entry_clicked);
+ unused_keys_listbox.row_activated.connect(on_key_entry_clicked);
+ auto_accept_switch.state_set.connect(on_auto_accept_toggled);
+
int identity_id = plugin.db.identity.get_id(account.id);
if (identity_id < 0) return;
- // Dialog opened from the account settings menu
- // Show the fingerprint for this device separately with buttons for a qrcode and to copy
+ auto_accept_switch.set_active(plugin.db.trust.get_blind_trust(identity_id, jid.bare_jid.to_string()));
+
+ // Dialog opened from the account settings menu
+ // Show the fingerprint for this device separately with buttons for a qrcode and to copy
if(jid.equals(account.bare_jid)) {
own = true;
own_id = plugin.db.identity.row_with(plugin.db.identity.account_id, account.id)[plugin.db.identity.device_id];
@@ -107,24 +114,6 @@ public class ContactDetailsDialog : Gtk.Dialog {
}
add_fingerprint(device, (TrustLevel) device[plugin.db.identity_meta.trust_level]);
}
-
- auto_accept_switch.set_active(plugin.db.trust.get_blind_trust(identity_id, jid.bare_jid.to_string()));
-
- auto_accept_switch.state_set.connect((active) => {
- plugin.trust_manager.set_blind_trust(account, jid, active);
-
- if (active) {
- new_keys_container.visible = false;
-
- foreach (Row device in plugin.db.identity_meta.get_new_devices(identity_id, jid.to_string())) {
- plugin.trust_manager.set_device_trust(account, jid, device[plugin.db.identity_meta.device_id], TrustLevel.TRUSTED);
- add_fingerprint(device, TrustLevel.TRUSTED);
- }
- }
-
- return false;
- });
-
}
private void header_function(ListBoxRow row, ListBoxRow? before) {
@@ -133,74 +122,50 @@ public class ContactDetailsDialog : Gtk.Dialog {
}
}
- private void set_row(int trust, bool now_active, Image img, Label status_lbl, Label lbl, ListBoxRow lbr){
- switch(trust) {
- case TrustLevel.TRUSTED:
- img.icon_name = "emblem-ok-symbolic";
- status_lbl.set_markup("%s".printf(_("Accepted")));
- lbl.get_style_context().remove_class("dim-label");
- break;
- case TrustLevel.UNTRUSTED:
- img.icon_name = "action-unavailable-symbolic";
- status_lbl.set_markup("%s".printf(_("Rejected")));
- lbl.get_style_context().add_class("dim-label");
- break;
- case TrustLevel.VERIFIED:
- img.icon_name = "security-high-symbolic";
- status_lbl.set_markup("%s".printf(_("Verified")));
- lbl.get_style_context().remove_class("dim-label");
- break;
- }
+ private void add_fingerprint(Row device, TrustLevel trust) {
+ string key_base64 = device[plugin.db.identity_meta.identity_key_public_base64];
+ bool key_active = device[plugin.db.identity_meta.now_active];
+ FingerprintRow fingerprint_row = new FingerprintRow(device, key_base64, trust, key_active) { visible = true, activatable = true, hexpand = true };
- if (!now_active) {
- img.icon_name = "appointment-missed-symbolic";
- status_lbl.set_markup("%s".printf(_("Unused")));
- lbr.activatable = false;
+ if (device[plugin.db.identity_meta.now_active]) {
+ keys_container.visible = true;
+ keys_listbox.add(fingerprint_row);
+ } else {
+ unused_keys_listbox.add(fingerprint_row);
}
}
- private void add_fingerprint(Row device, TrustLevel trust) {
- keys_container.visible = true;
+ private void on_key_entry_clicked(ListBoxRow widget) {
+ FingerprintRow? fingerprint_row = widget as FingerprintRow;
+ if (fingerprint_row == null) return;
- ListBoxRow lbr = new ListBoxRow() { visible = true, activatable = true, hexpand = true };
- Box box = new Box(Gtk.Orientation.HORIZONTAL, 40) { visible = true, margin_start = 20, margin_end = 20, margin_top = 14, margin_bottom = 14, hexpand = true };
-
- Box status_box = new Box(Gtk.Orientation.HORIZONTAL, 5) { visible = true, hexpand = true };
- Label status_lbl = new Label(null) { visible = true, hexpand = true, xalign = 0 };
-
- Image img = new Image() { visible = true, halign = Align.END, icon_size = IconSize.BUTTON };
-
- string res = fingerprint_markup(fingerprint_from_base64(device[plugin.db.identity_meta.identity_key_public_base64]));
- Label lbl = new Label(res)
- { use_markup=true, justify=Justification.RIGHT, visible=true, halign = Align.START, valign = Align.CENTER, hexpand = false };
-
- set_row(trust, device[plugin.db.identity_meta.now_active], img, status_lbl, lbl, lbr);
-
- box.add(lbl);
- box.add(status_box);
-
- status_box.add(status_lbl);
- status_box.add(img);
-
- lbr.add(box);
- keys_listbox.add(lbr);
-
- //Row clicked - pull the most up to date device info from the database and show the manage window
- keys_listbox.row_activated.connect((row) => {
- if(row == lbr) {
- Row updated_device = plugin.db.identity_meta.get_device(device[plugin.db.identity_meta.identity_id], device[plugin.db.identity_meta.address_name], device[plugin.db.identity_meta.device_id]);
- ManageKeyDialog manage_dialog = new ManageKeyDialog(updated_device, plugin.db);
- manage_dialog.set_transient_for((Gtk.Window) get_toplevel());
- manage_dialog.present();
- manage_dialog.response.connect((response) => {
- set_row(response, device[plugin.db.identity_meta.now_active], img, status_lbl, lbl, lbr);
- update_device(response, device);
- });
- }
+ Row updated_device = plugin.db.identity_meta.get_device(fingerprint_row.row[plugin.db.identity_meta.identity_id], fingerprint_row.row[plugin.db.identity_meta.address_name], fingerprint_row.row[plugin.db.identity_meta.device_id]);
+ ManageKeyDialog manage_dialog = new ManageKeyDialog(updated_device, plugin.db);
+ manage_dialog.set_transient_for((Gtk.Window) get_toplevel());
+ manage_dialog.present();
+ manage_dialog.response.connect((response) => {
+ fingerprint_row.update_trust_state(response, fingerprint_row.row[plugin.db.identity_meta.now_active]);
+ update_stored_trust(response, fingerprint_row.row);
});
}
- private void update_device(int response, Row device){
+ private bool on_auto_accept_toggled(bool active) {
+ plugin.trust_manager.set_blind_trust(account, jid, active);
+
+ if (active) {
+ int identity_id = plugin.db.identity.get_id(account.id);
+ if (identity_id < 0) return false;
+
+ new_keys_container.visible = false;
+ foreach (Row device in plugin.db.identity_meta.get_new_devices(identity_id, jid.to_string())) {
+ plugin.trust_manager.set_device_trust(account, jid, device[plugin.db.identity_meta.device_id], TrustLevel.TRUSTED);
+ add_fingerprint(device, TrustLevel.TRUSTED);
+ }
+ }
+ return false;
+ }
+
+ private void update_stored_trust(int response, Row device) {
switch (response) {
case TrustLevel.TRUSTED:
plugin.trust_manager.set_device_trust(account, jid, device[plugin.db.identity_meta.device_id], TrustLevel.TRUSTED);
@@ -216,7 +181,7 @@ public class ContactDetailsDialog : Gtk.Dialog {
}
}
- private void add_new_fingerprint(Row device){
+ private void add_new_fingerprint(Row device) {
new_keys_container.visible = true;
ListBoxRow lbr = new ListBoxRow() { visible = true, activatable = false, hexpand = true };
@@ -264,4 +229,57 @@ public class ContactDetailsDialog : Gtk.Dialog {
}
}
+public class FingerprintRow : ListBoxRow {
+
+ private Image trust_image = new Image() { visible = true, halign = Align.END, icon_size = IconSize.BUTTON };
+ private Label fingerprint_label = new Label("") { use_markup=true, justify=Justification.RIGHT, visible=true, halign = Align.START, valign = Align.CENTER, hexpand = false };
+ private Label trust_label = new Label(null) { visible = true, hexpand = true, xalign = 0 };
+
+ public Row row;
+
+ construct {
+ Box box = new Box(Gtk.Orientation.HORIZONTAL, 40) { visible = true, margin_start = 20, margin_end = 20, margin_top = 14, margin_bottom = 14, hexpand = true };
+ Box status_box = new Box(Gtk.Orientation.HORIZONTAL, 5) { visible = true, hexpand = true };
+
+ box.add(fingerprint_label);
+ box.add(status_box);
+
+ status_box.add(trust_label);
+ status_box.add(trust_image);
+
+ this.add(box);
+ }
+
+ public FingerprintRow(Row row, string key_base64, int trust, bool now_active) {
+ this.row = row;
+ fingerprint_label.label = fingerprint_markup(fingerprint_from_base64(key_base64));
+ update_trust_state(trust, now_active);
+ }
+
+ public void update_trust_state(int trust, bool now_active) {
+ switch(trust) {
+ case TrustLevel.TRUSTED:
+ trust_image.icon_name = "emblem-ok-symbolic";
+ trust_label.set_markup("%s".printf(_("Accepted")));
+ fingerprint_label.get_style_context().remove_class("dim-label");
+ break;
+ case TrustLevel.UNTRUSTED:
+ trust_image.icon_name = "action-unavailable-symbolic";
+ trust_label.set_markup("%s".printf(_("Rejected")));
+ fingerprint_label.get_style_context().add_class("dim-label");
+ break;
+ case TrustLevel.VERIFIED:
+ trust_image.icon_name = "security-high-symbolic";
+ trust_label.set_markup("%s".printf(_("Verified")));
+ fingerprint_label.get_style_context().remove_class("dim-label");
+ break;
+ }
+
+ if (!now_active) {
+ trust_image.icon_name = "appointment-missed-symbolic";
+ trust_label.set_markup("%s".printf(_("Unused")));
+ }
+ }
+}
+
}
diff --git a/plugins/omemo/src/ui/device_notification_populator.vala b/plugins/omemo/src/ui/device_notification_populator.vala
index 5b47611c..2f276f2b 100644
--- a/plugins/omemo/src/ui/device_notification_populator.vala
+++ b/plugins/omemo/src/ui/device_notification_populator.vala
@@ -21,16 +21,10 @@ public class DeviceNotificationPopulator : NotificationPopulator, Object {
stream_interactor.account_added.connect(on_account_added);
}
- public bool has_new_devices(Jid jid) {
- int identity_id = plugin.db.identity.get_id(current_conversation.account.id);
- if (identity_id < 0) return false;
- return plugin.db.identity_meta.get_new_devices(identity_id, jid.bare_jid.to_string()).count() > 0;
- }
-
public void init(Conversation conversation, NotificationCollection notification_collection, Plugins.WidgetType type) {
current_conversation = conversation;
this.notification_collection = notification_collection;
- if (has_new_devices(conversation.counterpart) && conversation.type_ == Conversation.Type.CHAT) {
+ if (plugin.has_new_devices(conversation.account, conversation.counterpart) && conversation.type_ == Conversation.Type.CHAT) {
display_notification();
}
}
@@ -48,7 +42,7 @@ public class DeviceNotificationPopulator : NotificationPopulator, Object {
}
public void should_hide() {
- if (!has_new_devices(current_conversation.counterpart) && notification != null){
+ if (!plugin.has_new_devices(current_conversation.account, current_conversation.counterpart) && notification != null){
notification_collection.remove_meta_notification(notification);
notification = null;
}
@@ -56,7 +50,7 @@ public class DeviceNotificationPopulator : NotificationPopulator, Object {
private void on_account_added(Account account) {
stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).bundle_fetched.connect_after((jid, device_id, bundle) => {
- if (current_conversation != null && jid.equals(current_conversation.counterpart) && has_new_devices(current_conversation.counterpart)) {
+ if (current_conversation != null && jid.equals(current_conversation.counterpart) && plugin.has_new_devices(current_conversation.account, current_conversation.counterpart)) {
display_notification();
}
});
diff --git a/plugins/omemo/src/ui/own_notifications.vala b/plugins/omemo/src/ui/own_notifications.vala
index f882d03a..7ff10e30 100644
--- a/plugins/omemo/src/ui/own_notifications.vala
+++ b/plugins/omemo/src/ui/own_notifications.vala
@@ -15,23 +15,16 @@ public class OwnNotifications {
this.plugin = plugin;
this.account = account;
stream_interactor.module_manager.get_module(account, StreamModule.IDENTITY).bundle_fetched.connect_after((jid, device_id, bundle) => {
- if (jid.equals(account.bare_jid) && has_new_devices(account.bare_jid)) {
+ if (jid.equals(account.bare_jid) && plugin.has_new_devices(account, account.bare_jid)) {
display_notification();
}
});
- if (has_new_devices(account.bare_jid)) {
+ if (plugin.has_new_devices(account, account.bare_jid)) {
display_notification();
}
}
- public bool has_new_devices(Jid jid) {
- int identity_id = plugin.db.identity.get_id(account.id);
- if (identity_id < 0) return false;
-
- return plugin.db.identity_meta.get_new_devices(identity_id, jid.bare_jid.to_string()).count() > 0;
- }
-
private void display_notification() {
Notification notification = new Notification(_("OMEMO trust decision required"));
notification.set_default_action_and_target_value("app.own-keys", new Variant.int32(account.id));