diff --git a/resources/icons/ui/refresh.png b/resources/icons/ui/refresh.png
new file mode 100644
index 00000000..64268203
Binary files /dev/null and b/resources/icons/ui/refresh.png differ
diff --git a/resources/icons/ui/refresh.svg b/resources/icons/ui/refresh.svg
new file mode 100644
index 00000000..17c41496
--- /dev/null
+++ b/resources/icons/ui/refresh.svg
@@ -0,0 +1,16 @@
+
+
diff --git a/resources/qml/dialogs/UserProfile.qml b/resources/qml/dialogs/UserProfile.qml
index 9bf548e3..d5442382 100644
--- a/resources/qml/dialogs/UserProfile.qml
+++ b/resources/qml/dialogs/UserProfile.qml
@@ -249,6 +249,14 @@ ApplicationWindow {
visible: !profile.isGlobalUserProfile && profile.room.permissions.canBan()
}
+ ImageButton {
+ image: ":/icons/icons/ui/refresh.png"
+ hoverEnabled: true
+ ToolTip.visible: hovered
+ ToolTip.text: qsTr("Refresh device list.")
+ onClicked: profile.refreshDevices();
+ }
+
}
}
@@ -264,6 +272,9 @@ ApplicationWindow {
delegate: RowLayout {
+ required property int verificationStatus
+ required property string deviceId
+ required property string deviceName
width: devicelist.width
spacing: 4
@@ -276,7 +287,7 @@ ApplicationWindow {
elide: Text.ElideRight
font.bold: true
color: Nheko.colors.text
- text: model.deviceId
+ text: deviceId
}
Text {
@@ -284,7 +295,7 @@ ApplicationWindow {
Layout.alignment: Qt.AlignRight
elide: Text.ElideRight
color: Nheko.colors.text
- text: model.deviceName
+ text: deviceName
}
}
@@ -292,19 +303,30 @@ ApplicationWindow {
Image {
Layout.preferredHeight: 16
Layout.preferredWidth: 16
- source: ((model.verificationStatus == VerificationStatus.VERIFIED) ? "image://colorimage/:/icons/icons/ui/lock.png?green" : ((model.verificationStatus == VerificationStatus.UNVERIFIED) ? "image://colorimage/:/icons/icons/ui/unlock.png?yellow" : "image://colorimage/:/icons/icons/ui/unlock.png?red"))
+ source: {
+ switch (verificationStatus){
+ case VerificationStatus.VERIFIED:
+ return "image://colorimage/:/icons/icons/ui/lock.png?green";
+ case VerificationStatus.UNVERIFIED:
+ return "image://colorimage/:/icons/icons/ui/unlock.png?yellow";
+ case VerificationStatus.SELF:
+ return "image://colorimage/:/icons/icons/ui/checkmark.png?green";
+ default:
+ return "image://colorimage/:/icons/icons/ui/unlock.png?red";
+ }
+ }
}
Button {
id: verifyButton
- visible: (!profile.userVerificationEnabled && !profile.isSelf) || (profile.isSelf && (model.verificationStatus != VerificationStatus.VERIFIED || !profile.userVerificationEnabled))
- text: (model.verificationStatus != VerificationStatus.VERIFIED) ? qsTr("Verify") : qsTr("Unverify")
+ visible: verificationStatus == VerificationStatus.UNVERIFIED && (profile.isSelf || !profile.userVerificationEnabled)
+ text: (verificationStatus != VerificationStatus.VERIFIED) ? qsTr("Verify") : qsTr("Unverify")
onClicked: {
- if (model.verificationStatus == VerificationStatus.VERIFIED)
- profile.unverify(model.deviceId);
+ if (verificationStatus == VerificationStatus.VERIFIED)
+ profile.unverify(deviceId);
else
- profile.verify(model.deviceId);
+ profile.verify(deviceId);
}
}
diff --git a/resources/res.qrc b/resources/res.qrc
index a001a929..3bd301f7 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -72,6 +72,7 @@
icons/ui/screen-share.png
icons/ui/toggle-camera-view.png
icons/ui/video-call.png
+ icons/ui/refresh.png
icons/emoji-categories/people.png
icons/emoji-categories/people@2x.png
icons/emoji-categories/nature.png
diff --git a/src/Cache.cpp b/src/Cache.cpp
index b124fe5e..ee0ca0c2 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -4045,6 +4045,16 @@ Cache::updateUserKeys(const std::string &sync_token, const mtx::responses::Query
}
}
+void
+Cache::markUserKeysOutOfDate(const std::vector &user_ids)
+{
+ auto currentBatchToken = nextBatchToken();
+ auto txn = lmdb::txn::begin(env_);
+ auto db = getUserKeysDb(txn);
+ markUserKeysOutOfDate(txn, db, user_ids, currentBatchToken);
+ txn.commit();
+}
+
void
Cache::markUserKeysOutOfDate(lmdb::txn &txn,
lmdb::dbi &db,
diff --git a/src/Cache_p.h b/src/Cache_p.h
index a15010e6..52375d38 100644
--- a/src/Cache_p.h
+++ b/src/Cache_p.h
@@ -50,6 +50,7 @@ public:
const std::string &room_id,
bool verified_only);
void updateUserKeys(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery);
+ void markUserKeysOutOfDate(const std::vector &user_ids);
void markUserKeysOutOfDate(lmdb::txn &txn,
lmdb::dbi &db,
const std::vector &user_ids,
diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp
index 58150ed7..31ae9f8b 100644
--- a/src/ui/UserProfile.cpp
+++ b/src/ui/UserProfile.cpp
@@ -34,6 +34,7 @@ UserProfile::UserProfile(QString roomid,
this,
&UserProfile::setGlobalUsername,
Qt::QueuedConnection);
+ connect(this, &UserProfile::verificationStatiChanged, &UserProfile::updateVerificationStatus);
if (isGlobalUserProfile()) {
getGlobalProfileData();
@@ -48,22 +49,7 @@ UserProfile::UserProfile(QString roomid,
if (user_id != this->userid_.toStdString())
return;
- auto status = cache::verificationStatus(user_id);
- if (!status)
- return;
- this->isUserVerified = status->user_verified;
- emit userStatusChanged();
-
- for (auto &deviceInfo : deviceList_.deviceList_) {
- deviceInfo.verification_status =
- std::find(status->verified_devices.begin(),
- status->verified_devices.end(),
- deviceInfo.device_id.toStdString()) == status->verified_devices.end()
- ? verification::UNVERIFIED
- : verification::VERIFIED;
- }
- deviceList_.reset(deviceList_.deviceList_);
- emit devicesChanged();
+ emit verificationStatiChanged();
});
fetchDeviceList(this->userid_);
}
@@ -151,6 +137,13 @@ UserProfile::isSelf() const
return this->userid_ == utils::localUser();
}
+void
+UserProfile::refreshDevices()
+{
+ cache::client()->markUserKeysOutOfDate({this->userid_.toStdString()});
+ fetchDeviceList(this->userid_);
+}
+
void
UserProfile::fetchDeviceList(const QString &userID)
{
@@ -161,20 +154,18 @@ UserProfile::fetchDeviceList(const QString &userID)
cache::client()->query_keys(
userID.toStdString(),
- [other_user_id = userID.toStdString(), this](const UserKeyCache &other_user_keys,
+ [other_user_id = userID.toStdString(), this](const UserKeyCache &,
mtx::http::RequestErr err) {
if (err) {
nhlog::net()->warn("failed to query device keys: {},{}",
mtx::errors::to_string(err->matrix_error.errcode),
static_cast(err->status_code));
- return;
}
// Ensure local key cache is up to date
cache::client()->query_keys(
utils::localUser().toStdString(),
- [other_user_id, other_user_keys, this](const UserKeyCache &,
- mtx::http::RequestErr err) {
+ [this](const UserKeyCache &, mtx::http::RequestErr err) {
using namespace mtx;
std::string local_user_id = utils::localUser().toStdString();
@@ -182,41 +173,58 @@ UserProfile::fetchDeviceList(const QString &userID)
nhlog::net()->warn("failed to query device keys: {},{}",
mtx::errors::to_string(err->matrix_error.errcode),
static_cast(err->status_code));
- return;
}
- this->hasMasterKey = !other_user_keys.master_keys.keys.empty();
-
- std::vector deviceInfo;
- auto devices = other_user_keys.device_keys;
- auto verificationStatus = cache::client()->verificationStatus(other_user_id);
-
- isUserVerified = verificationStatus.user_verified;
- emit userStatusChanged();
-
- for (const auto &d : devices) {
- auto device = d.second;
- verification::Status verified = verification::Status::UNVERIFIED;
-
- if (std::find(verificationStatus.verified_devices.begin(),
- verificationStatus.verified_devices.end(),
- device.device_id) != verificationStatus.verified_devices.end() &&
- mtx::crypto::verify_identity_signature(
- device, DeviceId(device.device_id), UserId(other_user_id)))
- verified = verification::Status::VERIFIED;
-
- deviceInfo.push_back(
- {QString::fromStdString(d.first),
- QString::fromStdString(device.unsigned_info.device_display_name),
- verified});
- }
-
- this->deviceList_.queueReset(std::move(deviceInfo));
- emit devicesChanged();
+ emit verificationStatiChanged();
});
});
}
+void
+UserProfile::updateVerificationStatus()
+{
+ if (!cache::client() || !cache::client()->isDatabaseReady())
+ return;
+
+ auto user_keys = cache::client()->userKeys(userid_.toStdString());
+ if (!user_keys) {
+ this->hasMasterKey = false;
+ this->isUserVerified = crypto::Trust::Unverified;
+ this->deviceList_.reset({});
+ emit userStatusChanged();
+ return;
+ }
+
+ this->hasMasterKey = !user_keys->master_keys.keys.empty();
+
+ std::vector deviceInfo;
+ auto devices = user_keys->device_keys;
+ auto verificationStatus = cache::client()->verificationStatus(userid_.toStdString());
+
+ this->isUserVerified = verificationStatus.user_verified;
+ emit userStatusChanged();
+
+ for (const auto &d : devices) {
+ auto device = d.second;
+ verification::Status verified =
+ std::find(verificationStatus.verified_devices.begin(),
+ verificationStatus.verified_devices.end(),
+ device.device_id) == verificationStatus.verified_devices.end()
+ ? verification::UNVERIFIED
+ : verification::VERIFIED;
+
+ if (isSelf() && device.device_id == ::http::client()->device_id())
+ verified = verification::Status::SELF;
+
+ deviceInfo.push_back({QString::fromStdString(d.first),
+ QString::fromStdString(device.unsigned_info.device_display_name),
+ verified});
+ }
+
+ this->deviceList_.queueReset(std::move(deviceInfo));
+ emit devicesChanged();
+}
+
void
UserProfile::banUser()
{
diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h
index a148c431..68f9c21b 100644
--- a/src/ui/UserProfile.h
+++ b/src/ui/UserProfile.h
@@ -18,6 +18,7 @@ Q_NAMESPACE
enum Status
{
+ SELF,
VERIFIED,
UNVERIFIED,
BLOCKED
@@ -118,6 +119,7 @@ public:
Q_INVOKABLE void verify(QString device = "");
Q_INVOKABLE void unverify(QString device = "");
Q_INVOKABLE void fetchDeviceList(const QString &userID);
+ Q_INVOKABLE void refreshDevices();
Q_INVOKABLE void banUser();
// Q_INVOKABLE void ignoreUser();
Q_INVOKABLE void kickUser();
@@ -135,11 +137,15 @@ signals:
void globalUsernameRetrieved(const QString &globalUser);
void devicesChanged();
+ // internal
+ void verificationStatiChanged();
+
public slots:
void updateAvatarUrl();
-protected slots:
+private slots:
void setGlobalUsername(const QString &globalUser);
+ void updateVerificationStatus();
private:
void updateRoomMemberState(mtx::events::state::Member member);