From 9c8563aef104577030be8f125deac4fcb347e172 Mon Sep 17 00:00:00 2001 From: defnax <9952056+defnax@users.noreply.github.com> Date: Sun, 19 Apr 2026 17:15:11 +0200 Subject: [PATCH 1/2] Added navigation for boards picture viewer --- .../src/gui/Posted/BoardPostDisplayWidget.cpp | 43 +-------- .../src/gui/Posted/BoardPostDisplayWidget.h | 5 ++ retroshare-gui/src/gui/Posted/PhotoView.cpp | 90 ++++++++++++++++++- retroshare-gui/src/gui/Posted/PhotoView.h | 9 ++ retroshare-gui/src/gui/Posted/PhotoView.ui | 52 ++++++++--- .../gui/Posted/PostedListWidgetWithModel.cpp | 45 +++++++++- .../gui/Posted/PostedListWidgetWithModel.h | 1 + 7 files changed, 187 insertions(+), 58 deletions(-) diff --git a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp index 02f1880b7..614e8f8e5 100644 --- a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp +++ b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp @@ -390,46 +390,9 @@ 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); } QToolButton *BoardPostDisplayWidget_compact::voteUpButton() { return ui->voteUpButton; } diff --git a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.h b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.h index 731ddc9da..5c10af55d 100644 --- a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.h +++ b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.h @@ -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(); diff --git a/retroshare-gui/src/gui/Posted/PhotoView.cpp b/retroshare-gui/src/gui/Posted/PhotoView.cpp index 79725b8e5..0b698fde6 100644 --- a/retroshare-gui/src/gui/Posted/PhotoView.cpp +++ b/retroshare-gui/src/gui/Posted/PhotoView.cpp @@ -29,8 +29,11 @@ #include #include +#include "BoardPostImageHelper.h" + #include "gui/gxs/GxsIdDetails.h" #include "gui/RetroShareLink.h" +#include "util/misc.h" #include #include @@ -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,78 @@ void PhotoView::setGroupNameString(const QString& name) { ui->nameLabel->setText("@" + name); } + +void PhotoView::setPosts(const QList& 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]; + + 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); +} diff --git a/retroshare-gui/src/gui/Posted/PhotoView.h b/retroshare-gui/src/gui/Posted/PhotoView.h index 7bd098601..420b45be3 100644 --- a/retroshare-gui/src/gui/Posted/PhotoView.h +++ b/retroshare-gui/src/gui/Posted/PhotoView.h @@ -23,6 +23,8 @@ #include "ui_PhotoView.h" +#include + #include namespace Ui { @@ -50,14 +52,21 @@ public slots: void setGroupId(const RsGxsGroupId &groupId); void setMessageId(const RsGxsMessageId& messageId); void setGroupNameString(const QString& name); + void setPosts(const QList& 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 mPosts; + int mCurrentIndex = 0; /** Qt Designer generated object */ Ui::PhotoView *ui; diff --git a/retroshare-gui/src/gui/Posted/PhotoView.ui b/retroshare-gui/src/gui/Posted/PhotoView.ui index 31db767c9..ee73f3bbd 100644 --- a/retroshare-gui/src/gui/Posted/PhotoView.ui +++ b/retroshare-gui/src/gui/Posted/PhotoView.ui @@ -17,7 +17,7 @@ Qt::LeftToRight - + @@ -35,7 +35,7 @@ - + @@ -56,6 +56,16 @@ 0 + + + + + + + Qt::AlignCenter + + + @@ -82,20 +92,21 @@ - - - - - - - Qt::AlignCenter - - - - + + + + <html><head/><body><p>Previuos</p></body></html> + + + + :/icons/png/arrow-left.png:/icons/png/arrow-left.png + + + + @@ -201,6 +212,20 @@ + + + + <html><head/><body><p>Next</p></body></html> + + + > + + + + :/icons/png/arrow-right.png:/icons/png/arrow-right.png + + + @@ -222,6 +247,7 @@ + diff --git a/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp b/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp index 89a657dad..fdf994dcf 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp @@ -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,30 @@ 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 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(); + + 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 + pv->setPosts(postsWithImages, startIndex); + pv->show(); + +} diff --git a/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.h b/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.h index 103154c9e..0432820a3 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.h +++ b/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.h @@ -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); From d4ab2ffea0b09017a3116b85b642489eb83aa73a Mon Sep 17 00:00:00 2001 From: defnax <9952056+defnax@users.noreply.github.com> Date: Sat, 25 Apr 2026 14:12:47 +0200 Subject: [PATCH 2/2] Fixed read status --- .../src/gui/Posted/BoardPostDisplayWidget.cpp | 1 + retroshare-gui/src/gui/Posted/PhotoView.cpp | 3 +++ retroshare-gui/src/gui/Posted/PhotoView.h | 2 ++ .../src/gui/Posted/PostedListWidgetWithModel.cpp | 12 ++++++++++++ 4 files changed, 18 insertions(+) diff --git a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp index 614e8f8e5..9155d6761 100644 --- a/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp +++ b/retroshare-gui/src/gui/Posted/BoardPostDisplayWidget.cpp @@ -393,6 +393,7 @@ void BoardPostDisplayWidget_compact::setup() 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; } diff --git a/retroshare-gui/src/gui/Posted/PhotoView.cpp b/retroshare-gui/src/gui/Posted/PhotoView.cpp index 0b698fde6..448435f85 100644 --- a/retroshare-gui/src/gui/Posted/PhotoView.cpp +++ b/retroshare-gui/src/gui/Posted/PhotoView.cpp @@ -191,6 +191,9 @@ void PhotoView::updateDisplay() 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 diff --git a/retroshare-gui/src/gui/Posted/PhotoView.h b/retroshare-gui/src/gui/Posted/PhotoView.h index 420b45be3..f943f24d1 100644 --- a/retroshare-gui/src/gui/Posted/PhotoView.h +++ b/retroshare-gui/src/gui/Posted/PhotoView.h @@ -42,6 +42,8 @@ public: /** Default Destructor */ ~PhotoView(); +signals: + void postChanged(const RsGxsMessageId& msgId); public slots: void setPixmap(const QPixmap& pixmap); diff --git a/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp b/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp index fdf994dcf..e39c4aeed 100644 --- a/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp +++ b/retroshare-gui/src/gui/Posted/PostedListWidgetWithModel.cpp @@ -1035,7 +1035,19 @@ void PostedListWidgetWithModel::handleViewGallery(const RsGxsMessageId& startMsg 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(); }