This commit is contained in:
john lee 2026-08-29 10:22:00 +00:00 committed by GitHub
commit 608fe9776b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 507 additions and 205 deletions

View File

@ -126,6 +126,10 @@ PeopleDialog::PeopleDialog(QWidget *parent)
reloadAll();
mCurrentViewMode = VIEW_MODE_LIST;
mSearchFilter.clear();
mSortMethod = 0;
}
/** Destructor. */
@ -1121,3 +1125,102 @@ void PeopleDialog::populatePictureFlowInt()
}//for (it=_int_circles_widgets.begin(); it!=_int_circles_widgets.end(); ++it)
pictureFlowWidgetInternal->setSlideSizeRatio(4/4.0);
}
void PeopleDialog::on_listViewButton_toggled(bool checked)
{
if (checked) {
thumbnailViewButton->setChecked(false);
setViewMode(VIEW_MODE_LIST);
}
}
void PeopleDialog::on_thumbnailViewButton_toggled(bool checked)
{
if (checked) {
listViewButton->setChecked(false);
setViewMode(VIEW_MODE_THUMBNAIL);
}
}
void PeopleDialog::on_searchPeopleLineEdit_textChanged(const QString &text)
{
mSearchFilter = text;
filterIdentities();
}
void PeopleDialog::on_sortPeopleComboBox_currentIndexChanged(int index)
{
mSortMethod = index;
sortIdentities();
}
void PeopleDialog::setViewMode(int mode)
{
mCurrentViewMode = mode;
Settings->setValueToGroup("PeopleDialog", "ViewMode", mode);
setIdentitiesViewMode(mode);
}
void PeopleDialog::filterIdentities()
{
std::map<RsGxsId,IdentityWidget *>::iterator itExt;
for (itExt = _gxs_identity_widgets.begin(); itExt != _gxs_identity_widgets.end(); ++itExt) {
IdentityWidget *widget = itExt->second;
if (mSearchFilter.isEmpty()) {
widget->setVisible(true);
} else {
widget->setVisible(true);
}
}
std::map<RsPgpId,IdentityWidget *>::iterator itInt;
for (itInt = _pgp_identity_widgets.begin(); itInt != _pgp_identity_widgets.end(); ++itInt) {
IdentityWidget *widget = itInt->second;
if (mSearchFilter.isEmpty()) {
widget->setVisible(true);
} else {
widget->setVisible(true);
}
}
}
void PeopleDialog::sortIdentities()
{
// Placeholder for sorting implementation
}
void PeopleDialog::setIdentitiesViewMode(int mode)
{
// Apply thumbnail/list mode to all identity widgets
// This changes the visual presentation of each IdentityWidget
if (mode == VIEW_MODE_THUMBNAIL) {
// In thumbnail mode, minimize labels and show compact view
std::map<RsGxsId,IdentityWidget *>::iterator itExt;
for (itExt = _gxs_identity_widgets.begin(); itExt != _gxs_identity_widgets.end(); ++itExt) {
IdentityWidget *widget = itExt->second;
widget->setMinimumSize(QSize(80, 80));
widget->setMaximumSize(QSize(80, 80));
}
std::map<RsPgpId,IdentityWidget *>::iterator itInt;
for (itInt = _pgp_identity_widgets.begin(); itInt != _pgp_identity_widgets.end(); ++itInt) {
IdentityWidget *widget = itInt->second;
widget->setMinimumSize(QSize(80, 80));
widget->setMaximumSize(QSize(80, 80));
}
} else {
// List mode - restore normal size
std::map<RsGxsId,IdentityWidget *>::iterator itExt;
for (itExt = _gxs_identity_widgets.begin(); itExt != _gxs_identity_widgets.end(); ++itExt) {
IdentityWidget *widget = itExt->second;
widget->setMinimumSize(QSize(100, 150));
widget->setMaximumSize(QSize(100, 150));
}
std::map<RsPgpId,IdentityWidget *>::iterator itInt;
for (itInt = _pgp_identity_widgets.begin(); itInt != _pgp_identity_widgets.end(); ++itInt) {
IdentityWidget *widget = itInt->second;
widget->setMinimumSize(QSize(100, 150));
widget->setMaximumSize(QSize(100, 150));
}
}
}

View File

@ -66,6 +66,11 @@ class PeopleDialog : public MainPage, public Ui::PeopleDialog, public TokenRespo
private slots:
void updateCirclesDisplay(bool);
void on_listViewButton_toggled(bool checked);
void on_thumbnailViewButton_toggled(bool checked);
void on_searchPeopleLineEdit_textChanged(const QString &text);
void on_sortPeopleComboBox_currentIndexChanged(int index);
void iw_AddButtonClickedExt();
void iw_AddButtonClickedInt();
void addToCircleExt();
@ -94,6 +99,20 @@ private:
void reloadAll();
void populatePictureFlowExt();
void populatePictureFlowInt();
void filterIdentities();
void sortIdentities();
void setViewMode(int mode);
enum ViewMode {
VIEW_MODE_LIST = 0,
VIEW_MODE_THUMBNAIL = 1
};
int mCurrentViewMode;
QString mSearchFilter;
int mSortMethod;
void setIdentitiesViewMode(int mode);
TokenQueue *mIdentityQueue;
TokenQueue *mCirclesQueue;

View File

@ -1,203 +1,294 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PeopleDialog</class>
<widget class="QWidget" name="PeopleDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>727</width>
<height>524</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string/>
</property>
<layout class="QGridLayout" name="titleBarLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="enabled">
<bool>true</bool>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabExternal">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>People</string>
</attribute>
<layout class="QVBoxLayout">
<item>
<widget class="QSplitter" name="splitterExternal">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QScrollArea" name="scrollAreaExternal">
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="FlowLayoutWidget" name="idExternal">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>701</width>
<height>248</height>
</rect>
</property>
<layout class="QVBoxLayout"/>
</widget>
</widget>
<widget class="QFrame" name="widgetExternal">
<layout class="QGridLayout" name="layoutExternal">
<item row="0" column="0">
<widget class="QLabel" name="label_External">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Drag your circles or people to each other.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="PictureFlow" name="pictureFlowWidgetExternal" native="true">
<property name="widgetResizable" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabInternal">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>Internal</string>
</attribute>
<layout class="QVBoxLayout">
<item>
<widget class="QSplitter" name="splitterInternal">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QScrollArea" name="scrollAreaInternal">
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="FlowLayoutWidget" name="idInternal">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>701</width>
<height>248</height>
</rect>
</property>
<layout class="QVBoxLayout"/>
</widget>
</widget>
<widget class="QWidget" name="widgetInternal">
<layout class="QGridLayout" name="layoutInternal">
<item row="0" column="0">
<widget class="QLabel" name="label_Internal">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Drag your circles or people to each other.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="PictureFlow" name="pictureFlowWidgetInternal" native="true">
<property name="widgetResizable" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>PictureFlow</class>
<extends>QWidget</extends>
<header location="global">gui/common/PictureFlow.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>FlowLayoutWidget</class>
<extends>QWidget</extends>
<header location="global">gui/common/FlowLayout.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../images.qrc"/>
</resources>
<connections/>
</ui>
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PeopleDialog</class>
<widget class="QWidget" name="PeopleDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>727</width>
<height>524</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string/>
</property>
<layout class="QGridLayout" name="titleBarLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<widget class="QWidget" name="viewModeBar">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="viewModeLayout">
<item>
<widget class="QToolButton" name="listViewButton">
<property name="text">
<string>List</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="toolTip">
<string>List View</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="thumbnailViewButton">
<property name="text">
<string>Thumbnail</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="toolTip">
<string>Thumbnail View</string>
</property>
</widget>
</item>
<item>
<spacer name="viewModeSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="searchPeopleLineEdit">
<property name="placeholderText">
<string>Search people...</string>
</property>
<property name="maximumWidth">
<number>200</number>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="sortPeopleComboBox">
<property name="maximumWidth">
<number>150</number>
</property>
<item>
<property name="text">
<string>Sort: Reputation</string>
</property>
</item>
<item>
<property name="text">
<string>Sort: Recommended</string>
</property>
</item>
<item>
<property name="text">
<string>Sort: Popularity</string>
</property>
</item>
<item>
<property name="text">
<string>Sort: Name</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="enabled">
<bool>true</bool>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tabExternal">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>People</string>
</attribute>
<layout class="QVBoxLayout">
<item>
<widget class="QSplitter" name="splitterExternal">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QScrollArea" name="scrollAreaExternal">
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="FlowLayoutWidget" name="idExternal">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>701</width>
<height>248</height>
</rect>
</property>
<layout class="QVBoxLayout"/>
</widget>
</widget>
<widget class="QFrame" name="widgetExternal">
<layout class="QGridLayout" name="layoutExternal">
<item row="0" column="0">
<widget class="QLabel" name="label_External">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Drag your circles or people to each other.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="PictureFlow" name="pictureFlowWidgetExternal" native="true">
<property name="widgetResizable" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tabInternal">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title">
<string>Internal</string>
</attribute>
<layout class="QVBoxLayout">
<item>
<widget class="QSplitter" name="splitterInternal">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QScrollArea" name="scrollAreaInternal">
<property name="minimumSize">
<size>
<width>0</width>
<height>250</height>
</size>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="FlowLayoutWidget" name="idInternal">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>701</width>
<height>248</height>
</rect>
</property>
<layout class="QVBoxLayout"/>
</widget>
</widget>
<widget class="QWidget" name="widgetInternal">
<layout class="QGridLayout" name="layoutInternal">
<item row="0" column="0">
<widget class="QLabel" name="label_Internal">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Drag your circles or people to each other.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="PictureFlow" name="pictureFlowWidgetInternal" native="true">
<property name="widgetResizable" stdset="0">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>PictureFlow</class>
<extends>QWidget</extends>
<header location="global">gui/common/PictureFlow.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>FlowLayoutWidget</class>
<extends>QWidget</extends>
<header location="global">gui/common/FlowLayout.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../images.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -19,6 +19,8 @@
*******************************************************************************/
#include <QPixmap>
#include <QDir>
#include <QFile>
#include <retroshare/rschats.h>
#include <retroshare/rspeers.h>
@ -28,6 +30,66 @@
#include "AvatarDefs.h"
#include "gui/common/FilesDefs.h"
#define AVATAR_CACHE_DIR "avatars"
QString AvatarDefs::getAvatarCacheDir()
{
QString cacheDir = QDir::homePath() + "/.cache/RetroShare/";
if (!QDir(cacheDir).exists()) {
QDir().mkpath(cacheDir);
}
return cacheDir + AVATAR_CACHE_DIR + "/";
}
bool AvatarDefs::loadAvatarFromDiskCache(const RsPeerId& sslId, QPixmap &avatar)
{
QString cacheDir = getAvatarCacheDir();
if (!QDir(cacheDir).exists()) {
QDir().mkpath(cacheDir);
}
QString filePath = cacheDir + QString::fromStdString(sslId.toStdString()) + ".png";
QFile file(filePath);
if (file.exists()) {
if (avatar.load(filePath)) {
return true;
}
}
return false;
}
bool AvatarDefs::saveAvatarToDiskCache(const RsPeerId& sslId, const QPixmap &avatar)
{
QString cacheDir = getAvatarCacheDir();
if (!QDir(cacheDir).exists()) {
QDir().mkpath(cacheDir);
}
QString filePath = cacheDir + QString::fromStdString(sslId.toStdString()) + ".png";
return avatar.save(filePath, "PNG");
}
void AvatarDefs::cleanupAvatarDiskCache()
{
QString cacheDir = getAvatarCacheDir();
QDir dir(cacheDir);
if (!dir.exists()) {
return;
}
// Remove avatars older than 30 days
QDateTime threshold = QDateTime::currentDateTime().addDays(-30);
QFileInfoList files = dir.entryInfoList(QStringList() << "*.png", QDir::Files);
for (const QFileInfo &file : files) {
if (file.lastModified() < threshold) {
dir.remove(file.fileName());
}
}
}
void AvatarDefs::getOwnAvatar(QPixmap &avatar, const QString& defaultImage)
{
unsigned char *data = NULL;
@ -46,12 +108,30 @@ void AvatarDefs::getOwnAvatar(QPixmap &avatar, const QString& defaultImage)
free(data);
}
bool AvatarDefs::getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, const QString& defaultImage)
{
unsigned char *data = NULL;
int size = 0;
/* get avatar */
// First try to load from disk cache
if (loadAvatarFromDiskCache(sslId, avatar)) {
// Got from cache, now check if network has newer version
rsChats->getAvatarData(RsPeerId(sslId), data, size);
if (size > 0) {
// Network has a newer avatar, update cache
QPixmap networkAvatar;
GxsIdDetails::loadPixmapFromData(data, size, networkAvatar, GxsIdDetails::LARGE);
saveAvatarToDiskCache(sslId, networkAvatar);
avatar = networkAvatar;
free(data);
return true;
}
// No network avatar, use cached one
return true;
}
/* get avatar from network */
rsChats->getAvatarData(RsPeerId(sslId), data, size);
if (size == 0) {
if (!defaultImage.isEmpty()) {
@ -63,9 +143,13 @@ bool AvatarDefs::getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, cons
/* load image */
GxsIdDetails::loadPixmapFromData(data, size, avatar, GxsIdDetails::LARGE) ;
// Save to disk cache for persistence
saveAvatarToDiskCache(sslId, avatar);
free(data);
return true;
}
bool AvatarDefs::getAvatarFromGxsId(const RsGxsId& gxsId, QPixmap &avatar, const QString& defaultImage)
{
//int size = 0;

View File

@ -39,7 +39,12 @@ public:
static bool getAvatarFromSslId(const RsPeerId& sslId, QPixmap &avatar, const QString& defaultImage = AVATAR_DEFAULT_IMAGE);
static bool getAvatarFromGpgId(const RsPgpId & gpgId, QPixmap &avatar, const QString& defaultImage = AVATAR_DEFAULT_IMAGE);
static bool getAvatarFromGxsId(const RsGxsId & gxsId, QPixmap &avatar, const QString& defaultImage = AVATAR_DEFAULT_IMAGE);
// Disk cache methods for persistent avatars
static QString getAvatarCacheDir();
static bool loadAvatarFromDiskCache(const RsPeerId& sslId, QPixmap &avatar);
static bool saveAvatarToDiskCache(const RsPeerId& sslId, const QPixmap &avatar);
static void cleanupAvatarDiskCache();
};
#endif