bit more polishment

This commit is contained in:
Martin Rotter 2024-04-23 10:59:28 +02:00
parent 9e5f830fdf
commit 1b2d155eca
10 changed files with 105 additions and 23 deletions

View File

@ -6,8 +6,9 @@ OK, dear users. Over recent releases, many features were added and as you can se
Sole focus will be on fixing bugs and polish existing features and clean codebase.
Added:
* Full article content can now be fetched with a single button. Button is placed in article viewer toolbar right next to "Reader mode" button. This feature (just as "reader mode" feature) requires Node.js installation. The feature works both for articles and for regular websites opened in embedded web browser.
* Article now can be marked (upon selection) as read with delay or only manually. (#1017)
* All RSS Guard plugins/services are now placed in their own library (DLL/SO/DYLIB) files and are loaded by main RSS Guard library dynamically. This means that unused services can now be removed from RSS Guard installation if not used by the user. Also it allows for a cleaner and slimmer common codebase. Refactoring of main RSS Guard library was also done and it is now more usable as regular dynamic-link library. I expect some regressions as this was HUGE change. Also, this change allows new potential interested people in writing new plugins easier as they now can just copy one of existing plugins and tweak for new service.
* All RSS Guard plugins/services are now placed in their own library (DLL/SO/DYLIB) files and are loaded by main RSS Guard library dynamically. This means that unused services can now be removed from RSS Guard installation if not used by the user. Also it allows for a cleaner and slimmer common codebase. Refactoring of main RSS Guard library was also done and it is now more usable as regular dynamic-link library. I expect some regressions as this was HUGE change. Also, this change allows new potential interested people in writing new plugins easier as they now can just copy one of existing plugins and tweak for new service. Also this change now propagates to RSS Guard installer which allows you to only install plugins/services you want.
* Application (Qt) style and icon theme now can be properly set to respect system style/icons and this setting is dynamic, meaning if you change system theme and restart RSS Guard, new theme is honored. (#1352)
* Button to copy system/app information to "About..." dialog. (#1318)
* All modal dialogs now remember their sizes forever. (#1336)

View File

@ -318,12 +318,70 @@ void WebBrowser::readabilityFailed(QObject* sndr, const QString& error) {
}
}
void WebBrowser::setFullArticleHtml(QObject* sndr, const QString& json_answer) {
Message WebBrowser::messageFromExtractor(const QJsonDocument& extracted_data) const {
QJsonObject extracted_obj = extracted_data.object();
Message msg;
msg.m_title = extracted_obj["title"].toString();
msg.m_author = extracted_obj["author"].toString();
msg.m_created = TextFactory::parseDateTime(extracted_obj["published"].toString());
msg.m_createdFromFeed = true;
msg.m_url = extracted_obj["url"].toString();
msg.m_contents = extracted_obj["content"].toString();
QString image = extracted_obj["image"].toString();
if (!image.isEmpty()) {
// NOTE: Prepend image to content.
msg.m_contents = msg.m_contents.prepend(QSL("<div>"
"<a href=\"%1\">"
"<img src=\"%1\" />"
"</a>"
"</div>")
.arg(image));
}
return msg;
}
void WebBrowser::setFullArticleHtml(QObject* sndr, const QString& url, const QString& json_answer) {
if (sndr == this && !json_answer.isEmpty()) {
QJsonDocument json_doc = QJsonDocument::fromJson(json_answer.toUtf8());
QString better_html = json_doc["content"].toString();
m_webView->setReadabledHtml(better_html, m_webView->url());
Message full_article = messageFromExtractor(json_doc);
if (!m_messages.isEmpty() && m_messages.first().m_url == url) {
const Message displayed_article = m_messages.first();
// Copy rest of original attributes which might influence the "full" article.
full_article.m_feedId = displayed_article.m_feedId;
full_article.m_feedTitle = displayed_article.m_feedTitle;
full_article.m_customId = displayed_article.m_customId;
full_article.m_customHash = displayed_article.m_customHash;
full_article.m_id = displayed_article.m_id;
full_article.m_accountId = displayed_article.m_accountId;
full_article.m_assignedLabels = displayed_article.m_assignedLabels;
full_article.m_assignedLabelsIds = displayed_article.m_assignedLabelsIds;
full_article.m_categories = displayed_article.m_categories;
full_article.m_rawContents = displayed_article.m_rawContents;
full_article.m_isRead = displayed_article.m_isRead;
full_article.m_isImportant = displayed_article.m_isImportant;
full_article.m_isDeleted = displayed_article.m_isDeleted;
full_article.m_score = displayed_article.m_score;
full_article.m_isRtl = displayed_article.m_isRtl;
full_article.m_enclosures = displayed_article.m_enclosures;
loadMessages({full_article}, m_root);
}
else {
auto html_message = m_webView->htmlForMessages({full_article}, nullptr);
setHtml(html_message.m_html, url);
}
//
// m_webView->setReadabledHtml(full_article.m_contents, m_webView->url());
}
}

View File

@ -79,7 +79,7 @@ class RSSGUARD_DLLSPEC WebBrowser : public TabContent {
void setReadabledHtml(QObject* sndr, const QString& better_html);
void readabilityFailed(QObject* sndr, const QString& error);
void setFullArticleHtml(QObject* sndr, const QString& json_answer);
void setFullArticleHtml(QObject* sndr, const QString &url, const QString& json_answer);
void fullArticleFailed(QObject* sndr, const QString& error);
signals:
@ -92,6 +92,8 @@ class RSSGUARD_DLLSPEC WebBrowser : public TabContent {
void bindWebView();
void createConnections();
Message messageFromExtractor(const QJsonDocument& extracted_data) const;
private:
QVBoxLayout* m_layout;
QToolBar* m_toolBar;

View File

@ -249,15 +249,7 @@ void TextBrowserViewer::loadMessages(const QList<Message>& messages, RootItem* r
emit loadingStarted();
m_root = root;
auto html_messages =
qApp->settings()->value(GROUP(Messages), SETTING(Messages::UseLegacyArticleFormat)).toBool()
? prepareLegacyHtmlForMessage(messages, root)
: qApp->skins()->generateHtmlOfArticles(messages, root, width() * ACCEPTABLE_IMAGE_PERCENTUAL_WIDTH);
// Remove other characters which cannot be displayed properly.
static QRegularExpression exp_symbols("&#x1F[0-9A-F]{3};");
html_messages.m_html = html_messages.m_html.replace(exp_symbols, QString());
auto html_messages = htmlForMessages(messages, root);
/*
// Replace base64 images.
@ -283,6 +275,20 @@ void TextBrowserViewer::loadMessages(const QList<Message>& messages, RootItem* r
emit loadingFinished(true);
}
PreparedHtml TextBrowserViewer::htmlForMessages(const QList<Message>& messages, RootItem* root) const {
auto html_messages =
qApp->settings()->value(GROUP(Messages), SETTING(Messages::UseLegacyArticleFormat)).toBool()
? prepareLegacyHtmlForMessage(messages, root)
: qApp->skins()->generateHtmlOfArticles(messages, root, width() * ACCEPTABLE_IMAGE_PERCENTUAL_WIDTH);
// Remove other characters which cannot be displayed properly.
static QRegularExpression exp_symbols("&#x1F[0-9A-F]{3};");
html_messages.m_html = html_messages.m_html.replace(exp_symbols, QString());
return html_messages;
}
double TextBrowserViewer::verticalScrollBarPosition() const {
return verticalScrollBar()->value();
}

View File

@ -52,6 +52,7 @@ class RSSGUARD_DLLSPEC TextBrowserViewer : public QTextBrowser, public WebViewer
virtual QUrl url() const;
virtual void clear();
virtual void loadMessages(const QList<Message>& messages, RootItem* root);
virtual PreparedHtml htmlForMessages(const QList<Message>& messages, RootItem* root) const;
virtual double verticalScrollBarPosition() const;
virtual void setVerticalScrollBarPosition(double pos);
virtual void applyFont(const QFont& fon);

View File

@ -53,8 +53,7 @@ WebEnginePage* WebEngineViewer::page() const {
}
void WebEngineViewer::loadMessages(const QList<Message>& messages, RootItem* root) {
auto html_messages =
qApp->skins()->generateHtmlOfArticles(messages, root, width() * ACCEPTABLE_IMAGE_PERCENTUAL_WIDTH);
auto html_messages = htmlForMessages(messages, root);
m_root = root;
m_messageContents = html_messages.m_html;
@ -69,6 +68,10 @@ void WebEngineViewer::loadMessages(const QList<Message>& messages, RootItem* roo
page()->runJavaScript(QSL("window.scrollTo(0, 0);"));
}
PreparedHtml WebEngineViewer::htmlForMessages(const QList<Message>& messages, RootItem* root) const {
return qApp->skins()->generateHtmlOfArticles(messages, root, width() * ACCEPTABLE_IMAGE_PERCENTUAL_WIDTH);
}
void WebEngineViewer::clear() {
bool previously_enabled = isEnabled();

View File

@ -22,6 +22,7 @@ class RSSGUARD_DLLSPEC WebEngineViewer : public QWebEngineView, public WebViewer
public:
virtual void loadMessages(const QList<Message>& messages, RootItem* root);
virtual PreparedHtml htmlForMessages(const QList<Message>& messages, RootItem* root) const;
virtual void bindToBrowser(WebBrowser* browser);
virtual void findText(const QString& text, bool backwards);
virtual void setUrl(const QUrl& url);

View File

@ -66,6 +66,9 @@ class WebViewer {
// Displays all messages and ensures that vertical scrollbar is set to 0 (scrolled to top).
virtual void loadMessages(const QList<Message>& messages, RootItem* root) = 0;
// Returns final HTML generated for the articles.
virtual PreparedHtml htmlForMessages(const QList<Message>& messages, RootItem* root) const = 0;
// Vertical scrollbar changer.
virtual double verticalScrollBarPosition() const = 0;
virtual void setVerticalScrollBarPosition(double pos) = 0;

View File

@ -40,7 +40,7 @@ void ArticleParse::onPackageReady(const QList<NodeJs::PackageMetadata>& pkgs, bo
{true, true, false});
// Emit this just to allow the action again for user.
emit articleParsed(nullptr, tr("Packages for article-extractor are installed. You can now use this feature!"));
emit articleParsed(nullptr, {}, tr("Packages for article-extractor are installed. You can now use this feature!"));
}
void ArticleParse::onPackageError(const QList<NodeJs::PackageMetadata>& pkgs, const QString& error) {
@ -61,7 +61,9 @@ void ArticleParse::onPackageError(const QList<NodeJs::PackageMetadata>& pkgs, co
{true, true, false});
// Emit this just to allow readability again for user.
emit articleParsed(nullptr, tr("Packages for article-extractor are NOT installed. There is error: %1").arg(error));
emit articleParsed(nullptr,
{},
tr("Packages for article-extractor are NOT installed. There is error: %1").arg(error));
}
void ArticleParse::parseArticle(QObject* sndr, const QString& url) {
@ -113,8 +115,10 @@ void ArticleParse::parseArticle(QObject* sndr, const QString& url) {
// Emit this just to allow readability again for user.
emit articleParsed(sndr,
url,
tr("Node.js is not configured properly. Go to \"Settings\" -> \"Node.js\" and check "
"if your Node.js is properly configured."));
return;
}
}
@ -124,17 +128,20 @@ void ArticleParse::parseArticle(QObject* sndr, const QString& url) {
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this,
[=](int exit_code, QProcess::ExitStatus exit_status) {
onParsingFinished(sndr, exit_code, exit_status);
onParsingFinished(sndr, url, exit_code, exit_status);
});
qApp->nodejs()->runScript(proc, m_scriptFilename, {url});
}
void ArticleParse::onParsingFinished(QObject* sndr, int exit_code, QProcess::ExitStatus exit_status) {
void ArticleParse::onParsingFinished(QObject* sndr,
const QString& url,
int exit_code,
QProcess::ExitStatus exit_status) {
QProcess* proc = qobject_cast<QProcess*>(sender());
if (exit_status == QProcess::ExitStatus::NormalExit && exit_code == EXIT_SUCCESS) {
emit articleParsed(sndr, QString::fromUtf8(proc->readAllStandardOutput()));
emit articleParsed(sndr, url, QString::fromUtf8(proc->readAllStandardOutput()));
}
else {
QString err = QString::fromUtf8(proc->readAllStandardError());

View File

@ -17,12 +17,12 @@ class ArticleParse : public QObject {
void parseArticle(QObject* sndr, const QString& url);
private slots:
void onParsingFinished(QObject* sndr, int exit_code, QProcess::ExitStatus exit_status);
void onParsingFinished(QObject* sndr, const QString& url, int exit_code, QProcess::ExitStatus exit_status);
void onPackageReady(const QList<NodeJs::PackageMetadata>& pkgs, bool already_up_to_date);
void onPackageError(const QList<NodeJs::PackageMetadata>& pkgs, const QString& error);
signals:
void articleParsed(QObject* sndr, const QString& better_html);
void articleParsed(QObject* sndr, const QString& url, const QString& better_html);
void errorOnArticlePArsing(QObject* sndr, const QString& error);
private: