mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2025-12-24 01:08:06 -06:00
Allow to filter RSS by simple string
Adds a search bar for RSS items. It supports plain text search (no regex), applies only to the selected tab, updates results as you type, and shows all items when the field is empty. PR #23278. Resolves #14719, resolves #15538, resolves #18444, resolves #18183, resolves #22570. --------- Co-authored-by: Vladimir Golovnev <glassez@yandex.ru> Co-authored-by: Chocobo1 <Chocobo1@users.noreply.github.com>
This commit is contained in:
@@ -64,7 +64,7 @@ QListWidgetItem *ArticleListWidget::mapRSSArticle(RSS::Article *rssArticle) cons
|
||||
return m_rssArticleToListItemMapping.value(rssArticle);
|
||||
}
|
||||
|
||||
void ArticleListWidget::setRSSItem(RSS::Item *rssItem, bool unreadOnly)
|
||||
void ArticleListWidget::setRSSItem(RSS::Item *rssItem, bool unreadOnly, const QString &filter)
|
||||
{
|
||||
// Clear the list first
|
||||
clear();
|
||||
@@ -82,7 +82,7 @@ void ArticleListWidget::setRSSItem(RSS::Item *rssItem, bool unreadOnly)
|
||||
|
||||
for (auto *article : asConst(rssItem->articles()))
|
||||
{
|
||||
if (!(m_unreadOnly && article->isRead()))
|
||||
if (!(m_unreadOnly && article->isRead()) && (filter.isEmpty() || article->title().contains(filter, Qt::CaseInsensitive)))
|
||||
{
|
||||
auto *item = createItem(article);
|
||||
addItem(item);
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
RSS::Article *getRSSArticle(QListWidgetItem *item) const;
|
||||
QListWidgetItem *mapRSSArticle(RSS::Article *rssArticle) const;
|
||||
|
||||
void setRSSItem(RSS::Item *rssItem, bool unreadOnly = false);
|
||||
void setRSSItem(RSS::Item *rssItem, bool unreadOnly, const QString &filter);
|
||||
|
||||
private slots:
|
||||
void handleArticleAdded(RSS::Article *rssArticle);
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "base/rss/rss_session.h"
|
||||
#include "gui/autoexpandabledialog.h"
|
||||
#include "gui/interfaces/iguiapplication.h"
|
||||
#include "gui/lineedit.h"
|
||||
#include "gui/uithememanager.h"
|
||||
#include "gui/utils/keysequence.h"
|
||||
#include "articlelistwidget.h"
|
||||
@@ -108,6 +109,7 @@ namespace
|
||||
RSSWidget::RSSWidget(IGUIApplication *app, QWidget *parent)
|
||||
: GUIApplicationComponent(app, parent)
|
||||
, m_ui {new Ui::RSSWidget}
|
||||
, m_rssFilter {new LineEdit(this)}
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
|
||||
@@ -130,6 +132,13 @@ RSSWidget::RSSWidget(IGUIApplication *app, QWidget *parent)
|
||||
m_ui->rssDownloaderBtn->setIcon(UIThemeManager::instance()->getIcon(u"downloading"_s, u"download"_s));
|
||||
#endif
|
||||
|
||||
m_rssFilter->setMaximumWidth(200);
|
||||
m_rssFilter->setPlaceholderText(tr("Filter feed items..."));
|
||||
|
||||
const int spacerIndex = m_ui->horizontalLayout->indexOf(m_ui->spacer1);
|
||||
m_ui->horizontalLayout->insertWidget((spacerIndex + 1), m_rssFilter);
|
||||
|
||||
connect(m_rssFilter, &QLineEdit::textChanged, this, &RSSWidget::handleRSSFilterTextChanged);
|
||||
connect(m_ui->articleListWidget, &ArticleListWidget::customContextMenuRequested, this, &RSSWidget::displayItemsListMenu);
|
||||
connect(m_ui->articleListWidget, &ArticleListWidget::currentItemChanged, this, &RSSWidget::handleCurrentArticleItemChanged);
|
||||
connect(m_ui->articleListWidget, &ArticleListWidget::itemDoubleClicked, this, &RSSWidget::downloadSelectedTorrents);
|
||||
@@ -568,7 +577,8 @@ void RSSWidget::copySelectedFeedsURL()
|
||||
void RSSWidget::handleCurrentFeedItemChanged(QTreeWidgetItem *currentItem)
|
||||
{
|
||||
m_ui->articleListWidget->setRSSItem(m_ui->feedListWidget->getRSSItem(currentItem)
|
||||
, (currentItem == m_ui->feedListWidget->stickyUnreadItem()));
|
||||
, (currentItem == m_ui->feedListWidget->stickyUnreadItem())
|
||||
, m_rssFilter->text());
|
||||
}
|
||||
|
||||
void RSSWidget::on_markReadButton_clicked()
|
||||
@@ -641,6 +651,14 @@ void RSSWidget::handleUnreadCountChanged()
|
||||
emit unreadCountUpdated(RSS::Session::instance()->rootFolder()->unreadCount());
|
||||
}
|
||||
|
||||
void RSSWidget::handleRSSFilterTextChanged(const QString &newFilter)
|
||||
{
|
||||
QTreeWidgetItem *currentItem = m_ui->feedListWidget->currentItem();
|
||||
m_ui->articleListWidget->setRSSItem(m_ui->feedListWidget->getRSSItem(currentItem)
|
||||
, (currentItem == m_ui->feedListWidget->stickyUnreadItem())
|
||||
, newFilter);
|
||||
}
|
||||
|
||||
bool RSSWidget::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if ((obj == m_ui->textBrowser) && (event->type() == QEvent::PaletteChange))
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
#include "gui/guiapplicationcomponent.h"
|
||||
|
||||
class LineEdit;
|
||||
class QListWidgetItem;
|
||||
class QTreeWidgetItem;
|
||||
|
||||
@@ -85,10 +86,12 @@ private slots:
|
||||
void on_rssDownloaderBtn_clicked();
|
||||
void handleSessionProcessingStateChanged(bool enabled);
|
||||
void handleUnreadCountChanged();
|
||||
void handleRSSFilterTextChanged(const QString &newFilter);
|
||||
|
||||
private:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
void renderArticle(const RSS::Article *article) const;
|
||||
|
||||
Ui::RSSWidget *m_ui = nullptr;
|
||||
LineEdit *m_rssFilter = nullptr;
|
||||
};
|
||||
|
||||
@@ -89,10 +89,32 @@
|
||||
padding: 3px 6px;
|
||||
}
|
||||
|
||||
#rssButtonBar input {
|
||||
background-color: var(--color-background-default);
|
||||
background-image: url("../images/edit-find.svg");
|
||||
background-position: 2px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 1.5em;
|
||||
border: 1px solid var(--color-border-default);
|
||||
border-radius: 3px;
|
||||
min-width: 170px;
|
||||
padding: 2px 2px 2px 25px;
|
||||
}
|
||||
|
||||
#rssButtonBar div {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
#rssButtonBar button img {
|
||||
margin: 0 5px -3px 0;
|
||||
}
|
||||
|
||||
#rssFilterToolbar {
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
#rssContentView table {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -120,9 +142,12 @@
|
||||
<button type="button" id="updateAllButton" onclick="qBittorrent.Rss.refreshAllFeeds()">
|
||||
<img alt="QBT_TR(Update all)QBT_TR[CONTEXT=RSSWidget]" src="images/view-refresh.svg" width="16" height="16">QBT_TR(Update all)QBT_TR[CONTEXT=RSSWidget]
|
||||
</button>
|
||||
<button type="button" id="rssDownloaderButton" class="alignRight" onclick="qBittorrent.Rss.openRssDownloader()">
|
||||
<img alt="QBT_TR(RSS Downloader...)QBT_TR[CONTEXT=RSSWidget]" src="images/downloading.svg" width="16" height="16">QBT_TR(RSS Downloader...)QBT_TR[CONTEXT=RSSWidget]
|
||||
</button>
|
||||
<div id="rssFilterToolbar" class="alignRight">
|
||||
<input type="search" id="rssFilterInput" placeholder="QBT_TR(Filter feed items...)QBT_TR[CONTEXT=MainWindow]" aria-label="QBT_TR(Filter feed items...)QBT_TR[CONTEXT=MainWindow]" autocorrect="off" autocapitalize="none">
|
||||
<button type="button" id="rssDownloaderButton" onclick="qBittorrent.Rss.openRssDownloader()">
|
||||
<img alt="QBT_TR(RSS Downloader...)QBT_TR[CONTEXT=RSSWidget]" src="images/downloading.svg" width="16" height="16">QBT_TR(RSS Downloader...)QBT_TR[CONTEXT=RSSWidget]
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="rssContentView">
|
||||
@@ -277,6 +302,17 @@
|
||||
rssFeedContextMenu.updateMenuItems();
|
||||
}
|
||||
});
|
||||
document.getElementById("rssFilterInput").addEventListener("input", (event) => {
|
||||
const rowId = rssFeedTable.selectedRows[0];
|
||||
let path = "";
|
||||
for (const row of rssFeedTable.getRowValues()) {
|
||||
if (row.rowId === rowId) {
|
||||
path = row.full_data.dataPath;
|
||||
break;
|
||||
}
|
||||
}
|
||||
qBittorrent.Rss.showRssFeed(path);
|
||||
});
|
||||
|
||||
document.getElementById("CopyFeedURL").addEventListener("click", async (event) => {
|
||||
let joined = "";
|
||||
@@ -406,6 +442,12 @@
|
||||
if (path === "")
|
||||
visibleArticles = visibleArticles.filter((a) => !a.isRead);
|
||||
|
||||
const rssFilterInput = document.getElementById("rssFilterInput");
|
||||
if (rssFilterInput.value.length > 0) {
|
||||
const lowerFilter = rssFilterInput.value.toLowerCase();
|
||||
visibleArticles = visibleArticles.filter((a) => a.title.toLowerCase().includes(lowerFilter));
|
||||
}
|
||||
|
||||
let rowID = -1;
|
||||
visibleArticles.sort((e1, e2) => new Date(e2.date) - new Date(e1.date))
|
||||
.each((torrentEntry) => {
|
||||
|
||||
Reference in New Issue
Block a user