mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-26 13:08:48 +03:00
Merge pull request #752 from Thulinma/devicelistEdits
Added support for refreshing the device list & marking current device with a checkmark instead of a lock
This commit is contained in:
commit
c514acb7c5
8 changed files with 122 additions and 58 deletions
BIN
resources/icons/ui/refresh.png
Normal file
BIN
resources/icons/ui/refresh.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
16
resources/icons/ui/refresh.svg
Normal file
16
resources/icons/ui/refresh.svg
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
version="1.1"
|
||||||
|
viewBox="-10 0 1792 1792"
|
||||||
|
id="svg866"
|
||||||
|
width="1792"
|
||||||
|
height="1792"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs870" />
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="m 1629,1056 q 0,5 -1,7 -64,268 -268,434.5 Q 1156,1664 882,1664 736,1664 599.5,1609 463,1554 356,1452 l -129,129 q -19,19 -45,19 -26,0 -45,-19 -19,-19 -19,-45 v -448 q 0,-26 19,-45 19,-19 45,-19 h 448 q 26,0 45,19 19,19 19,45 0,26 -19,45 l -137,137 q 71,66 161,102 90,36 187,36 134,0 250,-65 116,-65 186,-179 11,-17 53,-117 8,-23 30,-23 h 192 q 13,0 22.5,9.5 9.5,9.5 9.5,22.5 z m 25,-800 v 448 q 0,26 -19,45 -19,19 -45,19 h -448 q -26,0 -45,-19 -19,-19 -19,-45 0,-26 19,-45 L 1235,521 Q 1087,384 886,384 q -134,0 -250,65 -116,65 -186,179 -11,17 -53,117 -8,23 -30,23 H 168 q -13,0 -22.5,-9.5 Q 136,749 136,736 v -7 Q 201,461 406,294.5 611,128 886,128 q 146,0 284,55.5 138,55.5 245,156.5 l 130,-129 q 19,-19 45,-19 26,0 45,19 19,19 19,45 z"
|
||||||
|
id="path864" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1 KiB |
|
@ -249,6 +249,14 @@ ApplicationWindow {
|
||||||
visible: !profile.isGlobalUserProfile && profile.room.permissions.canBan()
|
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 {
|
delegate: RowLayout {
|
||||||
|
required property int verificationStatus
|
||||||
|
required property string deviceId
|
||||||
|
required property string deviceName
|
||||||
width: devicelist.width
|
width: devicelist.width
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
||||||
|
@ -276,7 +287,7 @@ ApplicationWindow {
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
font.bold: true
|
font.bold: true
|
||||||
color: Nheko.colors.text
|
color: Nheko.colors.text
|
||||||
text: model.deviceId
|
text: deviceId
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
@ -284,7 +295,7 @@ ApplicationWindow {
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
color: Nheko.colors.text
|
color: Nheko.colors.text
|
||||||
text: model.deviceName
|
text: deviceName
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -292,19 +303,30 @@ ApplicationWindow {
|
||||||
Image {
|
Image {
|
||||||
Layout.preferredHeight: 16
|
Layout.preferredHeight: 16
|
||||||
Layout.preferredWidth: 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 {
|
Button {
|
||||||
id: verifyButton
|
id: verifyButton
|
||||||
|
|
||||||
visible: (!profile.userVerificationEnabled && !profile.isSelf) || (profile.isSelf && (model.verificationStatus != VerificationStatus.VERIFIED || !profile.userVerificationEnabled))
|
visible: verificationStatus == VerificationStatus.UNVERIFIED && (profile.isSelf || !profile.userVerificationEnabled)
|
||||||
text: (model.verificationStatus != VerificationStatus.VERIFIED) ? qsTr("Verify") : qsTr("Unverify")
|
text: (verificationStatus != VerificationStatus.VERIFIED) ? qsTr("Verify") : qsTr("Unverify")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (model.verificationStatus == VerificationStatus.VERIFIED)
|
if (verificationStatus == VerificationStatus.VERIFIED)
|
||||||
profile.unverify(model.deviceId);
|
profile.unverify(deviceId);
|
||||||
else
|
else
|
||||||
profile.verify(model.deviceId);
|
profile.verify(deviceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@
|
||||||
<file>icons/ui/screen-share.png</file>
|
<file>icons/ui/screen-share.png</file>
|
||||||
<file>icons/ui/toggle-camera-view.png</file>
|
<file>icons/ui/toggle-camera-view.png</file>
|
||||||
<file>icons/ui/video-call.png</file>
|
<file>icons/ui/video-call.png</file>
|
||||||
|
<file>icons/ui/refresh.png</file>
|
||||||
<file>icons/emoji-categories/people.png</file>
|
<file>icons/emoji-categories/people.png</file>
|
||||||
<file>icons/emoji-categories/people@2x.png</file>
|
<file>icons/emoji-categories/people@2x.png</file>
|
||||||
<file>icons/emoji-categories/nature.png</file>
|
<file>icons/emoji-categories/nature.png</file>
|
||||||
|
|
|
@ -4045,6 +4045,16 @@ Cache::updateUserKeys(const std::string &sync_token, const mtx::responses::Query
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Cache::markUserKeysOutOfDate(const std::vector<std::string> &user_ids)
|
||||||
|
{
|
||||||
|
auto currentBatchToken = nextBatchToken();
|
||||||
|
auto txn = lmdb::txn::begin(env_);
|
||||||
|
auto db = getUserKeysDb(txn);
|
||||||
|
markUserKeysOutOfDate(txn, db, user_ids, currentBatchToken);
|
||||||
|
txn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Cache::markUserKeysOutOfDate(lmdb::txn &txn,
|
Cache::markUserKeysOutOfDate(lmdb::txn &txn,
|
||||||
lmdb::dbi &db,
|
lmdb::dbi &db,
|
||||||
|
|
|
@ -50,6 +50,7 @@ public:
|
||||||
const std::string &room_id,
|
const std::string &room_id,
|
||||||
bool verified_only);
|
bool verified_only);
|
||||||
void updateUserKeys(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery);
|
void updateUserKeys(const std::string &sync_token, const mtx::responses::QueryKeys &keyQuery);
|
||||||
|
void markUserKeysOutOfDate(const std::vector<std::string> &user_ids);
|
||||||
void markUserKeysOutOfDate(lmdb::txn &txn,
|
void markUserKeysOutOfDate(lmdb::txn &txn,
|
||||||
lmdb::dbi &db,
|
lmdb::dbi &db,
|
||||||
const std::vector<std::string> &user_ids,
|
const std::vector<std::string> &user_ids,
|
||||||
|
|
|
@ -34,6 +34,7 @@ UserProfile::UserProfile(QString roomid,
|
||||||
this,
|
this,
|
||||||
&UserProfile::setGlobalUsername,
|
&UserProfile::setGlobalUsername,
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
|
connect(this, &UserProfile::verificationStatiChanged, &UserProfile::updateVerificationStatus);
|
||||||
|
|
||||||
if (isGlobalUserProfile()) {
|
if (isGlobalUserProfile()) {
|
||||||
getGlobalProfileData();
|
getGlobalProfileData();
|
||||||
|
@ -48,22 +49,7 @@ UserProfile::UserProfile(QString roomid,
|
||||||
if (user_id != this->userid_.toStdString())
|
if (user_id != this->userid_.toStdString())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto status = cache::verificationStatus(user_id);
|
emit verificationStatiChanged();
|
||||||
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();
|
|
||||||
});
|
});
|
||||||
fetchDeviceList(this->userid_);
|
fetchDeviceList(this->userid_);
|
||||||
}
|
}
|
||||||
|
@ -151,6 +137,13 @@ UserProfile::isSelf() const
|
||||||
return this->userid_ == utils::localUser();
|
return this->userid_ == utils::localUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserProfile::refreshDevices()
|
||||||
|
{
|
||||||
|
cache::client()->markUserKeysOutOfDate({this->userid_.toStdString()});
|
||||||
|
fetchDeviceList(this->userid_);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
UserProfile::fetchDeviceList(const QString &userID)
|
UserProfile::fetchDeviceList(const QString &userID)
|
||||||
{
|
{
|
||||||
|
@ -161,20 +154,18 @@ UserProfile::fetchDeviceList(const QString &userID)
|
||||||
|
|
||||||
cache::client()->query_keys(
|
cache::client()->query_keys(
|
||||||
userID.toStdString(),
|
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) {
|
mtx::http::RequestErr err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
nhlog::net()->warn("failed to query device keys: {},{}",
|
nhlog::net()->warn("failed to query device keys: {},{}",
|
||||||
mtx::errors::to_string(err->matrix_error.errcode),
|
mtx::errors::to_string(err->matrix_error.errcode),
|
||||||
static_cast<int>(err->status_code));
|
static_cast<int>(err->status_code));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure local key cache is up to date
|
// Ensure local key cache is up to date
|
||||||
cache::client()->query_keys(
|
cache::client()->query_keys(
|
||||||
utils::localUser().toStdString(),
|
utils::localUser().toStdString(),
|
||||||
[other_user_id, other_user_keys, this](const UserKeyCache &,
|
[this](const UserKeyCache &, mtx::http::RequestErr err) {
|
||||||
mtx::http::RequestErr err) {
|
|
||||||
using namespace mtx;
|
using namespace mtx;
|
||||||
std::string local_user_id = utils::localUser().toStdString();
|
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: {},{}",
|
nhlog::net()->warn("failed to query device keys: {},{}",
|
||||||
mtx::errors::to_string(err->matrix_error.errcode),
|
mtx::errors::to_string(err->matrix_error.errcode),
|
||||||
static_cast<int>(err->status_code));
|
static_cast<int>(err->status_code));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->hasMasterKey = !other_user_keys.master_keys.keys.empty();
|
emit verificationStatiChanged();
|
||||||
|
|
||||||
std::vector<DeviceInfo> 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();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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> 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
|
void
|
||||||
UserProfile::banUser()
|
UserProfile::banUser()
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,7 @@ Q_NAMESPACE
|
||||||
|
|
||||||
enum Status
|
enum Status
|
||||||
{
|
{
|
||||||
|
SELF,
|
||||||
VERIFIED,
|
VERIFIED,
|
||||||
UNVERIFIED,
|
UNVERIFIED,
|
||||||
BLOCKED
|
BLOCKED
|
||||||
|
@ -118,6 +119,7 @@ public:
|
||||||
Q_INVOKABLE void verify(QString device = "");
|
Q_INVOKABLE void verify(QString device = "");
|
||||||
Q_INVOKABLE void unverify(QString device = "");
|
Q_INVOKABLE void unverify(QString device = "");
|
||||||
Q_INVOKABLE void fetchDeviceList(const QString &userID);
|
Q_INVOKABLE void fetchDeviceList(const QString &userID);
|
||||||
|
Q_INVOKABLE void refreshDevices();
|
||||||
Q_INVOKABLE void banUser();
|
Q_INVOKABLE void banUser();
|
||||||
// Q_INVOKABLE void ignoreUser();
|
// Q_INVOKABLE void ignoreUser();
|
||||||
Q_INVOKABLE void kickUser();
|
Q_INVOKABLE void kickUser();
|
||||||
|
@ -135,11 +137,15 @@ signals:
|
||||||
void globalUsernameRetrieved(const QString &globalUser);
|
void globalUsernameRetrieved(const QString &globalUser);
|
||||||
void devicesChanged();
|
void devicesChanged();
|
||||||
|
|
||||||
|
// internal
|
||||||
|
void verificationStatiChanged();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateAvatarUrl();
|
void updateAvatarUrl();
|
||||||
|
|
||||||
protected slots:
|
private slots:
|
||||||
void setGlobalUsername(const QString &globalUser);
|
void setGlobalUsername(const QString &globalUser);
|
||||||
|
void updateVerificationStatus();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateRoomMemberState(mtx::events::state::Member member);
|
void updateRoomMemberState(mtx::events::state::Member member);
|
||||||
|
|
Loading…
Reference in a new issue