commit
8e2f1e9dce
@ -345,6 +345,7 @@ set(SRC_FILES
|
|||||||
src/DeviceVerificationFlow.cpp
|
src/DeviceVerificationFlow.cpp
|
||||||
src/EventAccessors.cpp
|
src/EventAccessors.cpp
|
||||||
src/InviteesModel.cpp
|
src/InviteesModel.cpp
|
||||||
|
src/JdenticonProvider.cpp
|
||||||
src/Logging.cpp
|
src/Logging.cpp
|
||||||
src/LoginPage.cpp
|
src/LoginPage.cpp
|
||||||
src/MainWindow.cpp
|
src/MainWindow.cpp
|
||||||
@ -557,6 +558,7 @@ qt5_wrap_cpp(MOC_HEADERS
|
|||||||
src/DeviceVerificationFlow.h
|
src/DeviceVerificationFlow.h
|
||||||
src/ImagePackListModel.h
|
src/ImagePackListModel.h
|
||||||
src/InviteesModel.h
|
src/InviteesModel.h
|
||||||
|
src/JdenticonProvider.h
|
||||||
src/LoginPage.h
|
src/LoginPage.h
|
||||||
src/MainWindow.h
|
src/MainWindow.h
|
||||||
src/MemberList.h
|
src/MemberList.h
|
||||||
|
@ -12,6 +12,7 @@ Rectangle {
|
|||||||
|
|
||||||
property string url
|
property string url
|
||||||
property string userid
|
property string userid
|
||||||
|
property string roomid
|
||||||
property string displayName
|
property string displayName
|
||||||
property alias textColor: label.color
|
property alias textColor: label.color
|
||||||
property bool crop: true
|
property bool crop: true
|
||||||
@ -35,10 +36,28 @@ Rectangle {
|
|||||||
font.pixelSize: avatar.height / 2
|
font.pixelSize: avatar.height / 2
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
visible: img.status != Image.Ready
|
visible: img.status != Image.Ready && !Settings.useIdenticon
|
||||||
color: Nheko.colors.text
|
color: Nheko.colors.text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: identicon
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: Settings.useIdenticon && img.status != Image.Ready
|
||||||
|
source: Settings.useIdenticon ? ("image://jdenticon/" + (userid !== "" ? userid : roomid) + "?radius=" + (Settings.avatarCircles ? 100 : 25)) : ""
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
Ripple {
|
||||||
|
rippleTarget: parent
|
||||||
|
color: Qt.rgba(Nheko.colors.alternateBase.r, Nheko.colors.alternateBase.g, Nheko.colors.alternateBase.b, 0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: img
|
id: img
|
||||||
|
|
||||||
|
@ -130,6 +130,7 @@ Page {
|
|||||||
else
|
else
|
||||||
return "image://colorimage/" + model.avatarUrl + "?" + communityItem.unimportantText;
|
return "image://colorimage/" + model.avatarUrl + "?" + communityItem.unimportantText;
|
||||||
}
|
}
|
||||||
|
roomid: model.id
|
||||||
displayName: model.displayName
|
displayName: model.displayName
|
||||||
color: communityItem.background
|
color: communityItem.background
|
||||||
}
|
}
|
||||||
|
@ -139,6 +139,7 @@ Popup {
|
|||||||
height: popup.avatarHeight
|
height: popup.avatarHeight
|
||||||
width: popup.avatarWidth
|
width: popup.avatarWidth
|
||||||
displayName: model.displayName
|
displayName: model.displayName
|
||||||
|
userid: model.userid
|
||||||
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
onClicked: popup.completionClicked(completer.completionAt(model.index))
|
onClicked: popup.completionClicked(completer.completionAt(model.index))
|
||||||
}
|
}
|
||||||
@ -194,6 +195,7 @@ Popup {
|
|||||||
height: popup.avatarHeight
|
height: popup.avatarHeight
|
||||||
width: popup.avatarWidth
|
width: popup.avatarWidth
|
||||||
displayName: model.roomName
|
displayName: model.roomName
|
||||||
|
roomid: model.roomid
|
||||||
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
popup.completionClicked(completer.completionAt(model.index));
|
popup.completionClicked(completer.completionAt(model.index));
|
||||||
@ -225,6 +227,7 @@ Popup {
|
|||||||
height: popup.avatarHeight
|
height: popup.avatarHeight
|
||||||
width: popup.avatarWidth
|
width: popup.avatarWidth
|
||||||
displayName: model.roomName
|
displayName: model.roomName
|
||||||
|
roomid: model.roomid
|
||||||
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
onClicked: popup.completionClicked(completer.completionAt(model.index))
|
onClicked: popup.completionClicked(completer.completionAt(model.index))
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,7 @@ ApplicationWindow {
|
|||||||
width: avatarSize
|
width: avatarSize
|
||||||
height: avatarSize
|
height: avatarSize
|
||||||
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
|
roomid: model.roomid
|
||||||
displayName: model.name
|
displayName: model.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +143,8 @@ Page {
|
|||||||
required property int notificationCount
|
required property int notificationCount
|
||||||
required property bool hasLoudNotification
|
required property bool hasLoudNotification
|
||||||
required property bool hasUnreadMessages
|
required property bool hasUnreadMessages
|
||||||
|
required property bool isDirect
|
||||||
|
required property string directChatOtherUserId
|
||||||
|
|
||||||
color: background
|
color: background
|
||||||
height: avatarSize + 2 * Nheko.paddingMedium
|
height: avatarSize + 2 * Nheko.paddingMedium
|
||||||
@ -237,6 +239,8 @@ Page {
|
|||||||
width: avatarSize
|
width: avatarSize
|
||||||
url: avatarUrl.replace("mxc://", "image://MxcImage/")
|
url: avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: roomName
|
displayName: roomName
|
||||||
|
userid: isDirect ? directChatOtherUserId : ""
|
||||||
|
roomid: roomId
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: collapsedNotificationBubble
|
id: collapsedNotificationBubble
|
||||||
|
@ -39,6 +39,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
width: 130
|
width: 130
|
||||||
height: width
|
height: width
|
||||||
|
roomid: members.roomId
|
||||||
displayName: members.roomName
|
displayName: members.roomName
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
url: members.avatarUrl.replace("mxc://", "image://MxcImage/")
|
url: members.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
|
@ -38,6 +38,7 @@ ApplicationWindow {
|
|||||||
|
|
||||||
Avatar {
|
Avatar {
|
||||||
url: roomSettings.roomAvatarUrl.replace("mxc://", "image://MxcImage/")
|
url: roomSettings.roomAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
|
roomid: roomSettings.roomid
|
||||||
displayName: roomSettings.roomName
|
displayName: roomSettings.roomName
|
||||||
height: 130
|
height: 130
|
||||||
width: 130
|
width: 130
|
||||||
|
@ -137,6 +137,7 @@ Item {
|
|||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: preview
|
id: preview
|
||||||
|
|
||||||
|
property string roomId: room ? room.roomId : (roomPreview ? roomPreview.roomId : "")
|
||||||
property string roomName: room ? room.roomName : (roomPreview ? roomPreview.roomName : "")
|
property string roomName: room ? room.roomName : (roomPreview ? roomPreview.roomName : "")
|
||||||
property string roomTopic: room ? room.roomTopic : (roomPreview ? roomPreview.roomTopic : "")
|
property string roomTopic: room ? room.roomTopic : (roomPreview ? roomPreview.roomTopic : "")
|
||||||
property string avatarUrl: room ? room.roomAvatarUrl : (roomPreview ? roomPreview.roomAvatarUrl : "")
|
property string avatarUrl: room ? room.roomAvatarUrl : (roomPreview ? roomPreview.roomAvatarUrl : "")
|
||||||
@ -153,6 +154,7 @@ Item {
|
|||||||
|
|
||||||
Avatar {
|
Avatar {
|
||||||
url: parent.avatarUrl.replace("mxc://", "image://MxcImage/")
|
url: parent.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
|
roomid: parent.roomId
|
||||||
displayName: parent.roomName
|
displayName: parent.roomName
|
||||||
height: 130
|
height: 130
|
||||||
width: 130
|
width: 130
|
||||||
|
@ -13,10 +13,13 @@ Rectangle {
|
|||||||
|
|
||||||
property bool showBackButton: false
|
property bool showBackButton: false
|
||||||
property string roomName: room ? room.roomName : qsTr("No room selected")
|
property string roomName: room ? room.roomName : qsTr("No room selected")
|
||||||
|
property string roomId: room ? room.roomId : ""
|
||||||
property string avatarUrl: room ? room.roomAvatarUrl : ""
|
property string avatarUrl: room ? room.roomAvatarUrl : ""
|
||||||
property string roomTopic: room ? room.roomTopic : ""
|
property string roomTopic: room ? room.roomTopic : ""
|
||||||
property bool isEncrypted: room ? room.isEncrypted : false
|
property bool isEncrypted: room ? room.isEncrypted : false
|
||||||
property int trustlevel: room ? room.trustlevel : Crypto.Unverified
|
property int trustlevel: room ? room.trustlevel : Crypto.Unverified
|
||||||
|
property bool isDirect: room ? room.isDirect : false
|
||||||
|
property string directChatOtherUserId: room ? room.directChatOtherUserId : ""
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
implicitHeight: topLayout.height + Nheko.paddingMedium * 2
|
implicitHeight: topLayout.height + Nheko.paddingMedium * 2
|
||||||
@ -65,10 +68,12 @@ Rectangle {
|
|||||||
width: Nheko.avatarSize
|
width: Nheko.avatarSize
|
||||||
height: Nheko.avatarSize
|
height: Nheko.avatarSize
|
||||||
url: avatarUrl.replace("mxc://", "image://MxcImage/")
|
url: avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
|
roomid: roomId
|
||||||
|
userid: isDirect ? directChatOtherUserId : ""
|
||||||
displayName: roomName
|
displayName: roomName
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (room)
|
if (room)
|
||||||
TimelineManager.openRoomSettings(room.roomId);
|
TimelineManager.openRoomSettings(roomId);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -135,7 +140,7 @@ Rectangle {
|
|||||||
Platform.MenuItem {
|
Platform.MenuItem {
|
||||||
visible: room ? room.permissions.canInvite() : false
|
visible: room ? room.permissions.canInvite() : false
|
||||||
text: qsTr("Invite users")
|
text: qsTr("Invite users")
|
||||||
onTriggered: TimelineManager.openInviteUsers(room.roomId)
|
onTriggered: TimelineManager.openInviteUsers(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform.MenuItem {
|
Platform.MenuItem {
|
||||||
@ -145,12 +150,12 @@ Rectangle {
|
|||||||
|
|
||||||
Platform.MenuItem {
|
Platform.MenuItem {
|
||||||
text: qsTr("Leave room")
|
text: qsTr("Leave room")
|
||||||
onTriggered: TimelineManager.openLeaveRoomDialog(room.roomId)
|
onTriggered: TimelineManager.openLeaveRoomDialog(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
Platform.MenuItem {
|
Platform.MenuItem {
|
||||||
text: qsTr("Settings")
|
text: qsTr("Settings")
|
||||||
onTriggered: TimelineManager.openRoomSettings(room.roomId)
|
onTriggered: TimelineManager.openRoomSettings(roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ Rectangle {
|
|||||||
required property int index
|
required property int index
|
||||||
required property int selectedIndex
|
required property int selectedIndex
|
||||||
property bool crop: true
|
property bool crop: true
|
||||||
|
property alias roomid: avatar.roomid
|
||||||
|
property alias userid: avatar.userid
|
||||||
|
|
||||||
color: background
|
color: background
|
||||||
height: avatarSize + 2 * Nheko.paddingMedium
|
height: avatarSize + 2 * Nheko.paddingMedium
|
||||||
|
@ -61,6 +61,7 @@ ApplicationWindow {
|
|||||||
header: AvatarListTile {
|
header: AvatarListTile {
|
||||||
title: imagePack.packname
|
title: imagePack.packname
|
||||||
avatarUrl: imagePack.avatarUrl
|
avatarUrl: imagePack.avatarUrl
|
||||||
|
roomid: imagePack.statekey
|
||||||
subtitle: imagePack.statekey
|
subtitle: imagePack.statekey
|
||||||
index: -1
|
index: -1
|
||||||
selectedIndex: currentImageIndex
|
selectedIndex: currentImageIndex
|
||||||
@ -142,6 +143,7 @@ ApplicationWindow {
|
|||||||
Layout.columnSpan: 2
|
Layout.columnSpan: 2
|
||||||
url: imagePack.avatarUrl.replace("mxc://", "image://MxcImage/")
|
url: imagePack.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: imagePack.packname
|
displayName: imagePack.packname
|
||||||
|
roomid: imagePack.statekey
|
||||||
height: 130
|
height: 130
|
||||||
width: 130
|
width: 130
|
||||||
crop: false
|
crop: false
|
||||||
@ -219,6 +221,7 @@ ApplicationWindow {
|
|||||||
Layout.columnSpan: 2
|
Layout.columnSpan: 2
|
||||||
url: imagePack.data(imagePack.index(currentImageIndex, 0), SingleImagePackModel.Url).replace("mxc://", "image://MxcImage/")
|
url: imagePack.data(imagePack.index(currentImageIndex, 0), SingleImagePackModel.Url).replace("mxc://", "image://MxcImage/")
|
||||||
displayName: imagePack.data(imagePack.index(currentImageIndex, 0), SingleImagePackModel.ShortCode)
|
displayName: imagePack.data(imagePack.index(currentImageIndex, 0), SingleImagePackModel.ShortCode)
|
||||||
|
roomid: displayName
|
||||||
height: 130
|
height: 130
|
||||||
width: 130
|
width: 130
|
||||||
crop: false
|
crop: false
|
||||||
|
@ -112,6 +112,7 @@ ApplicationWindow {
|
|||||||
return qsTr("Globally enabled pack");
|
return qsTr("Globally enabled pack");
|
||||||
}
|
}
|
||||||
selectedIndex: currentPackIndex
|
selectedIndex: currentPackIndex
|
||||||
|
roomid: currentPack.statekey
|
||||||
|
|
||||||
TapHandler {
|
TapHandler {
|
||||||
onSingleTapped: currentPackIndex = index
|
onSingleTapped: currentPackIndex = index
|
||||||
@ -135,6 +136,7 @@ ApplicationWindow {
|
|||||||
property string packName: currentPack ? currentPack.packname : ""
|
property string packName: currentPack ? currentPack.packname : ""
|
||||||
property string attribution: currentPack ? currentPack.attribution : ""
|
property string attribution: currentPack ? currentPack.attribution : ""
|
||||||
property string avatarUrl: currentPack ? currentPack.avatarUrl : ""
|
property string avatarUrl: currentPack ? currentPack.avatarUrl : ""
|
||||||
|
property string statekey: currentPack ? currentPack.statekey : ""
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Nheko.paddingLarge
|
anchors.margins: Nheko.paddingLarge
|
||||||
@ -143,6 +145,7 @@ ApplicationWindow {
|
|||||||
Avatar {
|
Avatar {
|
||||||
url: packinfo.avatarUrl.replace("mxc://", "image://MxcImage/")
|
url: packinfo.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: packinfo.packName
|
displayName: packinfo.packName
|
||||||
|
roomid: packinfo.statekey
|
||||||
height: 100
|
height: 100
|
||||||
width: 100
|
width: 100
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
@ -34,14 +34,15 @@ Rectangle {
|
|||||||
width: Nheko.avatarSize
|
width: Nheko.avatarSize
|
||||||
height: Nheko.avatarSize
|
height: Nheko.avatarSize
|
||||||
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: CallManager.callParty
|
userid: CallManager.callParty
|
||||||
|
displayName: CallManager.callPartyDisplayName
|
||||||
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
|
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
Layout.leftMargin: 8
|
Layout.leftMargin: 8
|
||||||
font.pointSize: fontMetrics.font.pointSize * 1.1
|
font.pointSize: fontMetrics.font.pointSize * 1.1
|
||||||
text: CallManager.callParty
|
text: CallManager.callPartyDisplayName
|
||||||
color: "#000000"
|
color: "#000000"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ Popup {
|
|||||||
Label {
|
Label {
|
||||||
Layout.alignment: Qt.AlignCenter
|
Layout.alignment: Qt.AlignCenter
|
||||||
Layout.topMargin: msgView.height / 25
|
Layout.topMargin: msgView.height / 25
|
||||||
text: CallManager.callParty
|
text: CallManager.callPartyDisplayName
|
||||||
font.pointSize: fontMetrics.font.pointSize * 2
|
font.pointSize: fontMetrics.font.pointSize * 2
|
||||||
color: Nheko.colors.windowText
|
color: Nheko.colors.windowText
|
||||||
}
|
}
|
||||||
@ -50,7 +50,8 @@ Popup {
|
|||||||
width: msgView.height / 5
|
width: msgView.height / 5
|
||||||
height: msgView.height / 5
|
height: msgView.height / 5
|
||||||
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: CallManager.callParty
|
userid: CallManager.callParty
|
||||||
|
displayName: CallManager.callPartyDisplayName
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
@ -41,14 +41,15 @@ Rectangle {
|
|||||||
width: Nheko.avatarSize
|
width: Nheko.avatarSize
|
||||||
height: Nheko.avatarSize
|
height: Nheko.avatarSize
|
||||||
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: CallManager.callParty
|
userid: CallManager.callParty
|
||||||
|
displayName: CallManager.callPartyDisplayName
|
||||||
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
|
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
Layout.leftMargin: 8
|
Layout.leftMargin: 8
|
||||||
font.pointSize: fontMetrics.font.pointSize * 1.1
|
font.pointSize: fontMetrics.font.pointSize * 1.1
|
||||||
text: CallManager.callParty
|
text: CallManager.callPartyDisplayName
|
||||||
color: "#000000"
|
color: "#000000"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ Popup {
|
|||||||
height: Nheko.avatarSize
|
height: Nheko.avatarSize
|
||||||
url: room.roomAvatarUrl.replace("mxc://", "image://MxcImage/")
|
url: room.roomAvatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
displayName: room.roomName
|
displayName: room.roomName
|
||||||
|
roomid: room.roomid
|
||||||
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
|
onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2776,6 +2776,46 @@ Cache::getMembers(const std::string &room_id, std::size_t startIndex, std::size_
|
|||||||
return members;
|
return members;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<RoomMember>
|
||||||
|
Cache::getMembersFromInvite(const std::string &room_id, std::size_t startIndex, std::size_t len)
|
||||||
|
{
|
||||||
|
auto txn = ro_txn(env_);
|
||||||
|
auto db = getInviteMembersDb(txn, room_id);
|
||||||
|
auto cursor = lmdb::cursor::open(txn, db);
|
||||||
|
|
||||||
|
std::size_t currentIndex = 0;
|
||||||
|
|
||||||
|
const auto endIndex = std::min(startIndex + len, db.size(txn));
|
||||||
|
|
||||||
|
std::vector<RoomMember> members;
|
||||||
|
|
||||||
|
std::string_view user_id, user_data;
|
||||||
|
while (cursor.get(user_id, user_data, MDB_NEXT)) {
|
||||||
|
if (currentIndex < startIndex) {
|
||||||
|
currentIndex += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentIndex >= endIndex)
|
||||||
|
break;
|
||||||
|
|
||||||
|
try {
|
||||||
|
MemberInfo tmp = json::parse(user_data);
|
||||||
|
members.emplace_back(
|
||||||
|
RoomMember{QString::fromStdString(std::string(user_id)),
|
||||||
|
QString::fromStdString(tmp.name)});
|
||||||
|
} catch (const json::exception &e) {
|
||||||
|
nhlog::db()->warn("{}", e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
currentIndex += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor.close();
|
||||||
|
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Cache::isRoomMember(const std::string &user_id, const std::string &room_id)
|
Cache::isRoomMember(const std::string &user_id, const std::string &room_id)
|
||||||
{
|
{
|
||||||
@ -4808,6 +4848,12 @@ getMembers(const std::string &room_id, std::size_t startIndex, std::size_t len)
|
|||||||
return instance_->getMembers(room_id, startIndex, len);
|
return instance_->getMembers(room_id, startIndex, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<RoomMember>
|
||||||
|
getMembersFromInvite(const std::string &room_id, std::size_t startIndex, std::size_t len)
|
||||||
|
{
|
||||||
|
return instance_->getMembersFromInvite(room_id, startIndex, len);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
saveState(const mtx::responses::Sync &res)
|
saveState(const mtx::responses::Sync &res)
|
||||||
{
|
{
|
||||||
|
@ -83,6 +83,9 @@ getRoomAvatarUrl(lmdb::txn &txn, lmdb::dbi &statesdb, lmdb::dbi &membersdb);
|
|||||||
//! Retrieve member info from a room.
|
//! Retrieve member info from a room.
|
||||||
std::vector<RoomMember>
|
std::vector<RoomMember>
|
||||||
getMembers(const std::string &room_id, std::size_t startIndex = 0, std::size_t len = 30);
|
getMembers(const std::string &room_id, std::size_t startIndex = 0, std::size_t len = 30);
|
||||||
|
//! Retrive member info from an invite.
|
||||||
|
std::vector<RoomMember>
|
||||||
|
getMembersFromInvite(const std::string &room_id, std::size_t start_index = 0, std::size_t len = 30);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
isInitialized();
|
isInitialized();
|
||||||
|
@ -93,7 +93,7 @@ to_json(nlohmann::json &j, const RoomInfo &info);
|
|||||||
void
|
void
|
||||||
from_json(const nlohmann::json &j, RoomInfo &info);
|
from_json(const nlohmann::json &j, RoomInfo &info);
|
||||||
|
|
||||||
//! Basic information per member;
|
//! Basic information per member.
|
||||||
struct MemberInfo
|
struct MemberInfo
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
|
@ -106,6 +106,10 @@ public:
|
|||||||
std::vector<RoomMember> getMembers(const std::string &room_id,
|
std::vector<RoomMember> getMembers(const std::string &room_id,
|
||||||
std::size_t startIndex = 0,
|
std::size_t startIndex = 0,
|
||||||
std::size_t len = 30);
|
std::size_t len = 30);
|
||||||
|
|
||||||
|
std::vector<RoomMember> getMembersFromInvite(const std::string &room_id,
|
||||||
|
std::size_t startIndex = 0,
|
||||||
|
std::size_t len = 30);
|
||||||
size_t memberCount(const std::string &room_id);
|
size_t memberCount(const std::string &room_id);
|
||||||
|
|
||||||
void saveState(const mtx::responses::Sync &res);
|
void saveState(const mtx::responses::Sync &res);
|
||||||
@ -132,6 +136,9 @@ public:
|
|||||||
//! Retrieve all the user ids from a room.
|
//! Retrieve all the user ids from a room.
|
||||||
std::vector<std::string> roomMembers(const std::string &room_id);
|
std::vector<std::string> roomMembers(const std::string &room_id);
|
||||||
|
|
||||||
|
//! Get the other user from an invite to a direct chat.
|
||||||
|
RoomMember getDirectInviteMember(const std::string &room_id);
|
||||||
|
|
||||||
//! Check if the given user has power leve greater than than
|
//! Check if the given user has power leve greater than than
|
||||||
//! lowest power level of the given events.
|
//! lowest power level of the given events.
|
||||||
bool hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,
|
bool hasEnoughPowerLevel(const std::vector<mtx::events::EventType> &eventTypes,
|
||||||
@ -310,7 +317,6 @@ public:
|
|||||||
|
|
||||||
return get_skey(a).compare(get_skey(b));
|
return get_skey(a).compare(get_skey(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void newReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
void newReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
|
||||||
void roomReadStatus(const std::map<QString, bool> &status);
|
void roomReadStatus(const std::map<QString, bool> &status);
|
||||||
|
@ -206,7 +206,9 @@ CallManager::sendInvite(const QString &roomid, CallType callType, unsigned int w
|
|||||||
std::vector<RoomMember> members(cache::getMembers(roomid.toStdString()));
|
std::vector<RoomMember> members(cache::getMembers(roomid.toStdString()));
|
||||||
const RoomMember &callee =
|
const RoomMember &callee =
|
||||||
members.front().user_id == utils::localUser() ? members.back() : members.front();
|
members.front().user_id == utils::localUser() ? members.back() : members.front();
|
||||||
callParty_ = callee.display_name.isEmpty() ? callee.user_id : callee.display_name;
|
callParty_ = callee.user_id;
|
||||||
|
callPartyDisplayName_ =
|
||||||
|
callee.display_name.isEmpty() ? callee.user_id : callee.display_name;
|
||||||
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
|
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
|
||||||
emit newInviteState();
|
emit newInviteState();
|
||||||
playRingtone(QUrl("qrc:/media/media/ringback.ogg"), true);
|
playRingtone(QUrl("qrc:/media/media/ringback.ogg"), true);
|
||||||
@ -308,7 +310,9 @@ CallManager::handleEvent(const RoomEvent<CallInvite> &callInviteEvent)
|
|||||||
std::vector<RoomMember> members(cache::getMembers(callInviteEvent.room_id));
|
std::vector<RoomMember> members(cache::getMembers(callInviteEvent.room_id));
|
||||||
const RoomMember &caller =
|
const RoomMember &caller =
|
||||||
members.front().user_id == utils::localUser() ? members.back() : members.front();
|
members.front().user_id == utils::localUser() ? members.back() : members.front();
|
||||||
callParty_ = caller.display_name.isEmpty() ? caller.user_id : caller.display_name;
|
callParty_ = caller.user_id;
|
||||||
|
callPartyDisplayName_ =
|
||||||
|
caller.display_name.isEmpty() ? caller.user_id : caller.display_name;
|
||||||
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
|
callPartyAvatarUrl_ = QString::fromStdString(roomInfo.avatar_url);
|
||||||
|
|
||||||
haveCallInvite_ = true;
|
haveCallInvite_ = true;
|
||||||
@ -459,6 +463,7 @@ CallManager::clear()
|
|||||||
{
|
{
|
||||||
roomid_.clear();
|
roomid_.clear();
|
||||||
callParty_.clear();
|
callParty_.clear();
|
||||||
|
callPartyDisplayName_.clear();
|
||||||
callPartyAvatarUrl_.clear();
|
callPartyAvatarUrl_.clear();
|
||||||
callid_.clear();
|
callid_.clear();
|
||||||
callType_ = CallType::VOICE;
|
callType_ = CallType::VOICE;
|
||||||
|
@ -32,6 +32,7 @@ class CallManager : public QObject
|
|||||||
Q_PROPERTY(webrtc::CallType callType READ callType NOTIFY newInviteState)
|
Q_PROPERTY(webrtc::CallType callType READ callType NOTIFY newInviteState)
|
||||||
Q_PROPERTY(webrtc::State callState READ callState NOTIFY newCallState)
|
Q_PROPERTY(webrtc::State callState READ callState NOTIFY newCallState)
|
||||||
Q_PROPERTY(QString callParty READ callParty NOTIFY newInviteState)
|
Q_PROPERTY(QString callParty READ callParty NOTIFY newInviteState)
|
||||||
|
Q_PROPERTY(QString callPartyDisplayName READ callPartyDisplayName NOTIFY newInviteState)
|
||||||
Q_PROPERTY(QString callPartyAvatarUrl READ callPartyAvatarUrl NOTIFY newInviteState)
|
Q_PROPERTY(QString callPartyAvatarUrl READ callPartyAvatarUrl NOTIFY newInviteState)
|
||||||
Q_PROPERTY(bool isMicMuted READ isMicMuted NOTIFY micMuteChanged)
|
Q_PROPERTY(bool isMicMuted READ isMicMuted NOTIFY micMuteChanged)
|
||||||
Q_PROPERTY(bool haveLocalPiP READ haveLocalPiP NOTIFY newCallState)
|
Q_PROPERTY(bool haveLocalPiP READ haveLocalPiP NOTIFY newCallState)
|
||||||
@ -48,6 +49,7 @@ public:
|
|||||||
webrtc::CallType callType() const { return callType_; }
|
webrtc::CallType callType() const { return callType_; }
|
||||||
webrtc::State callState() const { return session_.state(); }
|
webrtc::State callState() const { return session_.state(); }
|
||||||
QString callParty() const { return callParty_; }
|
QString callParty() const { return callParty_; }
|
||||||
|
QString callPartyDisplayName() const { return callPartyDisplayName_; }
|
||||||
QString callPartyAvatarUrl() const { return callPartyAvatarUrl_; }
|
QString callPartyAvatarUrl() const { return callPartyAvatarUrl_; }
|
||||||
bool isMicMuted() const { return session_.isMicMuted(); }
|
bool isMicMuted() const { return session_.isMicMuted(); }
|
||||||
bool haveLocalPiP() const { return session_.haveLocalPiP(); }
|
bool haveLocalPiP() const { return session_.haveLocalPiP(); }
|
||||||
@ -87,6 +89,7 @@ private:
|
|||||||
WebRTCSession &session_;
|
WebRTCSession &session_;
|
||||||
QString roomid_;
|
QString roomid_;
|
||||||
QString callParty_;
|
QString callParty_;
|
||||||
|
QString callPartyDisplayName_;
|
||||||
QString callPartyAvatarUrl_;
|
QString callPartyAvatarUrl_;
|
||||||
std::string callid_;
|
std::string callid_;
|
||||||
const uint32_t timeoutms_ = 120000;
|
const uint32_t timeoutms_ = 120000;
|
||||||
|
107
src/JdenticonProvider.cpp
Normal file
107
src/JdenticonProvider.cpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "JdenticonProvider.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPainterPath>
|
||||||
|
#include <QPluginLoader>
|
||||||
|
#include <QSvgRenderer>
|
||||||
|
|
||||||
|
#include <mtxclient/crypto/client.hpp>
|
||||||
|
|
||||||
|
#include "Cache.h"
|
||||||
|
#include "Logging.h"
|
||||||
|
#include "MatrixClient.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "jdenticoninterface.h"
|
||||||
|
|
||||||
|
static QPixmap
|
||||||
|
clipRadius(QPixmap img, double radius)
|
||||||
|
{
|
||||||
|
QPixmap out(img.size());
|
||||||
|
out.fill(Qt::transparent);
|
||||||
|
|
||||||
|
QPainter painter(&out);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||||
|
|
||||||
|
QPainterPath ppath;
|
||||||
|
ppath.addRoundedRect(img.rect(), radius, radius, Qt::SizeMode::RelativeSize);
|
||||||
|
|
||||||
|
painter.setClipPath(ppath);
|
||||||
|
painter.drawPixmap(img.rect(), img);
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
JdenticonResponse::JdenticonResponse(const QString &key,
|
||||||
|
bool crop,
|
||||||
|
double radius,
|
||||||
|
const QSize &requestedSize)
|
||||||
|
: m_key(key)
|
||||||
|
, m_crop{crop}
|
||||||
|
, m_radius{radius}
|
||||||
|
, m_requestedSize(requestedSize.isValid() ? requestedSize : QSize(100, 100))
|
||||||
|
, m_pixmap{m_requestedSize}
|
||||||
|
, jdenticonInterface_{Jdenticon::getJdenticonInterface()}
|
||||||
|
{
|
||||||
|
setAutoDelete(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
JdenticonResponse::run()
|
||||||
|
{
|
||||||
|
m_pixmap.fill(Qt::transparent);
|
||||||
|
|
||||||
|
QPainter painter;
|
||||||
|
painter.begin(&m_pixmap);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing, true);
|
||||||
|
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
|
||||||
|
|
||||||
|
QSvgRenderer renderer{
|
||||||
|
jdenticonInterface_->generate(m_key, m_requestedSize.width()).toUtf8()};
|
||||||
|
renderer.render(&painter);
|
||||||
|
|
||||||
|
painter.end();
|
||||||
|
|
||||||
|
m_pixmap = clipRadius(m_pixmap, m_radius);
|
||||||
|
|
||||||
|
emit finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Jdenticon {
|
||||||
|
JdenticonInterface *
|
||||||
|
getJdenticonInterface()
|
||||||
|
{
|
||||||
|
static JdenticonInterface *interface = nullptr;
|
||||||
|
static bool interfaceExists{true};
|
||||||
|
|
||||||
|
if (interface == nullptr && interfaceExists) {
|
||||||
|
QDir pluginsDir(qApp->applicationDirPath());
|
||||||
|
|
||||||
|
bool plugins = pluginsDir.cd("plugins");
|
||||||
|
if (plugins) {
|
||||||
|
for (const QString &fileName : pluginsDir.entryList(QDir::Files)) {
|
||||||
|
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
|
||||||
|
QObject *plugin = pluginLoader.instance();
|
||||||
|
if (plugin) {
|
||||||
|
interface = qobject_cast<JdenticonInterface *>(plugin);
|
||||||
|
if (interface) {
|
||||||
|
nhlog::ui()->info("Loaded jdenticon plugin.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nhlog::ui()->info("jdenticon plugin not found.");
|
||||||
|
interfaceExists = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return interface;
|
||||||
|
}
|
||||||
|
}
|
81
src/JdenticonProvider.h
Normal file
81
src/JdenticonProvider.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2021 Nheko Contributors
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QImage>
|
||||||
|
#include <QQuickAsyncImageProvider>
|
||||||
|
#include <QQuickImageResponse>
|
||||||
|
#include <QThreadPool>
|
||||||
|
|
||||||
|
#include <mtx/common.hpp>
|
||||||
|
|
||||||
|
#include "jdenticoninterface.h"
|
||||||
|
|
||||||
|
namespace Jdenticon {
|
||||||
|
JdenticonInterface *
|
||||||
|
getJdenticonInterface();
|
||||||
|
}
|
||||||
|
|
||||||
|
class JdenticonResponse
|
||||||
|
: public QQuickImageResponse
|
||||||
|
, public QRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
JdenticonResponse(const QString &key, bool crop, double radius, const QSize &requestedSize);
|
||||||
|
|
||||||
|
QQuickTextureFactory *textureFactory() const override
|
||||||
|
{
|
||||||
|
return QQuickTextureFactory::textureFactoryForImage(m_pixmap.toImage());
|
||||||
|
}
|
||||||
|
|
||||||
|
void run() override;
|
||||||
|
|
||||||
|
QString m_key;
|
||||||
|
bool m_crop;
|
||||||
|
double m_radius;
|
||||||
|
QSize m_requestedSize;
|
||||||
|
QPixmap m_pixmap;
|
||||||
|
JdenticonInterface *jdenticonInterface_ = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class JdenticonProvider
|
||||||
|
: public QObject
|
||||||
|
, public QQuickAsyncImageProvider
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
static bool isAvailable() { return Jdenticon::getJdenticonInterface() != nullptr; }
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
QQuickImageResponse *requestImageResponse(const QString &id,
|
||||||
|
const QSize &requestedSize) override
|
||||||
|
{
|
||||||
|
auto id_ = id;
|
||||||
|
bool crop = true;
|
||||||
|
double radius = 0;
|
||||||
|
|
||||||
|
auto queryStart = id.lastIndexOf('?');
|
||||||
|
if (queryStart != -1) {
|
||||||
|
id_ = id.left(queryStart);
|
||||||
|
auto query = id.midRef(queryStart + 1);
|
||||||
|
auto queryBits = query.split('&');
|
||||||
|
|
||||||
|
for (auto b : queryBits) {
|
||||||
|
if (b.startsWith("radius=")) {
|
||||||
|
radius = b.mid(7).toDouble();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JdenticonResponse *response =
|
||||||
|
new JdenticonResponse(id_, crop, radius, requestedSize);
|
||||||
|
pool.start(response);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QThreadPool pool;
|
||||||
|
};
|
@ -16,6 +16,7 @@
|
|||||||
#include "Cache_p.h"
|
#include "Cache_p.h"
|
||||||
#include "ChatPage.h"
|
#include "ChatPage.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
#include "JdenticonProvider.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "LoginPage.h"
|
#include "LoginPage.h"
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
@ -152,10 +153,6 @@ MainWindow::MainWindow(QWidget *parent)
|
|||||||
showChatPage();
|
showChatPage();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (loadJdenticonPlugin()) {
|
|
||||||
nhlog::ui()->info("loaded jdenticon.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -428,29 +425,6 @@ MainWindow::showDialog(QWidget *dialog)
|
|||||||
dialog->show();
|
dialog->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
MainWindow::loadJdenticonPlugin()
|
|
||||||
{
|
|
||||||
QDir pluginsDir(qApp->applicationDirPath());
|
|
||||||
|
|
||||||
bool plugins = pluginsDir.cd("plugins");
|
|
||||||
if (plugins) {
|
|
||||||
foreach (QString fileName, pluginsDir.entryList(QDir::Files)) {
|
|
||||||
QPluginLoader pluginLoader(pluginsDir.absoluteFilePath(fileName));
|
|
||||||
QObject *plugin = pluginLoader.instance();
|
|
||||||
if (plugin) {
|
|
||||||
jdenticonInteface_ = qobject_cast<JdenticonInterface *>(plugin);
|
|
||||||
if (jdenticonInteface_) {
|
|
||||||
nhlog::ui()->info("Found jdenticon plugin.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
nhlog::ui()->info("jdenticon plugin not found.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void
|
void
|
||||||
MainWindow::showWelcomePage()
|
MainWindow::showWelcomePage()
|
||||||
{
|
{
|
||||||
|
@ -106,8 +106,6 @@ signals:
|
|||||||
void reload();
|
void reload();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool loadJdenticonPlugin();
|
|
||||||
|
|
||||||
void showDialog(QWidget *dialog);
|
void showDialog(QWidget *dialog);
|
||||||
bool hasActiveUser();
|
bool hasActiveUser();
|
||||||
void restoreWindowSize();
|
void restoreWindowSize();
|
||||||
@ -137,6 +135,4 @@ private:
|
|||||||
//! Overlay modal used to project other widgets.
|
//! Overlay modal used to project other widgets.
|
||||||
OverlayModal *modal_ = nullptr;
|
OverlayModal *modal_ = nullptr;
|
||||||
LoadingIndicator *spinner_ = nullptr;
|
LoadingIndicator *spinner_ = nullptr;
|
||||||
|
|
||||||
JdenticonInterface *jdenticonInteface_ = nullptr;
|
|
||||||
};
|
};
|
||||||
|
@ -86,6 +86,7 @@ UserSettings::load(std::optional<QString> profile)
|
|||||||
theme_ = settings.value("user/theme", defaultTheme_).toString();
|
theme_ = settings.value("user/theme", defaultTheme_).toString();
|
||||||
font_ = settings.value("user/font_family", "default").toString();
|
font_ = settings.value("user/font_family", "default").toString();
|
||||||
avatarCircles_ = settings.value("user/avatar_circles", true).toBool();
|
avatarCircles_ = settings.value("user/avatar_circles", true).toBool();
|
||||||
|
useIdenticon_ = settings.value("user/use_identicon", true).toBool();
|
||||||
decryptSidebar_ = settings.value("user/decrypt_sidebar", true).toBool();
|
decryptSidebar_ = settings.value("user/decrypt_sidebar", true).toBool();
|
||||||
privacyScreen_ = settings.value("user/privacy_screen", false).toBool();
|
privacyScreen_ = settings.value("user/privacy_screen", false).toBool();
|
||||||
privacyScreenTimeout_ = settings.value("user/privacy_screen_timeout", 0).toInt();
|
privacyScreenTimeout_ = settings.value("user/privacy_screen_timeout", 0).toInt();
|
||||||
@ -596,6 +597,15 @@ UserSettings::setDisableCertificateValidation(bool disabled)
|
|||||||
disableCertificateValidation_ = disabled;
|
disableCertificateValidation_ = disabled;
|
||||||
http::client()->verify_certificates(!disabled);
|
http::client()->verify_certificates(!disabled);
|
||||||
emit disableCertificateValidationChanged(disabled);
|
emit disableCertificateValidationChanged(disabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
UserSettings::setUseIdenticon(bool state)
|
||||||
|
{
|
||||||
|
if (state == useIdenticon_)
|
||||||
|
return;
|
||||||
|
useIdenticon_ = state;
|
||||||
|
emit useIdenticonChanged(useIdenticon_);
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -674,6 +684,7 @@ UserSettings::save()
|
|||||||
settings.setValue("screen_share_hide_cursor", screenShareHideCursor_);
|
settings.setValue("screen_share_hide_cursor", screenShareHideCursor_);
|
||||||
settings.setValue("use_stun_server", useStunServer_);
|
settings.setValue("use_stun_server", useStunServer_);
|
||||||
settings.setValue("currentProfile", profile_);
|
settings.setValue("currentProfile", profile_);
|
||||||
|
settings.setValue("use_identicon", useIdenticon_);
|
||||||
|
|
||||||
settings.endGroup(); // user
|
settings.endGroup(); // user
|
||||||
|
|
||||||
@ -746,6 +757,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
|||||||
trayToggle_ = new Toggle{this};
|
trayToggle_ = new Toggle{this};
|
||||||
startInTrayToggle_ = new Toggle{this};
|
startInTrayToggle_ = new Toggle{this};
|
||||||
avatarCircles_ = new Toggle{this};
|
avatarCircles_ = new Toggle{this};
|
||||||
|
useIdenticon_ = new Toggle{this};
|
||||||
decryptSidebar_ = new Toggle(this);
|
decryptSidebar_ = new Toggle(this);
|
||||||
privacyScreen_ = new Toggle{this};
|
privacyScreen_ = new Toggle{this};
|
||||||
onlyShareKeysWithVerifiedUsers_ = new Toggle(this);
|
onlyShareKeysWithVerifiedUsers_ = new Toggle(this);
|
||||||
@ -779,6 +791,7 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
|||||||
trayToggle_->setChecked(settings_->tray());
|
trayToggle_->setChecked(settings_->tray());
|
||||||
startInTrayToggle_->setChecked(settings_->startInTray());
|
startInTrayToggle_->setChecked(settings_->startInTray());
|
||||||
avatarCircles_->setChecked(settings_->avatarCircles());
|
avatarCircles_->setChecked(settings_->avatarCircles());
|
||||||
|
useIdenticon_->setChecked(settings_->useIdenticon());
|
||||||
decryptSidebar_->setChecked(settings_->decryptSidebar());
|
decryptSidebar_->setChecked(settings_->decryptSidebar());
|
||||||
privacyScreen_->setChecked(settings_->privacyScreen());
|
privacyScreen_->setChecked(settings_->privacyScreen());
|
||||||
onlyShareKeysWithVerifiedUsers_->setChecked(settings_->onlyShareKeysWithVerifiedUsers());
|
onlyShareKeysWithVerifiedUsers_->setChecked(settings_->onlyShareKeysWithVerifiedUsers());
|
||||||
@ -941,6 +954,9 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
|||||||
boxWrap(tr("Circular Avatars"),
|
boxWrap(tr("Circular Avatars"),
|
||||||
avatarCircles_,
|
avatarCircles_,
|
||||||
tr("Change the appearance of user avatars in chats.\nOFF - square, ON - Circle."));
|
tr("Change the appearance of user avatars in chats.\nOFF - square, ON - Circle."));
|
||||||
|
boxWrap(tr("Use identicons"),
|
||||||
|
useIdenticon_,
|
||||||
|
tr("Display an identicon instead of a letter when a user has not set an avatar."));
|
||||||
boxWrap(tr("Group's sidebar"),
|
boxWrap(tr("Group's sidebar"),
|
||||||
groupViewToggle_,
|
groupViewToggle_,
|
||||||
tr("Show a column containing groups and tags next to the room list."));
|
tr("Show a column containing groups and tags next to the room list."));
|
||||||
@ -1263,6 +1279,13 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
|
|||||||
settings_->setAvatarCircles(enabled);
|
settings_->setAvatarCircles(enabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (JdenticonProvider::isAvailable())
|
||||||
|
connect(useIdenticon_, &Toggle::toggled, this, [this](bool enabled) {
|
||||||
|
settings_->setUseIdenticon(enabled);
|
||||||
|
});
|
||||||
|
else
|
||||||
|
useIdenticon_->setDisabled(true);
|
||||||
|
|
||||||
connect(markdown_, &Toggle::toggled, this, [this](bool enabled) {
|
connect(markdown_, &Toggle::toggled, this, [this](bool enabled) {
|
||||||
settings_->setMarkdown(enabled);
|
settings_->setMarkdown(enabled);
|
||||||
});
|
});
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <QSharedPointer>
|
#include <QSharedPointer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "JdenticonProvider.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
class Toggle;
|
class Toggle;
|
||||||
@ -105,6 +106,8 @@ class UserSettings : public QObject
|
|||||||
Q_PROPERTY(QString homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged)
|
Q_PROPERTY(QString homeserver READ homeserver WRITE setHomeserver NOTIFY homeserverChanged)
|
||||||
Q_PROPERTY(bool disableCertificateValidation READ disableCertificateValidation WRITE
|
Q_PROPERTY(bool disableCertificateValidation READ disableCertificateValidation WRITE
|
||||||
setDisableCertificateValidation NOTIFY disableCertificateValidationChanged)
|
setDisableCertificateValidation NOTIFY disableCertificateValidationChanged)
|
||||||
|
Q_PROPERTY(
|
||||||
|
bool useIdenticon READ useIdenticon WRITE setUseIdenticon NOTIFY useIdenticonChanged)
|
||||||
|
|
||||||
UserSettings();
|
UserSettings();
|
||||||
|
|
||||||
@ -172,6 +175,7 @@ public:
|
|||||||
void setHomeserver(QString homeserver);
|
void setHomeserver(QString homeserver);
|
||||||
void setDisableCertificateValidation(bool disabled);
|
void setDisableCertificateValidation(bool disabled);
|
||||||
void setHiddenTags(QStringList hiddenTags);
|
void setHiddenTags(QStringList hiddenTags);
|
||||||
|
void setUseIdenticon(bool state);
|
||||||
|
|
||||||
QString theme() const { return !theme_.isEmpty() ? theme_ : defaultTheme_; }
|
QString theme() const { return !theme_.isEmpty() ? theme_ : defaultTheme_; }
|
||||||
bool messageHoverHighlight() const { return messageHoverHighlight_; }
|
bool messageHoverHighlight() const { return messageHoverHighlight_; }
|
||||||
@ -230,6 +234,7 @@ public:
|
|||||||
QString homeserver() const { return homeserver_; }
|
QString homeserver() const { return homeserver_; }
|
||||||
bool disableCertificateValidation() const { return disableCertificateValidation_; }
|
bool disableCertificateValidation() const { return disableCertificateValidation_; }
|
||||||
QStringList hiddenTags() const { return hiddenTags_; }
|
QStringList hiddenTags() const { return hiddenTags_; }
|
||||||
|
bool useIdenticon() const { return useIdenticon_ && JdenticonProvider::isAvailable(); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void groupViewStateChanged(bool state);
|
void groupViewStateChanged(bool state);
|
||||||
@ -277,6 +282,7 @@ signals:
|
|||||||
void deviceIdChanged(QString deviceId);
|
void deviceIdChanged(QString deviceId);
|
||||||
void homeserverChanged(QString homeserver);
|
void homeserverChanged(QString homeserver);
|
||||||
void disableCertificateValidationChanged(bool disabled);
|
void disableCertificateValidationChanged(bool disabled);
|
||||||
|
void useIdenticonChanged(bool state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Default to system theme if QT_QPA_PLATFORMTHEME var is set.
|
// Default to system theme if QT_QPA_PLATFORMTHEME var is set.
|
||||||
@ -330,6 +336,7 @@ private:
|
|||||||
QString deviceId_;
|
QString deviceId_;
|
||||||
QString homeserver_;
|
QString homeserver_;
|
||||||
QStringList hiddenTags_;
|
QStringList hiddenTags_;
|
||||||
|
bool useIdenticon_;
|
||||||
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
|
|
||||||
@ -391,6 +398,7 @@ private:
|
|||||||
Toggle *desktopNotifications_;
|
Toggle *desktopNotifications_;
|
||||||
Toggle *alertOnNotification_;
|
Toggle *alertOnNotification_;
|
||||||
Toggle *avatarCircles_;
|
Toggle *avatarCircles_;
|
||||||
|
Toggle *useIdenticon_;
|
||||||
Toggle *useStunServer_;
|
Toggle *useStunServer_;
|
||||||
Toggle *decryptSidebar_;
|
Toggle *decryptSidebar_;
|
||||||
Toggle *privacyScreen_;
|
Toggle *privacyScreen_;
|
||||||
|
@ -76,6 +76,8 @@ RoomlistModel::roleNames() const
|
|||||||
{IsSpace, "isSpace"},
|
{IsSpace, "isSpace"},
|
||||||
{Tags, "tags"},
|
{Tags, "tags"},
|
||||||
{ParentSpaces, "parentSpaces"},
|
{ParentSpaces, "parentSpaces"},
|
||||||
|
{IsDirect, "isDirect"},
|
||||||
|
{DirectChatOtherUserId, "directChatOtherUserId"},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,6 +131,10 @@ RoomlistModel::data(const QModelIndex &index, int role) const
|
|||||||
list.push_back(QString::fromStdString(t));
|
list.push_back(QString::fromStdString(t));
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
case Roles::IsDirect:
|
||||||
|
return room->isDirect();
|
||||||
|
case Roles::DirectChatOtherUserId:
|
||||||
|
return room->directChatOtherUserId();
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -158,6 +164,14 @@ RoomlistModel::data(const QModelIndex &index, int role) const
|
|||||||
return false;
|
return false;
|
||||||
case Roles::Tags:
|
case Roles::Tags:
|
||||||
return QStringList();
|
return QStringList();
|
||||||
|
case Roles::IsDirect:
|
||||||
|
// The list of users from the room doesn't contain the invited
|
||||||
|
// users, so we won't factor the invite into the count
|
||||||
|
return room.member_count == 1;
|
||||||
|
case Roles::DirectChatOtherUserId:
|
||||||
|
return cache::getMembersFromInvite(roomid.toStdString(), 0, 1)
|
||||||
|
.front()
|
||||||
|
.user_id;
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -190,6 +204,10 @@ RoomlistModel::data(const QModelIndex &index, int role) const
|
|||||||
return true;
|
return true;
|
||||||
case Roles::Tags:
|
case Roles::Tags:
|
||||||
return QStringList();
|
return QStringList();
|
||||||
|
case Roles::IsDirect:
|
||||||
|
return false;
|
||||||
|
case Roles::DirectChatOtherUserId:
|
||||||
|
return QString{}; // should never be reached
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -65,6 +65,8 @@ public:
|
|||||||
IsPreviewFetched,
|
IsPreviewFetched,
|
||||||
Tags,
|
Tags,
|
||||||
ParentSpaces,
|
ParentSpaces,
|
||||||
|
IsDirect,
|
||||||
|
DirectChatOtherUserId,
|
||||||
};
|
};
|
||||||
|
|
||||||
RoomlistModel(TimelineViewManager *parent = nullptr);
|
RoomlistModel(TimelineViewManager *parent = nullptr);
|
||||||
|
@ -817,6 +817,11 @@ TimelineModel::syncState(const mtx::responses::State &s)
|
|||||||
emit roomAvatarUrlChanged();
|
emit roomAvatarUrlChanged();
|
||||||
emit roomNameChanged();
|
emit roomNameChanged();
|
||||||
emit roomMemberCountChanged();
|
emit roomMemberCountChanged();
|
||||||
|
|
||||||
|
if (roomMemberCount() <= 2) {
|
||||||
|
emit isDirectChanged();
|
||||||
|
emit directChatOtherUserIdChanged();
|
||||||
|
}
|
||||||
} else if (std::holds_alternative<StateEvent<state::Encryption>>(e)) {
|
} else if (std::holds_alternative<StateEvent<state::Encryption>>(e)) {
|
||||||
this->isEncrypted_ = cache::isRoomEncrypted(room_id_.toStdString());
|
this->isEncrypted_ = cache::isRoomEncrypted(room_id_.toStdString());
|
||||||
emit encryptionChanged();
|
emit encryptionChanged();
|
||||||
@ -2073,3 +2078,16 @@ TimelineModel::roomMemberCount() const
|
|||||||
{
|
{
|
||||||
return (int)cache::client()->memberCount(room_id_.toStdString());
|
return (int)cache::client()->memberCount(room_id_.toStdString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
TimelineModel::directChatOtherUserId() const
|
||||||
|
{
|
||||||
|
if (roomMemberCount() < 3) {
|
||||||
|
QString id;
|
||||||
|
for (auto member : cache::getMembers(room_id_.toStdString()))
|
||||||
|
if (member.user_id != UserSettings::instance()->userId())
|
||||||
|
id = member.user_id;
|
||||||
|
return id;
|
||||||
|
} else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
@ -176,6 +176,9 @@ class TimelineModel : public QAbstractListModel
|
|||||||
Q_PROPERTY(bool isEncrypted READ isEncrypted NOTIFY encryptionChanged)
|
Q_PROPERTY(bool isEncrypted READ isEncrypted NOTIFY encryptionChanged)
|
||||||
Q_PROPERTY(bool isSpace READ isSpace CONSTANT)
|
Q_PROPERTY(bool isSpace READ isSpace CONSTANT)
|
||||||
Q_PROPERTY(int trustlevel READ trustlevel NOTIFY trustlevelChanged)
|
Q_PROPERTY(int trustlevel READ trustlevel NOTIFY trustlevelChanged)
|
||||||
|
Q_PROPERTY(bool isDirect READ isDirect NOTIFY isDirectChanged)
|
||||||
|
Q_PROPERTY(QString directChatOtherUserId READ directChatOtherUserId NOTIFY
|
||||||
|
directChatOtherUserIdChanged)
|
||||||
Q_PROPERTY(InputBar *input READ input CONSTANT)
|
Q_PROPERTY(InputBar *input READ input CONSTANT)
|
||||||
Q_PROPERTY(Permissions *permissions READ permissions NOTIFY permissionsChanged)
|
Q_PROPERTY(Permissions *permissions READ permissions NOTIFY permissionsChanged)
|
||||||
|
|
||||||
@ -292,6 +295,8 @@ public:
|
|||||||
bool isEncrypted() const { return isEncrypted_; }
|
bool isEncrypted() const { return isEncrypted_; }
|
||||||
crypto::Trust trustlevel() const;
|
crypto::Trust trustlevel() const;
|
||||||
int roomMemberCount() const;
|
int roomMemberCount() const;
|
||||||
|
bool isDirect() const { return roomMemberCount() <= 2; }
|
||||||
|
QString directChatOtherUserId() const;
|
||||||
|
|
||||||
std::optional<mtx::events::collections::TimelineEvents> eventById(const QString &id)
|
std::optional<mtx::events::collections::TimelineEvents> eventById(const QString &id)
|
||||||
{
|
{
|
||||||
@ -391,6 +396,8 @@ signals:
|
|||||||
void roomTopicChanged();
|
void roomTopicChanged();
|
||||||
void roomAvatarUrlChanged();
|
void roomAvatarUrlChanged();
|
||||||
void roomMemberCountChanged();
|
void roomMemberCountChanged();
|
||||||
|
void isDirectChanged();
|
||||||
|
void directChatOtherUserIdChanged();
|
||||||
void permissionsChanged();
|
void permissionsChanged();
|
||||||
void forwardToRoom(mtx::events::collections::TimelineEvents *e, QString roomId);
|
void forwardToRoom(mtx::events::collections::TimelineEvents *e, QString roomId);
|
||||||
|
|
||||||
|
@ -141,6 +141,7 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
|||||||
, imgProvider(new MxcImageProvider())
|
, imgProvider(new MxcImageProvider())
|
||||||
, colorImgProvider(new ColorImageProvider())
|
, colorImgProvider(new ColorImageProvider())
|
||||||
, blurhashProvider(new BlurhashProvider())
|
, blurhashProvider(new BlurhashProvider())
|
||||||
|
, jdenticonProvider(new JdenticonProvider())
|
||||||
, callManager_(callManager)
|
, callManager_(callManager)
|
||||||
, rooms_(new RoomlistModel(this))
|
, rooms_(new RoomlistModel(this))
|
||||||
, communities_(new CommunitiesModel(this))
|
, communities_(new CommunitiesModel(this))
|
||||||
@ -310,6 +311,8 @@ TimelineViewManager::TimelineViewManager(CallManager *callManager, ChatPage *par
|
|||||||
view->engine()->addImageProvider("MxcImage", imgProvider);
|
view->engine()->addImageProvider("MxcImage", imgProvider);
|
||||||
view->engine()->addImageProvider("colorimage", colorImgProvider);
|
view->engine()->addImageProvider("colorimage", colorImgProvider);
|
||||||
view->engine()->addImageProvider("blurhash", blurhashProvider);
|
view->engine()->addImageProvider("blurhash", blurhashProvider);
|
||||||
|
if (JdenticonProvider::isAvailable())
|
||||||
|
view->engine()->addImageProvider("jdenticon", jdenticonProvider);
|
||||||
view->setSource(QUrl("qrc:///qml/Root.qml"));
|
view->setSource(QUrl("qrc:///qml/Root.qml"));
|
||||||
|
|
||||||
connect(parent, &ChatPage::themeChanged, this, &TimelineViewManager::updateColorPalette);
|
connect(parent, &ChatPage::themeChanged, this, &TimelineViewManager::updateColorPalette);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "CallManager.h"
|
#include "CallManager.h"
|
||||||
|
#include "JdenticonProvider.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "TimelineModel.h"
|
#include "TimelineModel.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
@ -141,6 +142,7 @@ private:
|
|||||||
MxcImageProvider *imgProvider;
|
MxcImageProvider *imgProvider;
|
||||||
ColorImageProvider *colorImgProvider;
|
ColorImageProvider *colorImgProvider;
|
||||||
BlurhashProvider *blurhashProvider;
|
BlurhashProvider *blurhashProvider;
|
||||||
|
JdenticonProvider *jdenticonProvider;
|
||||||
|
|
||||||
CallManager *callManager_ = nullptr;
|
CallManager *callManager_ = nullptr;
|
||||||
|
|
||||||
|
@ -8,12 +8,6 @@
|
|||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
enum class AvatarType
|
|
||||||
{
|
|
||||||
Image,
|
|
||||||
Letter
|
|
||||||
};
|
|
||||||
|
|
||||||
// Default font size.
|
// Default font size.
|
||||||
const int FontSize = 16;
|
const int FontSize = 16;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user