Merge pull request #3202 from defnax/boards-picture-navigation

[Boards] Added navigation for boards picture viewer
This commit is contained in:
csoler 2026-06-15 20:49:07 +02:00 committed by GitHub
commit df4561ec81
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 205 additions and 58 deletions

View File

@ -390,46 +390,10 @@ void BoardPostDisplayWidget_compact::setup()
#endif
}
void BoardPostDisplayWidget_compact::viewPicture()
{
if(mPost.mImage.mData == NULL)
return;
QString timestamp = misc::timeRelativeToNow(mPost.mMeta.mPublishTs);
RsGxsId authorID = mPost.mMeta.mAuthorId;
PhotoView *PView = new PhotoView();
// Check if animated image
QString format;
if (BoardPostImageHelper::isAnimatedImage(mPost.mImage.mData, mPost.mImage.mSize, &format))
{
// Animated GIF/WEBP - use QMovie in popup
QMovie* movie = BoardPostImageHelper::createMovieFromData(mPost.mImage.mData, mPost.mImage.mSize);
if (movie)
{
movie->setParent(PView); // Ensure cleanup
PView->setMovie(movie);
movie->start();
}
}
else
{
// Static image - use QPixmap
QPixmap pixmap;
GxsIdDetails::loadPixmapFromData(mPost.mImage.mData, mPost.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL);
PView->setPixmap(pixmap);
}
PView->setTitle(QString::fromUtf8(mPost.mMeta.mMsgName.c_str()));
PView->setName(authorID);
PView->setTime(timestamp);
PView->setGroupId(mPost.mMeta.mGroupId);
PView->setMessageId(mPost.mMeta.mMsgId);
PView->show();
emit thumbnailOpenned();
void BoardPostDisplayWidget_compact::viewPicture() {
// PostedListWidgetWithModel catches to show the PhotoView with the full list.
emit showGalleryRequest(mPost.mMeta.mMsgId);
emit thumbnailOpenned(); // Keep this for legacy compatibility
}
QToolButton *BoardPostDisplayWidget_compact::voteUpButton() { return ui->voteUpButton; }

View File

@ -104,6 +104,8 @@ signals:
// void shareButtonClicked();
// void copylinkClicked();
void showGalleryRequest(const RsGxsMessageId& msgId);
protected:
RsPostedPost mPost;
uint8_t mDisplayFlags;
@ -113,6 +115,9 @@ class BoardPostDisplayWidget_compact : public BoardPostDisplayWidgetBase
{
Q_OBJECT
signals:
void showGalleryRequest(const RsGxsMessageId& msgId);
public:
BoardPostDisplayWidget_compact(const RsPostedPost& post, uint8_t display_flags, QWidget *parent);
virtual ~BoardPostDisplayWidget_compact();

View File

@ -29,8 +29,11 @@
#include <QBuffer>
#include <QMovie>
#include "BoardPostImageHelper.h"
#include "gui/gxs/GxsIdDetails.h"
#include "gui/RetroShareLink.h"
#include "util/misc.h"
#include <retroshare/rsidentity.h>
#include <retroshare/rsposted.h>
@ -45,7 +48,14 @@ PhotoView::PhotoView(QWidget *parent)
setAttribute(Qt::WA_DeleteOnClose, true);
// Hide navigation buttons by default
ui->prevButton->hide();
ui->nextButton->hide();
connect(ui->shareButton, SIGNAL(clicked()), this, SLOT(copyMessageLink()));
connect(ui->prevButton, &QToolButton::clicked, this, &PhotoView::goToPrevious);
connect(ui->nextButton, &QToolButton::clicked, this, &PhotoView::goToNext);
}
/** Destructor */
@ -62,7 +72,10 @@ PhotoView::~PhotoView()
void PhotoView::setPixmap(const QPixmap& pixmap)
{
ui->photoLabel->setPixmap(pixmap);
this->adjustSize();
if (mPosts.size() <= 1){
this->adjustSize();
}
}
void PhotoView::setMovie(QMovie* movie)
@ -137,3 +150,81 @@ void PhotoView::setGroupNameString(const QString& name)
{
ui->nameLabel->setText("@" + name);
}
void PhotoView::setPosts(const QList<RsPostedPost>& posts, int currentIndex)
{
mPosts = posts;
mCurrentIndex = currentIndex;
if (mPosts.size() > 1) {
// Apply constraints only when multiple photos exist
this->resize(800, 600);
}
// Show buttons only if there is more than one post to navigate
bool showNavigation = (mPosts.size() > 1);
ui->prevButton->setVisible(showNavigation);
ui->nextButton->setVisible(showNavigation);
updateDisplay();
}
void PhotoView::goToPrevious()
{
if (mCurrentIndex > 0) {
mCurrentIndex--;
updateDisplay();
}
}
void PhotoView::goToNext()
{
if (mCurrentIndex < mPosts.size() - 1){
mCurrentIndex++;
updateDisplay();
}
}
void PhotoView::updateDisplay()
{
if (mCurrentIndex < 0 || mCurrentIndex >= mPosts.size()) return;
const RsPostedPost& post = mPosts[mCurrentIndex];
// Emit the signal with the current message ID
emit postChanged(post.mMeta.mMsgId);
QString timestamp = misc::timeRelativeToNow(post.mMeta.mPublishTs);
// Set Title, ID, and Time using existing methods
setTitle(QString::fromUtf8(post.mMeta.mMsgName.c_str()));
setName(post.mMeta.mAuthorId);
setTime(timestamp);
setGroupId(post.mMeta.mGroupId);
setMessageId(post.mMeta.mMsgId);
// Check if animated image
QString format;
if (BoardPostImageHelper::isAnimatedImage(post.mImage.mData, post.mImage.mSize, &format))
{
// Animated GIF/WEBP - use QMovie in popup
QMovie* movie = BoardPostImageHelper::createMovieFromData(post.mImage.mData, post.mImage.mSize);
if (movie)
{
movie->setParent(this); // Ensure cleanup
setMovie(movie);
movie->start();
}
}
else
{
// Static image - use QPixmap
QPixmap pixmap;
GxsIdDetails::loadPixmapFromData(post.mImage.mData, post.mImage.mSize, pixmap,GxsIdDetails::ORIGINAL);
setPixmap(pixmap);
}
// Enable/Disable buttons based on bounds
ui->prevButton->setEnabled(mCurrentIndex > 0);
ui->nextButton->setEnabled(mCurrentIndex < mPosts.size() - 1);
}

View File

@ -23,6 +23,8 @@
#include "ui_PhotoView.h"
#include <retroshare/rsposted.h>
#include <QDialog>
namespace Ui {
@ -40,6 +42,8 @@ public:
/** Default Destructor */
~PhotoView();
signals:
void postChanged(const RsGxsMessageId& msgId);
public slots:
void setPixmap(const QPixmap& pixmap);
@ -50,14 +54,21 @@ public slots:
void setGroupId(const RsGxsGroupId &groupId);
void setMessageId(const RsGxsMessageId& messageId);
void setGroupNameString(const QString& name);
void setPosts(const QList<RsPostedPost>& posts, int currentIndex);
private slots:
void copyMessageLink();
void goToPrevious();
void goToNext();
void updateDisplay();
private:
RsGxsMessageId mMessageId;
RsGxsGroupId mGroupId;
QMovie* mMovie = nullptr; // Track QMovie for cleanup
QList<RsPostedPost> mPosts;
int mCurrentIndex = 0;
/** Qt Designer generated object */
Ui::PhotoView *ui;

View File

@ -17,7 +17,7 @@
<enum>Qt::LeftToRight</enum>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0" colspan="2">
<item row="0" column="1" colspan="2">
<widget class="QLabel" name="titleLabel">
<property name="font">
<font>
@ -35,7 +35,7 @@
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<item row="1" column="1" colspan="2">
<widget class="QFrame" name="plainFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
@ -56,6 +56,16 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="1">
<widget class="AspectRatioPixmapLabel" name="photoLabel">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer_3">
<property name="orientation">
@ -82,20 +92,21 @@
</property>
</spacer>
</item>
<item row="0" column="1">
<widget class="AspectRatioPixmapLabel" name="photoLabel">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" colspan="2">
<item row="1" column="0">
<widget class="QToolButton" name="prevButton">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Previuos&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/arrow-left.png</normaloff>:/icons/png/arrow-left.png</iconset>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="label">
@ -201,6 +212,20 @@
</item>
</layout>
</item>
<item row="1" column="3">
<widget class="QToolButton" name="nextButton">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Next&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>&gt;</string>
</property>
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/icons/png/arrow-right.png</normaloff>:/icons/png/arrow-right.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
@ -222,6 +247,7 @@
</customwidget>
</customwidgets>
<resources>
<include location="../icons.qrc"/>
<include location="Posted_images.qrc"/>
</resources>
<connections/>

View File

@ -41,6 +41,7 @@
#include "gui/feeds/SubFileItem.h"
#include "gui/Identity/IdDialog.h"
#include "gui/RetroShareLink.h"
#include "PhotoView.h"
#include "util/HandleRichText.h"
#include "util/DateTime.h"
#include "util/qtthreadsutils.h"
@ -217,10 +218,19 @@ QWidget *PostedPostDelegate::createEditor(QWidget *parent, const QStyleOptionVie
RS_DBG("Title:", post.mMeta.mMsgName.c_str());
#endif
if(mDisplayMode==BoardPostDisplayWidget_compact::DISPLAY_MODE_COMPACT)
w = new BoardPostDisplayWidget_compact(post,displayFlags(post.mMeta.mMsgId),parent);
else
w = new BoardPostDisplayWidget_card(post,displayFlags(post.mMeta.mMsgId),parent);
if(mDisplayMode==BoardPostDisplayWidget_compact::DISPLAY_MODE_COMPACT){
BoardPostDisplayWidget_compact *compactWidget = new BoardPostDisplayWidget_compact(post, displayFlags(post.mMeta.mMsgId), parent);
w = compactWidget;
// Connect to the specific class that has the signal
QObject::connect(compactWidget, SIGNAL(showGalleryRequest(RsGxsMessageId)),
mPostListWidget, SLOT(handleViewGallery(RsGxsMessageId)));
}else{
BoardPostDisplayWidget_card *cardWidget = new BoardPostDisplayWidget_card(post, displayFlags(post.mMeta.mMsgId), parent);
QObject::connect(cardWidget, SIGNAL(showGalleryRequest(RsGxsMessageId)),
mPostListWidget, SLOT(handleViewGallery(RsGxsMessageId)));
w = cardWidget;
}
QObject::connect(w,SIGNAL(vote(RsGxsGrpMsgIdPair,bool)),mPostListWidget,SLOT(voteMsg(RsGxsGrpMsgIdPair,bool)));
QObject::connect(w,SIGNAL(expand(RsGxsMessageId,bool)),this,SLOT(expandItem(RsGxsMessageId,bool)));
@ -1002,3 +1012,42 @@ void PostedListWidgetWithModel::voteMsg(RsGxsGrpMsgIdPair msg,bool up_or_down)
updateDisplay(true);
}
void PostedListWidgetWithModel::handleViewGallery(const RsGxsMessageId& startMsgId)
{
std::cerr << "Gallery slot triggered for msg:";
std::cerr << std::endl;
QList<RsPostedPost> postsWithImages;
int startIndex = 0;
// Use the model to find all posts with images
for(int i = 0; i < mPostedPostsModel->rowCount(); ++i) {
QModelIndex idx = mPostedPostsModel->index(i, 0);
RsPostedPost post = idx.data(Qt::UserRole).value<RsPostedPost>();
if (post.mImage.mSize > 0) {
postsWithImages.append(post);
if (post.mMeta.mMsgId == startMsgId) {
startIndex = postsWithImages.size() - 1;
}
}
}
PhotoView *pv = new PhotoView(this);
pv->setAttribute(Qt::WA_DeleteOnClose); // Clean up memory on close
// CONNECTION: When the gallery shows a post, mark it read
connect(pv, &PhotoView::postChanged, [this](const RsGxsMessageId& msgId) {
// Combine Group ID and Message ID into the required pair
RsGxsGrpMsgIdPair idPair(mGroup.mMeta.mGroupId, msgId);
// Call with the correct pair type
rsPosted->setPostReadStatus(idPair, true);
});
pv->setPosts(postsWithImages, startIndex);
pv->show();
// Mark the current item as read immediately in the UI list
this->markCurrentPostAsRead();
}

View File

@ -152,6 +152,7 @@ private slots:
void prevPosts();
void filterItems(QString s);
void updateShowLabel();
void handleViewGallery(const RsGxsMessageId& startMsgId);
public slots:
void handlePostsTreeSizeChange(QSize size);