Merge 3fcc1e9774db387958ef5ccb84b108e972c6e415 into 1d1138d0cb941845632cc4a8f74336818d63bcc4

This commit is contained in:
defnax 2025-04-16 00:37:20 +00:00 committed by GitHub
commit 49cf03cc22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 113 additions and 7 deletions

View File

@ -34,6 +34,8 @@
#include "gui/common/FriendListModel.h"
#include "gui/gxs/GxsIdDetails.h"
#include "gui/gxs/GxsIdTreeWidgetItem.h"
#include "gui/chat/ChatUserNotify.h"
#include "retroshare/rsexpr.h"
#include "retroshare/rsmsgs.h"
@ -65,7 +67,7 @@ static const uint32_t NODE_DETAILS_UPDATE_DELAY = 5; // update each node every 5
RsFriendListModel::RsFriendListModel(QObject *parent)
: QAbstractItemModel(parent)
, mDisplayGroups(true), mDisplayStatusString(true), mDisplayStatusIcon (false)
, mDisplayGroups(true), mDisplayStatusString(true), mDisplayStatusIcon (false), mDisplayCircleAvatars (false)
, mLastInternalDataUpdate(0), mLastNodeUpdate(0)
{
mFilterStrings.clear();
@ -160,6 +162,27 @@ static QIcon createAvatar(const QPixmap &avatar, const QPixmap &overlay)
return icon;
}
static QImage getCirclePhoto(const QImage original, int sizePhoto)
{
QImage target(sizePhoto, sizePhoto, QImage::Format_ARGB32_Premultiplied);
target.fill(Qt::transparent);
QPainter painter(&target);
painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
painter.setBrush(QBrush(Qt::white));
auto scaledPhoto = original
.scaled(sizePhoto, sizePhoto, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation)
.convertToFormat(QImage::Format_ARGB32_Premultiplied);
int margin = 0;
if (scaledPhoto.width() > sizePhoto) {
margin = (scaledPhoto.width() - sizePhoto) / 2;
}
painter.drawEllipse(0, 0, sizePhoto, sizePhoto);
painter.setCompositionMode(QPainter::CompositionMode_SourceIn);
painter.drawImage(0, 0, scaledPhoto, margin, 0);
return target;
}
void RsFriendListModel::setDisplayStatusString(bool b)
{
preMods();
@ -174,6 +197,12 @@ void RsFriendListModel::setDisplayStatusIcon(bool b)
postMods();
}
void RsFriendListModel::setDisplayCircleAvatars(bool b)
{
mDisplayCircleAvatars = b;
postMods();
}
void RsFriendListModel::setDisplayGroups(bool b)
{
mDisplayGroups = b;
@ -998,6 +1027,12 @@ QVariant RsFriendListModel::decorationRole(const EntryIndex& entry,int col) cons
{
QPixmap sslAvatar;
bool foundAvatar = false;
bool hasPrivateChat = false;
// get peers with waiting incoming chats
std::vector<RsPeerId> privateChatIds;
ChatUserNotify::getPeersWithWaitingChat(privateChatIds);
const HierarchicalProfileInformation *hn = getProfileInfo(entry);
uint32_t status = RS_STATUS_OFFLINE;
const HierarchicalNodeInformation *bestNodeInformation = NULL;
@ -1025,11 +1060,33 @@ QVariant RsFriendListModel::decorationRole(const EntryIndex& entry,int col) cons
if (!foundAvatar || sslAvatar.isNull()) {
sslAvatar = FilesDefs::getPixmapFromQtResourcePath(AVATAR_DEFAULT_IMAGE);
}
if(mDisplayCircleAvatars) {
//make avatar as circle avatar
QImage orginalImage = sslAvatar.toImage();
QImage circleImage = getCirclePhoto(orginalImage,orginalImage.size().width());
sslAvatar.convertFromImage(circleImage);
}
if (mDisplayStatusIcon) {
for(uint32_t i=0;i<hn->child_node_indices.size();++i) {
if (std::find(privateChatIds.begin(), privateChatIds.end(), RsPeerId(mLocations[hn->child_node_indices[i]].node_info.id.toStdString())) != privateChatIds.end()) {
// private chat is available
hasPrivateChat = true;
break;
}
}
}
if (mDisplayStatusIcon) {
if (bestNodeInformation) {
QPixmap sslOverlayIcon = FilesDefs::getPixmapFromQtResourcePath(StatusDefs::imageStatus(status));
return QVariant(QIcon(createAvatar(sslAvatar, sslOverlayIcon)));
if (hasPrivateChat) {
QPixmap sslOverlayIcon = FilesDefs::getPixmapFromQtResourcePath(":/images/orange-bubble-64.png");
return QVariant(QIcon(createAvatar(sslAvatar, sslOverlayIcon)));
} else {
QPixmap sslOverlayIcon = FilesDefs::getPixmapFromQtResourcePath(StatusDefs::imageStatus(status));
return QVariant(QIcon(createAvatar(sslAvatar, sslOverlayIcon)));
}
}
}
@ -1047,10 +1104,38 @@ QVariant RsFriendListModel::decorationRole(const EntryIndex& entry,int col) cons
return QVariant();
QPixmap sslAvatar;
bool hasPrivateChat = false;
AvatarDefs::getAvatarFromSslId(RsPeerId(hn->node_info.id.toStdString()), sslAvatar);
// get peers with waiting incoming chats
std::vector<RsPeerId> privateChatIds;
ChatUserNotify::getPeersWithWaitingChat(privateChatIds);
if(mDisplayCircleAvatars) {
//make avatar as circle avatar
QImage orginalImage = sslAvatar.toImage();
QImage circleImage = getCirclePhoto(orginalImage,orginalImage.size().width());
sslAvatar.convertFromImage(circleImage);
}
if (mDisplayStatusIcon) {
QPixmap sslOverlayIcon = FilesDefs::getPixmapFromQtResourcePath(StatusDefs::imageStatus(statusRole(entry, col).toInt()));
return QVariant(QIcon(createAvatar(sslAvatar, sslOverlayIcon)));
for(uint32_t i=0;i<mLocations.size();++i){
if (std::find(privateChatIds.begin(), privateChatIds.end(), RsPeerId(hn->node_info.id.toStdString())) != privateChatIds.end()) {
// private chat is available
hasPrivateChat = true;
break;
}
}
}
if (mDisplayStatusIcon) {
if (hasPrivateChat) {
QPixmap sslOverlayIcon = FilesDefs::getPixmapFromQtResourcePath(":/images/orange-bubble-64.png");
return QVariant(QIcon(createAvatar(sslAvatar, sslOverlayIcon)));
} else {
QPixmap sslOverlayIcon = FilesDefs::getPixmapFromQtResourcePath(StatusDefs::imageStatus(statusRole(entry, col).toInt()));
return QVariant(QIcon(createAvatar(sslAvatar, sslOverlayIcon)));
}
}
return QVariant(QIcon(sslAvatar));

View File

@ -131,7 +131,8 @@ public:
bool getDisplayStatusString() const { return mDisplayStatusString; }
void setDisplayStatusIcon(bool b);
bool getDisplayStatusIcon() const { return mDisplayStatusIcon; }
void setDisplayCircleAvatars(bool b);
bool getDisplayCircleAvatars() const { return mDisplayCircleAvatars; }
EntryType getType(const QModelIndex&) const;
@ -231,6 +232,7 @@ private:
bool mDisplayGroups ;
bool mDisplayStatusString ;
bool mDisplayStatusIcon ;
bool mDisplayCircleAvatars ;
rstime_t mLastInternalDataUpdate;
rstime_t mLastNodeUpdate;;

View File

@ -267,6 +267,7 @@ NewFriendList::NewFriendList(QWidget */*parent*/) : /* RsAutoUpdatePage(5000,par
connect(ui->actionShowState, SIGNAL(triggered(bool)), this, SLOT(setShowState(bool)) );
connect(ui->actionShowStateIcon, SIGNAL(triggered(bool)), this, SLOT(setShowStateIcon(bool)) );
connect(ui->actionShowGroups, SIGNAL(triggered(bool)), this, SLOT(setShowGroups(bool)) );
connect(ui->actionShowCircleAvatars, SIGNAL(triggered(bool)), this, SLOT(setShowCircleAvatars(bool)) );
connect(ui->actionExportFriendlist, SIGNAL(triggered()) , this, SLOT(exportFriendlistClicked()));
connect(ui->actionImportFriendlist, SIGNAL(triggered()) , this, SLOT(importFriendlistClicked()));
@ -349,12 +350,14 @@ void NewFriendList::headerContextMenuRequested(QPoint /*p*/)
displayMenu.addAction(ui->actionShowOfflineFriends);
displayMenu.addAction(ui->actionShowState);
displayMenu.addAction(ui->actionShowStateIcon);
displayMenu.addAction(ui->actionShowCircleAvatars);
displayMenu.addAction(ui->actionShowGroups);
ui->actionShowOfflineFriends->setChecked(mProxyModel->showOfflineNodes());
ui->actionShowState->setChecked(mModel->getDisplayStatusString());
ui->actionShowStateIcon->setChecked(mModel->getDisplayStatusIcon());
ui->actionShowGroups->setChecked(mModel->getDisplayGroups());
ui->actionShowCircleAvatars->setChecked(mModel->getDisplayCircleAvatars());
QHeaderView *header = ui->peerTreeWidget->header();
@ -515,6 +518,7 @@ void NewFriendList::processSettings(bool load)
mModel->setDisplayStatusString(Settings->value("showState", mModel->getDisplayStatusString()).toBool());
mModel->setDisplayGroups(Settings->value("showGroups", mModel->getDisplayGroups()).toBool());
mModel->setDisplayStatusIcon(Settings->value("showStateIcon", mModel->getDisplayStatusIcon()).toBool());
mModel->setDisplayCircleAvatars(Settings->value("showCircleAvatars", mModel->getDisplayCircleAvatars()).toBool());
setColumnVisible(RsFriendListModel::COLUMN_THREAD_IP,Settings->value("showIP", isColumnVisible(RsFriendListModel::COLUMN_THREAD_IP)).toBool());
@ -540,7 +544,7 @@ void NewFriendList::processSettings(bool load)
Settings->setValue("showState", mModel->getDisplayStatusString());
Settings->setValue("showGroups", mModel->getDisplayGroups());
Settings->setValue("showStateIcon", mModel->getDisplayStatusIcon());
Settings->setValue("showCircleAvatars", mModel->getDisplayCircleAvatars());
Settings->setValue("showIP",isColumnVisible(RsFriendListModel::COLUMN_THREAD_IP));
Settings->setValue("showID",isColumnVisible(RsFriendListModel::COLUMN_THREAD_ID));
@ -1662,6 +1666,12 @@ void NewFriendList::setShowStateIcon(bool show)
processSettings(false);
}
void NewFriendList::setShowCircleAvatars(bool show)
{
applyWhileKeepingTree([show,this]() { mModel->setDisplayCircleAvatars(show) ; });
processSettings(false);
}
void NewFriendList::setShowGroups(bool show)
{
applyWhileKeepingTree([show,this]() { mModel->setDisplayGroups(show) ; });

View File

@ -89,6 +89,7 @@ public slots:
void setShowUnconnected(bool hidden);
void setShowState(bool show);
void setShowStateIcon(bool show);
void setShowCircleAvatars(bool show);
void headerContextMenuRequested(QPoint);
void exportFriendlistClicked();

View File

@ -130,6 +130,14 @@
<string>Show status icons</string>
</property>
</action>
<action name="actionShowCircleAvatars">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Circle Avatars</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>