diff --git a/resources/qml/dialogs/UserProfile.qml b/resources/qml/dialogs/UserProfile.qml index 30052168..4c7095b2 100644 --- a/resources/qml/dialogs/UserProfile.qml +++ b/resources/qml/dialogs/UserProfile.qml @@ -281,6 +281,8 @@ ApplicationWindow { required property int verificationStatus required property string deviceId required property string deviceName + required property string lastIp + required property var lastTs width: devicelist.width spacing: 4 @@ -288,21 +290,90 @@ ApplicationWindow { ColumnLayout { spacing: 0 - Text { - Layout.fillWidth: true - Layout.alignment: Qt.AlignLeft - elide: Text.ElideRight - font.bold: true - color: Nheko.colors.text - text: deviceId + RowLayout { + Text { + Layout.fillWidth: true + Layout.alignment: Qt.AlignLeft + elide: Text.ElideRight + font.bold: true + color: Nheko.colors.text + text: deviceId + } + + Image { + Layout.preferredHeight: 16 + Layout.preferredWidth: 16 + visible: profile.isSelf && verificationStatus != VerificationStatus.NOT_APPLICABLE + 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"; + } + } + } + + ImageButton { + Layout.alignment: Qt.AlignTop + image: ":/icons/icons/ui/power-button-off.png" + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: qsTr("Sign out this device.") + onClicked: profile.signOutDevice(deviceId) + visible: profile.isSelf + } + } + + RowLayout { + id: deviceNameRow + property bool isEditingAllowed + + TextInput { + id: deviceNameField + readOnly: !deviceNameRow.isEditingAllowed + text: deviceName + color: Nheko.colors.text + Layout.alignment: Qt.AlignLeft + Layout.fillWidth: true + selectByMouse: true + onAccepted: { + profile.changeDeviceName(deviceId, deviceNameField.text); + deviceNameRow.isEditingAllowed = false; + } + } + + ImageButton { + visible: profile.isSelf + hoverEnabled: true + ToolTip.visible: hovered + ToolTip.text: qsTr("Change device name.") + image: deviceNameRow.isEditingAllowed ? ":/icons/icons/ui/checkmark.png" : ":/icons/icons/ui/edit.png" + onClicked: { + if (deviceNameRow.isEditingAllowed) { + profile.changeDeviceName(deviceId, deviceNameField.text); + deviceNameRow.isEditingAllowed = false; + } else { + deviceNameRow.isEditingAllowed = true; + deviceNameField.focus = true; + deviceNameField.selectAll(); + } + } + } + } Text { + visible: profile.isSelf Layout.fillWidth: true - Layout.alignment: Qt.AlignRight + Layout.alignment: Qt.AlignLeft elide: Text.ElideRight color: Nheko.colors.text - text: deviceName + text: qsTr("Last seen %1 from %2").arg(new Date(lastTs).toLocaleString(Locale.ShortFormat)).arg(lastIp?lastIp:"???") } } @@ -310,7 +381,7 @@ ApplicationWindow { Image { Layout.preferredHeight: 16 Layout.preferredWidth: 16 - visible: verificationStatus != VerificationStatus.NOT_APPLICABLE + visible: !profile.isSelf && verificationStatus != VerificationStatus.NOT_APPLICABLE source: { switch (verificationStatus) { case VerificationStatus.VERIFIED: @@ -338,14 +409,7 @@ ApplicationWindow { } } - ImageButton { - image: ":/icons/icons/ui/power-button-off.png" - hoverEnabled: true - ToolTip.visible: hovered - ToolTip.text: qsTr("Sign out this device.") - onClicked: profile.signOutDevice(deviceId) - visible: profile.isSelf - } + } diff --git a/src/ui/UserProfile.cpp b/src/ui/UserProfile.cpp index 0e3fd39f..b5a16f43 100644 --- a/src/ui/UserProfile.cpp +++ b/src/ui/UserProfile.cpp @@ -62,6 +62,8 @@ DeviceInfoModel::roleNames() const {DeviceId, "deviceId"}, {DeviceName, "deviceName"}, {VerificationStatus, "verificationStatus"}, + {LastIp, "lastIp"}, + {LastTs, "lastTs"}, }; } @@ -78,6 +80,10 @@ DeviceInfoModel::data(const QModelIndex &index, int role) const return deviceList_[index.row()].display_name; case VerificationStatus: return QVariant::fromValue(deviceList_[index.row()].verification_status); + case LastIp: + return deviceList_[index.row()].lastIp; + case LastTs: + return deviceList_[index.row()].lastTs; default: return {}; } @@ -334,6 +340,19 @@ UserProfile::changeUsername(QString username) } } +void +UserProfile::changeDeviceName(QString deviceID, QString deviceName) +{ + http::client()->set_device_name( + deviceID.toStdString(), deviceName.toStdString(), [this](mtx::http::RequestErr err) { + if (err) { + nhlog::net()->warn("could not change device name"); + return; + } + refreshDevices(); + }); +} + void UserProfile::verify(QString device) { diff --git a/src/ui/UserProfile.h b/src/ui/UserProfile.h index e8bff6ba..cd2f4740 100644 --- a/src/ui/UserProfile.h +++ b/src/ui/UserProfile.h @@ -62,7 +62,7 @@ public: verification::Status verification_status; QString lastIp; - size_t lastTs; + qlonglong lastTs; }; class DeviceInfoModel : public QAbstractListModel @@ -74,6 +74,8 @@ public: DeviceId, DeviceName, VerificationStatus, + LastIp, + LastTs, }; explicit DeviceInfoModel(QObject *parent = nullptr) @@ -141,6 +143,7 @@ public: Q_INVOKABLE void kickUser(); Q_INVOKABLE void startChat(); Q_INVOKABLE void changeUsername(QString username); + Q_INVOKABLE void changeDeviceName(QString deviceID, QString deviceName); Q_INVOKABLE void changeAvatar(); Q_INVOKABLE void openGlobalProfile();