Merge branch 'master' of github.com:martinrotter/rssguard
@ -15,6 +15,8 @@ RSS Guard is simple, light and easy-to-use RSS/ATOM feed aggregator developed us
|
||||
* [Nextcloud News](https://apps.nextcloud.com/apps/news),
|
||||
* [Gmail API](https://developers.google.com/gmail/api).
|
||||
|
||||
Application icon was kindly contributed by Siddharth Yadav - @Siddharth_yd (Instagram), illustrationdesignsid@gmail.com (e-mail).
|
||||
|
||||
Development builds can be downloaded [here for Windows](https://bintray.com/martinrotter/rssguard/Development/Windows) and [here for Linux/Mac](https://bintray.com/martinrotter/rssguard/Development/LinuxMacOs).
|
||||
|
||||
Documentation is [here](https://github.com/martinrotter/rssguard/blob/master/resources/docs/Documentation.md).
|
||||
|
@ -48,6 +48,19 @@ function filterMessage() {
|
||||
return MSG_ACCEPT;
|
||||
}
|
||||
```
|
||||
|
||||
Make sure that your receive only one message with particular URL and all other messages with same URL are subsequently ignored.
|
||||
```js
|
||||
function filterMessage() {
|
||||
if (msg.isDuplicateWithAttribute(2)) {
|
||||
return MSG_IGNORE;
|
||||
}
|
||||
else {
|
||||
return MSG_ACCEPT;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## `Message filters` dialog
|
||||
The dialog is accessible from menu `Messages -> Message filters` and is the central place for message filters management within RSS Guard. It allows you to:
|
||||
* add or remove message filters,
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 24 KiB |
BIN
resources/graphics/original_sizes/rssguard.png
Executable file
After Width: | Height: | Size: 140 KiB |
BIN
resources/graphics/original_sizes/rssguard_mono.png
Executable file
After Width: | Height: | Size: 140 KiB |
BIN
resources/graphics/original_sizes/rssguard_plain.png
Executable file
After Width: | Height: | Size: 69 KiB |
BIN
resources/graphics/original_sizes/rssguard_plain_mono.png
Executable file
After Width: | Height: | Size: 68 KiB |
BIN
resources/graphics/rssguard.ico
Normal file → Executable file
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 122 KiB |
BIN
resources/graphics/rssguard.png
Normal file → Executable file
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 21 KiB |
BIN
resources/graphics/rssguard_plain.png
Normal file → Executable file
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 10 KiB |
BIN
resources/macosx/rssguard.icns
Normal file → Executable file
@ -1,3 +1,17 @@
|
||||
3.8.1
|
||||
—————
|
||||
|
||||
Added:
|
||||
▪ New applications icons. Contributed by Siddharth Yadav:
|
||||
▪ @Siddharth_yd (Instagram)
|
||||
▪ illustrationdesignsid@gmail.com (e-mail)
|
||||
▪
|
||||
▪
|
||||
|
||||
Fixed/changed:
|
||||
▪
|
||||
▪
|
||||
|
||||
3.8.0
|
||||
—————
|
||||
|
||||
|
@ -159,6 +159,7 @@ QList<QAction*> FormMain::allActions() const {
|
||||
actions << m_ui->m_actionClearAllItems;
|
||||
actions << m_ui->m_actionShowOnlyUnreadItems;
|
||||
actions << m_ui->m_actionShowTreeBranches;
|
||||
actions << m_ui->m_actionAutoExpandItemsWhenSelected;
|
||||
actions << m_ui->m_actionShowOnlyUnreadMessages;
|
||||
actions << m_ui->m_actionMarkSelectedMessagesAsRead;
|
||||
actions << m_ui->m_actionMarkSelectedMessagesAsUnread;
|
||||
@ -596,6 +597,8 @@ void FormMain::loadSize() {
|
||||
SETTING(Feeds::ShowOnlyUnreadFeeds)).toBool());
|
||||
m_ui->m_actionShowTreeBranches->setChecked(settings->value(GROUP(Feeds),
|
||||
SETTING(Feeds::ShowTreeBranches)).toBool());
|
||||
m_ui->m_actionAutoExpandItemsWhenSelected->setChecked(settings->value(GROUP(Feeds),
|
||||
SETTING(Feeds::AutoExpandOnSelection)).toBool());
|
||||
m_ui->m_actionShowOnlyUnreadMessages->setChecked(settings->value(GROUP(Messages),
|
||||
SETTING(Messages::ShowOnlyUnreadMessages)).toBool());
|
||||
m_ui->m_actionAlternateColorsInLists->setChecked(settings->value(GROUP(GUI),
|
||||
@ -763,6 +766,8 @@ void FormMain::createConnections() {
|
||||
tabWidget()->feedMessageViewer(), &FeedMessageViewer::toggleShowOnlyUnreadFeeds);
|
||||
connect(m_ui->m_actionShowTreeBranches, &QAction::toggled,
|
||||
tabWidget()->feedMessageViewer(), &FeedMessageViewer::toggleShowFeedTreeBranches);
|
||||
connect(m_ui->m_actionAutoExpandItemsWhenSelected, &QAction::toggled,
|
||||
tabWidget()->feedMessageViewer(), &FeedMessageViewer::toggleItemsAutoExpandingOnSelection);
|
||||
connect(m_ui->m_actionAlternateColorsInLists, &QAction::toggled,
|
||||
tabWidget()->feedMessageViewer(), &FeedMessageViewer::alternateRowColorsInLists);
|
||||
connect(m_ui->m_actionShowOnlyUnreadMessages, &QAction::toggled,
|
||||
|
@ -116,6 +116,7 @@
|
||||
<addaction name="m_actionDeleteSelectedItem"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="m_actionShowOnlyUnreadItems"/>
|
||||
<addaction name="m_actionAutoExpandItemsWhenSelected"/>
|
||||
<addaction name="m_actionShowTreeBranches"/>
|
||||
<addaction name="m_actionExpandCollapseItem"/>
|
||||
<addaction name="separator"/>
|
||||
@ -784,6 +785,14 @@
|
||||
<string>Alternate row colors in lists</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="m_actionAutoExpandItemsWhenSelected">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Automatically &expand items when selected</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
@ -188,6 +188,12 @@ void FeedMessageViewer::toggleShowFeedTreeBranches() {
|
||||
qApp->settings()->setValue(GROUP(Feeds), Feeds::ShowTreeBranches, origin->isChecked());
|
||||
}
|
||||
|
||||
void FeedMessageViewer::toggleItemsAutoExpandingOnSelection() {
|
||||
const QAction* origin = qobject_cast<QAction*>(sender());
|
||||
|
||||
qApp->settings()->setValue(GROUP(Feeds), Feeds::AutoExpandOnSelection, origin->isChecked());
|
||||
}
|
||||
|
||||
void FeedMessageViewer::alternateRowColorsInLists() {
|
||||
const QAction* origin = qobject_cast<QAction*>(sender());
|
||||
|
||||
|
@ -66,6 +66,7 @@ class RSSGUARD_DLLSPEC FeedMessageViewer : public TabContent {
|
||||
void toggleShowOnlyUnreadMessages();
|
||||
void toggleShowOnlyUnreadFeeds();
|
||||
void toggleShowFeedTreeBranches();
|
||||
void toggleItemsAutoExpandingOnSelection();
|
||||
void alternateRowColorsInLists();
|
||||
|
||||
private slots:
|
||||
|
@ -713,6 +713,11 @@ void FeedsView::selectionChanged(const QItemSelection& selected, const QItemSele
|
||||
emit itemSelected(selected_item);
|
||||
|
||||
m_proxyModel->invalidateReadFeedsFilter();
|
||||
|
||||
if (!selectedIndexes().isEmpty() &&
|
||||
qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::AutoExpandOnSelection)).toBool()) {
|
||||
expand(selectedIndexes().first());
|
||||
}
|
||||
}
|
||||
|
||||
void FeedsView::keyPressEvent(QKeyEvent* event) {
|
||||
|
@ -124,26 +124,26 @@ void SystemTrayIcon::setNumber(int number, bool any_new_message) {
|
||||
// Numbers with more than 2 digits won't be readable, display
|
||||
// infinity symbol in that case.
|
||||
if (number > 999) {
|
||||
m_font.setPixelSize(100);
|
||||
m_font.setPixelSize(background.width() * 0.78);
|
||||
tray_painter.setFont(m_font);
|
||||
tray_painter.drawText(QRect(0, 0, 128, 128), Qt::AlignVCenter | Qt::AlignCenter, QChar(8734));
|
||||
tray_painter.drawText(background.rect(), Qt::AlignVCenter | Qt::AlignCenter, QChar(8734));
|
||||
}
|
||||
else {
|
||||
// Smaller number if it has 3 digits.
|
||||
if (number > 99) {
|
||||
m_font.setPixelSize(55);
|
||||
m_font.setPixelSize(background.width() * 0.43);
|
||||
}
|
||||
else if (number > 9) {
|
||||
m_font.setPixelSize(80);
|
||||
m_font.setPixelSize(background.width() * 0.56);
|
||||
}
|
||||
|
||||
// Bigger number if it has just one digit.
|
||||
else {
|
||||
m_font.setPixelSize(100);
|
||||
m_font.setPixelSize(background.width() * 0.78);
|
||||
}
|
||||
|
||||
tray_painter.setFont(m_font);
|
||||
tray_painter.drawText(QRect(0, 0, 128, 128),
|
||||
tray_painter.drawText(background.rect(),
|
||||
Qt::AlignmentFlag::AlignVCenter | Qt::AlignmentFlag::AlignCenter,
|
||||
QString::number(number));
|
||||
}
|
||||
|
@ -888,9 +888,9 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
|
||||
}
|
||||
|
||||
int id_existing_message = -1;
|
||||
qint64 date_existing_message;
|
||||
bool is_read_existing_message;
|
||||
bool is_important_existing_message;
|
||||
qint64 date_existing_message = 0;
|
||||
bool is_read_existing_message = false;
|
||||
bool is_important_existing_message = false;
|
||||
QString contents_existing_message;
|
||||
QString feed_id_existing_message;
|
||||
|
||||
@ -973,19 +973,22 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
|
||||
// Message is already in the DB.
|
||||
//
|
||||
// Now, we update it if at least one of next conditions is true:
|
||||
// 1) Message has custom ID AND (its date OR read status OR starred status are changed).
|
||||
// 1) Message has custom ID AND (its date OR read status OR starred status are changed or message
|
||||
// was moved from one feed to another - this can particularly happen in Gmail feeds).
|
||||
//
|
||||
// 2) Message has its date fetched from feed AND its date is different from date in DB and contents is changed.
|
||||
if (/* 1 */ (!message.m_customId.isEmpty() && (message.m_created.toMSecsSinceEpoch() != date_existing_message ||
|
||||
message.m_isRead != is_read_existing_message ||
|
||||
message.m_isImportant != is_important_existing_message ||
|
||||
message.m_feedId != feed_id_existing_message)) ||
|
||||
message.m_feedId != feed_id_existing_message ||
|
||||
message.m_contents != contents_existing_message)) ||
|
||||
|
||||
/* 2 */ (message.m_createdFromFeed && message.m_created.toMSecsSinceEpoch() != date_existing_message
|
||||
&& message.m_contents != contents_existing_message)) {
|
||||
// Message exists, it is changed, update it.
|
||||
query_update.bindValue(QSL(":title"), unnulifyString(message.m_title));
|
||||
query_update.bindValue(QSL(":is_read"), (int) message.m_isRead);
|
||||
query_update.bindValue(QSL(":is_important"), (int) message.m_isImportant);
|
||||
query_update.bindValue(QSL(":is_read"), int(message.m_isRead));
|
||||
query_update.bindValue(QSL(":is_important"), int(message.m_isImportant));
|
||||
query_update.bindValue(QSL(":url"), unnulifyString(message.m_url));
|
||||
query_update.bindValue(QSL(":author"), unnulifyString(message.m_author));
|
||||
query_update.bindValue(QSL(":date_created"), message.m_created.toMSecsSinceEpoch());
|
||||
@ -1019,8 +1022,8 @@ int DatabaseQueries::updateMessages(QSqlDatabase db,
|
||||
// Message with this URL is not fetched in this feed yet.
|
||||
query_insert.bindValue(QSL(":feed"), unnulifyString(feed_custom_id));
|
||||
query_insert.bindValue(QSL(":title"), unnulifyString(message.m_title));
|
||||
query_insert.bindValue(QSL(":is_read"), (int) message.m_isRead);
|
||||
query_insert.bindValue(QSL(":is_important"), (int) message.m_isImportant);
|
||||
query_insert.bindValue(QSL(":is_read"), int(message.m_isRead));
|
||||
query_insert.bindValue(QSL(":is_important"), int(message.m_isImportant));
|
||||
query_insert.bindValue(QSL(":url"), unnulifyString( message.m_url));
|
||||
query_insert.bindValue(QSL(":author"), unnulifyString(message.m_author));
|
||||
query_insert.bindValue(QSL(":date_created"), message.m_created.toMSecsSinceEpoch());
|
||||
|
@ -60,6 +60,9 @@ DVALUE(bool) Feeds::ShowOnlyUnreadFeedsDef = false;
|
||||
DKEY Feeds::ShowTreeBranches = "show_tree_branches";
|
||||
DVALUE(bool) Feeds::ShowTreeBranchesDef = true;
|
||||
|
||||
DKEY Feeds::AutoExpandOnSelection = "auto_expand_on_selection";
|
||||
DVALUE(bool) Feeds::AutoExpandOnSelectionDef = false;
|
||||
|
||||
DKEY Feeds::ListFont = "list_font";
|
||||
|
||||
// Messages.
|
||||
|
@ -79,6 +79,9 @@ namespace Feeds {
|
||||
KEY ShowTreeBranches;
|
||||
VALUE(bool) ShowTreeBranchesDef;
|
||||
|
||||
KEY AutoExpandOnSelection;
|
||||
VALUE(bool) AutoExpandOnSelectionDef;
|
||||
|
||||
KEY ListFont;
|
||||
}
|
||||
|
||||
|
@ -435,7 +435,6 @@ QList<Message> StandardFeed::obtainNewMessages(bool* error_during_obtaining) {
|
||||
QList<QPair<QByteArray, QByteArray>> headers;
|
||||
|
||||
headers << NetworkFactory::generateBasicAuthHeader(username(), password());
|
||||
|
||||
m_networkError = NetworkFactory::performNetworkOperation(url(),
|
||||
download_timeout,
|
||||
QByteArray(),
|
||||
|