remove newsblur wip code, some work on toasts

This commit is contained in:
Martin Rotter 2023-09-18 13:35:13 +02:00
parent b6cce9efa8
commit bff766ba93
58 changed files with 464 additions and 1543 deletions

File diff suppressed because it is too large Load Diff

View File

@ -332,17 +332,6 @@ set(SOURCES
services/greader/gui/formeditgreaderaccount.h
services/greader/gui/greaderaccountdetails.cpp
services/greader/gui/greaderaccountdetails.h
services/newsblur/definitions.h
services/newsblur/newsblurentrypoint.cpp
services/newsblur/newsblurentrypoint.h
services/newsblur/newsblurnetwork.cpp
services/newsblur/newsblurnetwork.h
services/newsblur/newsblurserviceroot.cpp
services/newsblur/newsblurserviceroot.h
services/newsblur/gui/formeditnewsbluraccount.cpp
services/newsblur/gui/formeditnewsbluraccount.h
services/newsblur/gui/newsbluraccountdetails.cpp
services/newsblur/gui/newsbluraccountdetails.h
services/owncloud/definitions.h
services/owncloud/gui/formeditowncloudaccount.cpp
services/owncloud/gui/formeditowncloudaccount.h
@ -481,7 +470,6 @@ set(UI_FILES
services/gmail/gui/gmailaccountdetails.ui
services/gmail/gui/emailpreviewer.ui
services/greader/gui/greaderaccountdetails.ui
services/newsblur/gui/newsbluraccountdetails.ui
services/owncloud/gui/owncloudaccountdetails.ui
services/reddit/gui/redditaccountdetails.ui
services/standard/gui/formstandardimportexport.ui

View File

@ -9,6 +9,7 @@
#include "exceptions/feedfetchexception.h"
#include "exceptions/filteringexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "services/abstract/cacheforserviceroot.h"
#include "services/abstract/feed.h"
#include "services/abstract/labelsnode.h"

View File

@ -10,6 +10,7 @@
#include "gui/messagebox.h"
#include "miscellaneous/feedreader.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "services/abstract/feed.h"
#include "services/abstract/recyclebin.h"
#include "services/abstract/serviceentrypoint.h"

View File

@ -9,6 +9,7 @@
#include "gui/feedsview.h"
#include "miscellaneous/application.h"
#include "miscellaneous/regexfactory.h"
#include "miscellaneous/settings.h"
#include "services/abstract/rootitem.h"
#include <QMimeData>

View File

@ -11,6 +11,7 @@
#include "gui/messagesview.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/skinfactory.h"
#include "miscellaneous/textfactory.h"
#include "services/abstract/recyclebin.h"

View File

@ -9,6 +9,7 @@
#include "gui/messagebox.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iofactory.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/textfactory.h"
#include <QDir>
@ -17,8 +18,7 @@
#include <QSqlResult>
#include <QVariant>
DatabaseFactory::DatabaseFactory(QObject* parent)
: QObject(parent), m_dbDriver(nullptr) {
DatabaseFactory::DatabaseFactory(QObject* parent) : QObject(parent), m_dbDriver(nullptr) {
determineDriver();
}
@ -29,8 +29,7 @@ void DatabaseFactory::removeConnection(const QString& connection_name) {
void DatabaseFactory::determineDriver() {
m_allDbDrivers = {
new SqliteDriver(qApp->settings()->value(GROUP(Database), SETTING(Database::UseInMemory)).toBool(), this)
};
new SqliteDriver(qApp->settings()->value(GROUP(Database), SETTING(Database::UseInMemory)).toBool(), this)};
if (QSqlDatabase::isDriverAvailable(QSL(APP_DB_MYSQL_DRIVER))) {
m_allDbDrivers.append(new MariaDbDriver(this));
@ -51,16 +50,15 @@ void DatabaseFactory::determineDriver() {
m_dbDriver->connection(QSL("DatabaseFactory"));
}
catch (const ApplicationException& ex) {
qCriticalNN << LOGSEC_DB
<< "Failed to reach connection to DB source:"
<< QUOTE_W_SPACE_DOT(ex.message());
qCriticalNN << LOGSEC_DB << "Failed to reach connection to DB source:" << QUOTE_W_SPACE_DOT(ex.message());
if (m_dbDriver->driverType() != DatabaseDriver::DriverType::SQLite) {
MsgBox::show(nullptr,
QMessageBox::Icon::Critical,
tr("Cannot connect to database"),
tr("Connection to your database was not established with error: '%1'. "
"Falling back to SQLite.").arg(ex.message()));
QMessageBox::Icon::Critical,
tr("Cannot connect to database"),
tr("Connection to your database was not established with error: '%1'. "
"Falling back to SQLite.")
.arg(ex.message()));
m_dbDriver = boolinq::from(m_allDbDrivers).first([](DatabaseDriver* driv) {
return driv->driverType() == DatabaseDriver::DriverType::SQLite;
@ -88,8 +86,7 @@ QString DatabaseFactory::lastExecutedQuery(const QSqlQuery& query) {
while (it.hasNext()) {
it.next();
if (it.value().type() == QVariant::Type::Char ||
it.value().type() == QVariant::Type::String) {
if (it.value().type() == QVariant::Type::Char || it.value().type() == QVariant::Type::String) {
str.replace(it.key(), QSL("'%1'").arg(it.value().toString()));
}
else {
@ -102,8 +99,7 @@ QString DatabaseFactory::lastExecutedQuery(const QSqlQuery& query) {
}
QString DatabaseFactory::escapeQuery(const QString& query) {
return QString(query)
.replace(QSL("'"), QSL("''"));
return QString(query).replace(QSL("'"), QSL("''"));
//.replace(QSL("\""), QSL("\\\""));
}

View File

@ -7,6 +7,7 @@
#include "exceptions/applicationexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "services/abstract/category.h"
#include <QSqlDriver>

View File

@ -6,6 +6,7 @@
#include "gui/guiutilities.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/settingsproperties.h"
#include "miscellaneous/textfactory.h"
#include "network-web/webfactory.h"

View File

@ -6,6 +6,7 @@
#include "gui/guiutilities.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include <QCheckBox>
#include <QDateTime>
@ -13,7 +14,8 @@
#include <QFileDialog>
#include <QPushButton>
FormBackupDatabaseSettings::FormBackupDatabaseSettings(QWidget* parent) : QDialog(parent), m_ui(new Ui::FormBackupDatabaseSettings) {
FormBackupDatabaseSettings::FormBackupDatabaseSettings(QWidget* parent)
: QDialog(parent), m_ui(new Ui::FormBackupDatabaseSettings) {
m_ui->setupUi(this);
setObjectName(QSL("form_backup_db_set"));
@ -24,21 +26,31 @@ FormBackupDatabaseSettings::FormBackupDatabaseSettings(QWidget* parent) : QDialo
connect(m_ui->m_checkBackupDatabase, &QCheckBox::toggled, this, &FormBackupDatabaseSettings::checkOkButton);
connect(m_ui->m_checkBackupSettings, &QCheckBox::toggled, this, &FormBackupDatabaseSettings::checkOkButton);
connect(m_ui->m_buttonBox->button(QDialogButtonBox::StandardButton::Ok), &QPushButton::clicked, this, &FormBackupDatabaseSettings::performBackup);
connect(m_ui->m_txtBackupName->lineEdit(), &BaseLineEdit::textChanged, this, &FormBackupDatabaseSettings::checkBackupNames);
connect(m_ui->m_txtBackupName->lineEdit(), &BaseLineEdit::textChanged, this, &FormBackupDatabaseSettings::checkOkButton);
connect(m_ui->m_buttonBox->button(QDialogButtonBox::StandardButton::Ok),
&QPushButton::clicked,
this,
&FormBackupDatabaseSettings::performBackup);
connect(m_ui->m_txtBackupName->lineEdit(),
&BaseLineEdit::textChanged,
this,
&FormBackupDatabaseSettings::checkBackupNames);
connect(m_ui->m_txtBackupName->lineEdit(),
&BaseLineEdit::textChanged,
this,
&FormBackupDatabaseSettings::checkOkButton);
connect(m_ui->m_btnSelectFolder, &QPushButton::clicked, this, &FormBackupDatabaseSettings::selectFolderInitial);
selectFolder(qApp->documentsFolder());
m_ui->m_txtBackupName->lineEdit()->setText(QSL(APP_LOW_NAME) + QL1S("_") +
QDateTime::currentDateTime().toString(QSL("yyyyMMddHHmm")));
m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Warning, tr("No operation executed yet."), tr("No operation executed yet."));
m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Warning,
tr("No operation executed yet."),
tr("No operation executed yet."));
if (qApp->database()->activeDatabaseDriver() != DatabaseDriver::DriverType::SQLite) {
m_ui->m_checkBackupDatabase->setDisabled(true);
}
GuiUtilities::restoreState(this,
qApp->settings()->value(GROUP(GUI), objectName(), QByteArray()).toByteArray());
GuiUtilities::restoreState(this, qApp->settings()->value(GROUP(GUI), objectName(), QByteArray()).toByteArray());
}
FormBackupDatabaseSettings::~FormBackupDatabaseSettings() {
@ -47,8 +59,10 @@ FormBackupDatabaseSettings::~FormBackupDatabaseSettings() {
void FormBackupDatabaseSettings::performBackup() {
try {
qApp->backupDatabaseSettings(m_ui->m_checkBackupDatabase->isChecked(), m_ui->m_checkBackupSettings->isChecked(),
m_ui->m_lblSelectFolder->label()->text(), m_ui->m_txtBackupName->lineEdit()->text());
qApp->backupDatabaseSettings(m_ui->m_checkBackupDatabase->isChecked(),
m_ui->m_checkBackupSettings->isChecked(),
m_ui->m_lblSelectFolder->label()->text(),
m_ui->m_txtBackupName->lineEdit()->text());
m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Ok,
tr("Backup was created successfully and stored in target directory."),
tr("Backup was created successfully."));
@ -64,11 +78,14 @@ void FormBackupDatabaseSettings::selectFolderInitial() {
void FormBackupDatabaseSettings::selectFolder(QString path) {
if (path.isEmpty()) {
path = QFileDialog::getExistingDirectory(this, tr("Select destination directory"), m_ui->m_lblSelectFolder->label()->text());
path = QFileDialog::getExistingDirectory(this,
tr("Select destination directory"),
m_ui->m_lblSelectFolder->label()->text());
}
if (!path.isEmpty()) {
m_ui->m_lblSelectFolder->setStatus(WidgetWithStatus::StatusType::Ok, QDir::toNativeSeparators(path),
m_ui->m_lblSelectFolder->setStatus(WidgetWithStatus::StatusType::Ok,
QDir::toNativeSeparators(path),
tr("Good destination directory is specified."));
}
}
@ -83,10 +100,10 @@ void FormBackupDatabaseSettings::checkBackupNames(const QString& name) {
}
void FormBackupDatabaseSettings::checkOkButton() {
m_ui->m_buttonBox->button(QDialogButtonBox::StandardButton::Ok)->setDisabled(m_ui->m_txtBackupName->lineEdit()->text().simplified().isEmpty() ||
m_ui->m_lblSelectFolder->label()->text().simplified().isEmpty() ||
(!m_ui->m_checkBackupDatabase->isChecked() &&
!m_ui->m_checkBackupSettings->isChecked()));
m_ui->m_buttonBox->button(QDialogButtonBox::StandardButton::Ok)
->setDisabled(m_ui->m_txtBackupName->lineEdit()->text().simplified().isEmpty() ||
m_ui->m_lblSelectFolder->label()->text().simplified().isEmpty() ||
(!m_ui->m_checkBackupDatabase->isChecked() && !m_ui->m_checkBackupSettings->isChecked()));
}
void FormBackupDatabaseSettings::hideEvent(QHideEvent* event) {

View File

@ -7,20 +7,28 @@
#include "gui/guiutilities.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include <QCloseEvent>
#include <QDialogButtonBox>
#include <QPushButton>
FormDatabaseCleanup::FormDatabaseCleanup(QWidget* parent) : QDialog(parent), m_ui(new Ui::FormDatabaseCleanup), m_cleaner(nullptr) {
FormDatabaseCleanup::FormDatabaseCleanup(QWidget* parent)
: QDialog(parent), m_ui(new Ui::FormDatabaseCleanup), m_cleaner(nullptr) {
m_ui->setupUi(this);
setObjectName(QSL("form_db_cleanup"));
GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("edit-clear")));
connect(m_ui->m_spinDays, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &FormDatabaseCleanup::updateDaysSuffix);
connect(m_ui->m_btnBox->button(QDialogButtonBox::StandardButton::Ok), &QPushButton::clicked, this, &FormDatabaseCleanup::startPurging);
connect(m_ui->m_spinDays,
static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
this,
&FormDatabaseCleanup::updateDaysSuffix);
connect(m_ui->m_btnBox->button(QDialogButtonBox::StandardButton::Ok),
&QPushButton::clicked,
this,
&FormDatabaseCleanup::startPurging);
connect(this, &FormDatabaseCleanup::purgeRequested, &m_cleaner, &DatabaseCleaner::purgeDatabaseData);
connect(&m_cleaner, &DatabaseCleaner::purgeStarted, this, &FormDatabaseCleanup::onPurgeStarted);
connect(&m_cleaner, &DatabaseCleaner::purgeProgress, this, &FormDatabaseCleanup::onPurgeProgress);
@ -31,8 +39,7 @@ FormDatabaseCleanup::FormDatabaseCleanup(QWidget* parent) : QDialog(parent), m_u
loadDatabaseInfo();
GuiUtilities::restoreState(this,
qApp->settings()->value(GROUP(GUI), objectName(), QByteArray()).toByteArray());
GuiUtilities::restoreState(this, qApp->settings()->value(GROUP(GUI), objectName(), QByteArray()).toByteArray());
}
void FormDatabaseCleanup::closeEvent(QCloseEvent* event) {
@ -73,7 +80,8 @@ void FormDatabaseCleanup::startPurging() {
void FormDatabaseCleanup::onPurgeStarted() {
m_ui->m_progressBar->setValue(0);
m_ui->m_btnBox->setEnabled(false);
m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Information, tr("Database cleanup is running."),
m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Information,
tr("Database cleanup is running."),
tr("Database cleanup is running."));
}
@ -92,7 +100,9 @@ void FormDatabaseCleanup::onPurgeFinished(bool finished) {
tr("Database cleanup is completed."));
}
else {
m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Error, tr("Database cleanup failed."), tr("Database cleanup failed."));
m_ui->m_lblResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("Database cleanup failed."),
tr("Database cleanup failed."));
}
loadDatabaseInfo();

View File

@ -10,6 +10,8 @@
#include "gui/reusable/styleditemdelegatewithoutfocus.h"
#include "miscellaneous/feedreader.h"
#include "miscellaneous/mutex.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/textfactory.h"
#include "services/abstract/feed.h"
#include "services/abstract/rootitem.h"
#include "services/abstract/serviceroot.h"

View File

@ -6,6 +6,7 @@
#include "gui/itemdetails.h"
#include "gui/webbrowser.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "services/abstract/gui/custommessagepreviewer.h"
#include "services/abstract/label.h"
#include "services/abstract/labelsnode.h"

View File

@ -3,31 +3,29 @@
#include "gui/reusable/basetreeview.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include <QKeyEvent>
BaseTreeView::BaseTreeView(QWidget* parent) : QTreeView(parent) {
m_allowedKeyboardKeys = {
Qt::Key::Key_Back,
Qt::Key::Key_Select,
Qt::Key::Key_Copy,
Qt::Key::Key_Shift,
Qt::Key::Key_Control,
Qt::Key::Key_Up,
Qt::Key::Key_Down,
Qt::Key::Key_Left,
Qt::Key::Key_Right,
Qt::Key::Key_Home,
Qt::Key::Key_End,
Qt::Key::Key_PageUp,
Qt::Key::Key_PageDown
};
m_allowedKeyboardKeys = {Qt::Key::Key_Back,
Qt::Key::Key_Select,
Qt::Key::Key_Copy,
Qt::Key::Key_Shift,
Qt::Key::Key_Control,
Qt::Key::Key_Up,
Qt::Key::Key_Down,
Qt::Key::Key_Left,
Qt::Key::Key_Right,
Qt::Key::Key_Home,
Qt::Key::Key_End,
Qt::Key::Key_PageUp,
Qt::Key::Key_PageDown};
}
void BaseTreeView::keyPressEvent(QKeyEvent* event) {
if (qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::OnlyBasicShortcutsInLists)).toBool() &&
!m_allowedKeyboardKeys.contains(event->key()) &&
!event->matches(QKeySequence::StandardKey::SelectAll)) {
!m_allowedKeyboardKeys.contains(event->key()) && !event->matches(QKeySequence::StandardKey::SelectAll)) {
event->ignore();
}
else {

View File

@ -7,6 +7,7 @@
#include "miscellaneous/application.h"
#include "miscellaneous/externaltool.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "network-web/cookiejar.h"
#include "network-web/silentnetworkaccessmanager.h"
#include "network-web/webfactory.h"

View File

@ -6,6 +6,7 @@
#include "database/mariadbdriver.h"
#include "definitions/definitions.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
SettingsDatabase::SettingsDatabase(Settings* settings, QWidget* parent)
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsDatabase) {

View File

@ -10,6 +10,8 @@
#include "gui/reusable/timespinbox.h"
#include "miscellaneous/application.h"
#include "miscellaneous/feedreader.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/textfactory.h"
#include <QFontDialog>
#include <QLocale>

View File

@ -3,6 +3,7 @@
#include "gui/settings/settingsgeneral.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/systemfactory.h"
SettingsGeneral::SettingsGeneral(Settings* settings, QWidget* parent)

View File

@ -66,10 +66,6 @@ bool SystemTrayIcon::isSystemTrayDesired() {
return qApp->settings()->value(GROUP(GUI), SETTING(GUI::UseTrayIcon)).toBool();
}
bool SystemTrayIcon::areNotificationsEnabled() {
return qApp->settings()->value(GROUP(GUI), SETTING(GUI::EnableNotifications)).toBool();
}
void SystemTrayIcon::showPrivate() {
// Make sure that application does not exit some window (for example
// the settings window) gets closed. Behavior for main window

View File

@ -18,10 +18,9 @@ class QEvent;
#if defined(Q_OS_WIN)
class TrayIconMenu : public QMenu {
Q_OBJECT
Q_OBJECT
public:
// Constructors and destructors.
explicit TrayIconMenu(const QString& title, QWidget* parent);
@ -32,10 +31,9 @@ class TrayIconMenu : public QMenu {
#endif
class SystemTrayIcon : public QSystemTrayIcon {
Q_OBJECT
Q_OBJECT
public:
// Constructors and destructors.
explicit SystemTrayIcon(const QString& normal_icon, const QString& plain_icon, FormMain* parent = nullptr);
virtual ~SystemTrayIcon();
@ -43,8 +41,11 @@ class SystemTrayIcon : public QSystemTrayIcon {
// Sets the number to be visible in the tray icon, number <= 0 removes it.
void setNumber(int number = -1, bool any_feed_has_new_unread_messages = false);
void showMessage(const QString& title, const QString& message, MessageIcon icon = Information,
int milliseconds_timeout_hint = TRAY_ICON_BUBBLE_TIMEOUT, const std::function<void ()>& functor = nullptr);
void showMessage(const QString& title,
const QString& message,
MessageIcon icon = Information,
int milliseconds_timeout_hint = TRAY_ICON_BUBBLE_TIMEOUT,
const std::function<void()>& functor = nullptr);
// Returns true if tray area is available and icon can be displayed.
static bool isSystemTrayAreaAvailable();
@ -52,9 +53,6 @@ class SystemTrayIcon : public QSystemTrayIcon {
// Returns true if user wants to have tray icon displayed.
static bool isSystemTrayDesired();
// Determines whether balloon tips are enabled or not on tray icons.
static bool areNotificationsEnabled();
public slots:
void show();

View File

@ -7,6 +7,7 @@
#include "gui/reusable/progressbarwithtext.h"
#include "gui/tabwidget.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include <QLabel>
#include <QToolButton>

View File

@ -12,6 +12,7 @@
#include "gui/webviewers/webviewer.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "network-web/networkfactory.h"
#include "network-web/readability.h"
#include "network-web/webfactory.h"

View File

@ -9,6 +9,7 @@
#include "miscellaneous/application.h"
#include "miscellaneous/externaltool.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "network-web/adblock/adblockrequestinfo.h"
#include "network-web/downloader.h"
#include "network-web/networkfactory.h"

View File

@ -7,6 +7,7 @@
#include "gui/webbrowser.h"
#include "miscellaneous/application.h"
#include "miscellaneous/externaltool.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/skinfactory.h"
#include "network-web/adblock/adblockicon.h"
#include "network-web/adblock/adblockmanager.h"
@ -16,6 +17,7 @@
#include <QFileIconProvider>
#include <QTimer>
#include <QToolTip>
#include <QWheelEvent>
#if QT_VERSION_MAJOR == 6
#include <QWebEngineContextMenuRequest>
@ -24,8 +26,6 @@
#include <QWebEngineContextMenuData>
#endif
#include <QWheelEvent>
WebEngineViewer::WebEngineViewer(QWidget* parent) : QWebEngineView(parent), m_browser(nullptr), m_root(nullptr) {
WebEnginePage* page = new WebEnginePage(this);

View File

@ -25,6 +25,7 @@
#include "miscellaneous/iofactory.h"
#include "miscellaneous/mutex.h"
#include "miscellaneous/notificationfactory.h"
#include "miscellaneous/settings.h"
#include "network-web/adblock/adblockicon.h"
#include "network-web/adblock/adblockmanager.h"
#include "network-web/webfactory.h"
@ -692,7 +693,7 @@ void Application::showGuiMessageCore(Notification::Event event,
m_toastNotifications->showNotification(event, msg, action);
return;
if (SystemTrayIcon::areNotificationsEnabled()) {
if (m_notifications->areNotificationsEnabled()) {
auto notification = m_notifications->notificationForEvent(event);
notification.playSound(this);

View File

@ -12,7 +12,6 @@
#include "miscellaneous/localization.h"
#include "miscellaneous/nodejs.h"
#include "miscellaneous/notification.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/singleapplication.h"
#include "miscellaneous/skinfactory.h"
#include "miscellaneous/systemfactory.h"
@ -46,6 +45,7 @@ class WebFactory;
class NotificationFactory;
class ToastNotificationsManager;
class WebViewer;
class Settings;
#if defined(Q_OS_WIN)
struct ITaskbarList4;

View File

@ -5,6 +5,7 @@
#include "definitions/definitions.h"
#include "exceptions/applicationexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include <QDir>
#include <QObject>

View File

@ -12,12 +12,12 @@
#include "gui/dialogs/formmessagefiltersmanager.h"
#include "miscellaneous/application.h"
#include "miscellaneous/mutex.h"
#include "miscellaneous/settings.h"
#include "services/abstract/cacheforserviceroot.h"
#include "services/abstract/serviceroot.h"
#include "services/feedly/feedlyentrypoint.h"
#include "services/gmail/gmailentrypoint.h"
#include "services/greader/greaderentrypoint.h"
#include "services/newsblur/newsblurentrypoint.h"
#include "services/owncloud/owncloudserviceentrypoint.h"
#include "services/reddit/redditentrypoint.h"
#include "services/standard/standardserviceentrypoint.h"
@ -65,7 +65,6 @@ QList<ServiceEntryPoint*> FeedReader::feedServices() {
m_feedServices.append(new OwnCloudServiceEntryPoint());
#if !defined(NDEBUG)
m_feedServices.append(new NewsBlurEntryPoint());
m_feedServices.append(new RedditEntryPoint());
#endif

View File

@ -3,6 +3,7 @@
#include "miscellaneous/localization.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include <QDir>
#include <QFileInfoList>

View File

@ -15,6 +15,14 @@ QList<Notification> NotificationFactory::allNotifications() const {
return m_notifications;
}
bool NotificationFactory::areNotificationsEnabled() const {
return qApp->settings()->value(GROUP(GUI), SETTING(GUI::EnableNotifications)).toBool();
}
bool NotificationFactory::useToastNotifications() const {
return qApp->settings()->value(GROUP(GUI), SETTING(GUI::EnableNotifications)).toBool();
}
Notification NotificationFactory::notificationForEvent(Notification::Event event) const {
if (!qApp->settings()->value(GROUP(GUI), SETTING(GUI::EnableNotifications)).toBool()) {
return Notification();

View File

@ -18,9 +18,11 @@ class NotificationFactory : public QObject {
QList<Notification> allNotifications() const;
Notification notificationForEvent(Notification::Event event) const;
public slots:
// Determines whether balloon tips are enabled or not.
bool areNotificationsEnabled() const;
bool useToastNotifications() const;
// Load saved notifications from settings
public slots:
void load(Settings* settings);
void save(const QList<Notification>& new_notifications, Settings* settings);

View File

@ -285,6 +285,13 @@ DVALUE(bool) GUI::StatusBarVisibleDef = true;
DKEY GUI::EnableNotifications = "enable_notifications";
DVALUE(bool) GUI::EnableNotificationsDef = true;
DKEY GUI::UseToastNotifications = "use_toast_notifications";
DVALUE(bool) GUI::UseToastNotificationsDef = true;
DKEY GUI::ToastNotificationsPosition = "toast_notifications_position";
DVALUE(ToastNotificationsManager::NotificationPosition)
GUI::ToastNotificationsPositionDef = ToastNotificationsManager::NotificationPosition::BottomRight;
DKEY GUI::HideMainWindowWhenMinimized = "hide_when_minimized";
DVALUE(bool) GUI::HideMainWindowWhenMinimizedDef = false;

View File

@ -7,6 +7,7 @@
#include "definitions/definitions.h"
#include "gui/notifications/toastnotificationsmanager.h"
#include "miscellaneous/settingsproperties.h"
#include "miscellaneous/textfactory.h"
@ -18,15 +19,15 @@
#include <QStringList>
#include <QWriteLocker>
#define KEY extern const QString
#define DKEY const QString
#define VALUE(x) extern const x
#define NON_CONST_VALUE(x) extern x
#define DVALUE(x) const x
#define KEY extern const QString
#define DKEY const QString
#define VALUE(x) extern const x
#define NON_CONST_VALUE(x) extern x
#define DVALUE(x) const x
#define NON_CONST_DVALUE(x) x
#define SETTING(x) x, x##Def
#define DEFAULT_VALUE(x) x##Def
#define GROUP(x) x::ID
#define SETTING(x) x, x##Def
#define DEFAULT_VALUE(x) x##Def
#define GROUP(x) x::ID
#if defined(USE_WEBENGINE)
namespace WebEngineAttributes {
@ -218,6 +219,12 @@ namespace GUI {
KEY EnableNotifications;
VALUE(bool) EnableNotificationsDef;
KEY UseToastNotifications;
VALUE(bool) UseToastNotificationsDef;
KEY ToastNotificationsPosition;
VALUE(ToastNotificationsManager::NotificationPosition) ToastNotificationsPositionDef;
KEY MessageViewState;
VALUE(QString) MessageViewStateDef;

View File

@ -3,6 +3,7 @@
#include "miscellaneous/skinfactory.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "network-web/networkfactory.h"
#include "services/abstract/rootitem.h"

View File

@ -7,6 +7,7 @@
#include "gui/dialogs/formmain.h"
#include "gui/dialogs/formupdate.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/systemfactory.h"
#if defined(Q_OS_WIN)

View File

@ -7,6 +7,7 @@
#include "exceptions/applicationexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iofactory.h"
#include "miscellaneous/settings.h"
#include <QDir>
#include <QLocale>

View File

@ -10,6 +10,7 @@
#include "gui/messagebox.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "network-web/webfactory.h"
#include <QInputDialog>

View File

@ -3,6 +3,7 @@
#include "network-web/basenetworkaccessmanager.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "network-web/webfactory.h"
#include <QNetworkProxy>

View File

@ -5,6 +5,7 @@
#include "definitions/definitions.h"
#include "gui/webviewers/webengine/webengineviewer.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "network-web/adblock/adblockmanager.h"
#include "network-web/adblock/adblockrequestinfo.h"
#include "network-web/webfactory.h"

View File

@ -5,6 +5,7 @@
#include "gui/messagebox.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "network-web/adblock/adblockmanager.h"
#include "network-web/cookiejar.h"
#include "network-web/readability.h"

View File

@ -5,6 +5,7 @@
#include "3rd-party/boolinq/boolinq.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "services/abstract/category.h"
#include "services/abstract/feed.h"
#include "services/abstract/label.h"

View File

@ -6,6 +6,7 @@
#include "database/databasequeries.h"
#include "exceptions/networkexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "network-web/networkfactory.h"
#include "network-web/webfactory.h"
#include "services/abstract/category.h"

View File

@ -8,6 +8,7 @@
#include "exceptions/applicationexception.h"
#include "exceptions/networkexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/textfactory.h"
#include "network-web/networkfactory.h"
#include "network-web/oauth2service.h"

View File

@ -8,6 +8,7 @@
#include "exceptions/feedfetchexception.h"
#include "exceptions/networkexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "network-web/networkfactory.h"
#include "network-web/oauth2service.h"
#include "network-web/webfactory.h"

View File

@ -1,17 +0,0 @@
#ifndef NEWSBLUR_DEFINITIONS_H
#define NEWSBLUR_DEFINITIONS_H
// Misc.
#define NEWSBLUR_DEFAULT_BATCH_SIZE 500
#define NEWSBLUS_AUTH_COOKIE "newsblur_sessionid"
// URLs.
#define NEWSBLUR_URL "https://newsblur.com"
// API.
#define NEWSBLUR_API_LOGIN "api/login"
#define NEWSBLUR_API_LOGOUT "api/logout"
#define NEWSBLUR_API_SIGNUP "api/signup"
#define NEWSBLUR_API_FEEDS "reader/feeds"
#endif // NEWSBLUR_DEFINITIONS_H

View File

@ -1,59 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/newsblur/gui/formeditnewsbluraccount.h"
#include "miscellaneous/iconfactory.h"
#include "services/newsblur/gui/newsbluraccountdetails.h"
#include "services/newsblur/newsblurnetwork.h"
#include "services/newsblur/newsblurserviceroot.h"
FormEditNewsBlurAccount::FormEditNewsBlurAccount(QWidget* parent)
: FormAccountDetails(qApp->icons()->miscIcon(QSL("newsblur")), parent), m_details(new NewsBlurAccountDetails(this)) {
insertCustomTab(m_details, tr("Server setup"), 0);
activateTab(0);
connect(m_details->m_ui.m_btnTestSetup, &QPushButton::clicked, this, &FormEditNewsBlurAccount::performTest);
m_details->m_ui.m_txtUrl->setFocus();
}
void FormEditNewsBlurAccount::apply() {
FormAccountDetails::apply();
NewsBlurServiceRoot* existing_root = account<NewsBlurServiceRoot>();
bool using_another_acc = m_details->m_ui.m_txtUsername->lineEdit()->text() != existing_root->network()->username() ||
m_details->m_ui.m_txtUrl->lineEdit()->text() != existing_root->network()->baseUrl();
existing_root->network()->setBaseUrl(m_details->m_ui.m_txtUrl->lineEdit()->text());
existing_root->network()->setUsername(m_details->m_ui.m_txtUsername->lineEdit()->text());
existing_root->network()->setPassword(m_details->m_ui.m_txtPassword->lineEdit()->text());
existing_root->network()->setBatchSize(m_details->m_ui.m_spinLimitMessages->value());
existing_root->network()->setDownloadOnlyUnreadMessages(m_details->m_ui.m_cbDownloadOnlyUnreadMessages->isChecked());
existing_root->saveAccountDataToDatabase();
accept();
if (!m_creatingNew) {
if (using_another_acc) {
existing_root->completelyRemoveAllData();
}
existing_root->start(true);
}
}
void FormEditNewsBlurAccount::loadAccountData() {
FormAccountDetails::loadAccountData();
NewsBlurServiceRoot* existing_root = account<NewsBlurServiceRoot>();
m_details->m_ui.m_txtUsername->lineEdit()->setText(existing_root->network()->username());
m_details->m_ui.m_txtPassword->lineEdit()->setText(existing_root->network()->password());
m_details->m_ui.m_txtUrl->lineEdit()->setText(existing_root->network()->baseUrl());
m_details->m_ui.m_spinLimitMessages->setValue(existing_root->network()->batchSize());
m_details->m_ui.m_cbDownloadOnlyUnreadMessages->setChecked(existing_root->network()->downloadOnlyUnreadMessages());
}
void FormEditNewsBlurAccount::performTest() {
m_details->performTest(m_proxyDetails->proxy());
}

View File

@ -1,30 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef FORMEDITNEWSBLURACCOUNT_H
#define FORMEDITNEWSBLURACCOUNT_H
#include "services/abstract/gui/formaccountdetails.h"
class NewsBlurAccountDetails;
class NewsBlurServiceRoot;
class FormEditNewsBlurAccount : public FormAccountDetails {
Q_OBJECT
public:
explicit FormEditNewsBlurAccount(QWidget* parent = nullptr);
protected slots:
virtual void apply();
protected:
virtual void loadAccountData();
private slots:
void performTest();
private:
NewsBlurAccountDetails* m_details;
};
#endif // FORMEDITNEWSBLURACCOUNT_H

View File

@ -1,108 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/newsblur/gui/newsbluraccountdetails.h"
#include "definitions/definitions.h"
#include "exceptions/applicationexception.h"
#include "exceptions/networkexception.h"
#include "services/newsblur/newsblurnetwork.h"
#include <QVariantHash>
NewsBlurAccountDetails::NewsBlurAccountDetails(QWidget* parent) : QWidget(parent), m_lastProxy({}) {
m_ui.setupUi(this);
m_ui.m_lblTestResult->label()->setWordWrap(true);
m_ui.m_txtPassword->lineEdit()->setPasswordMode(true);
m_ui.m_txtPassword->lineEdit()->setPlaceholderText(tr("Password for your account"));
m_ui.m_txtUsername->lineEdit()->setPlaceholderText(tr("Username for your account"));
m_ui.m_txtUrl->lineEdit()->setPlaceholderText(tr("URL of your server, without any service-specific path"));
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Information,
tr("No test done yet."),
tr("Here, results of connection test are shown."));
m_ui.m_lblLimitMessages->setHelpText(tr("Some feeds might contain tens of thousands of articles "
"and downloading all of them could take great amount of time, "
"so sometimes it is good to download "
"only certain amount of newest messages."),
true);
connect(m_ui.m_txtPassword->lineEdit(), &BaseLineEdit::textChanged, this, &NewsBlurAccountDetails::onPasswordChanged);
connect(m_ui.m_txtUsername->lineEdit(), &BaseLineEdit::textChanged, this, &NewsBlurAccountDetails::onUsernameChanged);
connect(m_ui.m_txtUrl->lineEdit(), &BaseLineEdit::textChanged, this, &NewsBlurAccountDetails::onUrlChanged);
setTabOrder(m_ui.m_txtUrl->lineEdit(), m_ui.m_cbDownloadOnlyUnreadMessages);
setTabOrder(m_ui.m_cbDownloadOnlyUnreadMessages, m_ui.m_spinLimitMessages);
setTabOrder(m_ui.m_spinLimitMessages, m_ui.m_txtUsername->lineEdit());
setTabOrder(m_ui.m_txtUsername->lineEdit(), m_ui.m_txtPassword->lineEdit());
setTabOrder(m_ui.m_txtPassword->lineEdit(), m_ui.m_btnTestSetup);
onPasswordChanged();
onUsernameChanged();
onUrlChanged();
}
void NewsBlurAccountDetails::performTest(const QNetworkProxy& custom_proxy) {
m_lastProxy = custom_proxy;
NewsBlurNetwork factory;
factory.setUsername(m_ui.m_txtUsername->lineEdit()->text());
factory.setPassword(m_ui.m_txtPassword->lineEdit()->text());
factory.setBaseUrl(m_ui.m_txtUrl->lineEdit()->text());
try {
LoginResult result = factory.login(custom_proxy);
if (result.m_authenticated && !result.m_sessiodId.isEmpty()) {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Ok, tr("You are good to go!"), tr("Yeah."));
}
else {
throw ApplicationException(result.m_errors.join(QSL(", ")));
}
}
catch (const NetworkException& netEx) {
m_ui.m_lblTestResult
->setStatus(WidgetWithStatus::StatusType::Error,
tr("Network error: '%1'.").arg(NetworkFactory::networkErrorText(netEx.networkError())),
tr("Network error, have you entered correct username and password?"));
}
catch (const ApplicationException& ex) {
m_ui.m_lblTestResult->setStatus(WidgetWithStatus::StatusType::Error,
tr("Error: '%1'.").arg(ex.message()),
tr("Error, have you entered correct Nextcloud endpoint and password?"));
}
}
void NewsBlurAccountDetails::onUsernameChanged() {
const QString username = m_ui.m_txtUsername->lineEdit()->text();
if (username.isEmpty()) {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Error, tr("Username cannot be empty."));
}
else {
m_ui.m_txtUsername->setStatus(WidgetWithStatus::StatusType::Ok, tr("Username is okay."));
}
}
void NewsBlurAccountDetails::onPasswordChanged() {
const QString password = m_ui.m_txtPassword->lineEdit()->text();
if (password.isEmpty()) {
m_ui.m_txtPassword->setStatus(WidgetWithStatus::StatusType::Error, tr("Password cannot be empty."));
}
else {
m_ui.m_txtPassword->setStatus(WidgetWithStatus::StatusType::Ok, tr("Password is okay."));
}
}
void NewsBlurAccountDetails::onUrlChanged() {
const QString url = m_ui.m_txtUrl->lineEdit()->text();
if (url.isEmpty()) {
m_ui.m_txtUrl->setStatus(WidgetWithStatus::StatusType::Error, tr("URL cannot be empty."));
}
else {
m_ui.m_txtUrl->setStatus(WidgetWithStatus::StatusType::Ok, tr("URL is okay."));
}
}

View File

@ -1,33 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef NEWSBLURACCOUNTDETAILS_H
#define NEWSBLURACCOUNTDETAILS_H
#include <QWidget>
#include "ui_newsbluraccountdetails.h"
#include "services/newsblur/newsblurserviceroot.h"
#include <QNetworkProxy>
class NewsBlurAccountDetails : public QWidget {
Q_OBJECT
friend class FormEditNewsBlurAccount;
public:
explicit NewsBlurAccountDetails(QWidget* parent = nullptr);
private slots:
void performTest(const QNetworkProxy& custom_proxy);
void onUsernameChanged();
void onPasswordChanged();
void onUrlChanged();
private:
Ui::NewsBlurAccountDetails m_ui;
QNetworkProxy m_lastProxy;
};
#endif // NEWSBLURACCOUNTDETAILS_H

View File

@ -1,163 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>NewsBlurAccountDetails</class>
<widget class="QWidget" name="NewsBlurAccountDetails">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>430</width>
<height>281</height>
</rect>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="m_lblTitle">
<property name="text">
<string>URL</string>
</property>
<property name="buddy">
<cstring>m_txtUrl</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="LineEditWithStatus" name="m_txtUrl" native="true"/>
</item>
<item row="1" column="0" colspan="2">
<widget class="QCheckBox" name="m_cbDownloadOnlyUnreadMessages">
<property name="text">
<string>Download unread articles only</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="m_lblLimitMessagesShort">
<property name="text">
<string>Only download newest X articles per feed</string>
</property>
<property name="buddy">
<cstring>m_spinLimitMessages</cstring>
</property>
</widget>
</item>
<item>
<widget class="MessageCountSpinBox" name="m_spinLimitMessages"/>
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<widget class="HelpSpoiler" name="m_lblLimitMessages" native="true"/>
</item>
<item row="4" column="0" colspan="2">
<widget class="QGroupBox" name="m_gbAuth">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Authentication</string>
</property>
<layout class="QFormLayout" name="formLayout_4">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Username</string>
</property>
<property name="buddy">
<cstring>m_txtUsername</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="LineEditWithStatus" name="m_txtUsername" native="true"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Password</string>
</property>
<property name="buddy">
<cstring>m_txtPassword</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="LineEditWithStatus" name="m_txtPassword" native="true"/>
</item>
</layout>
</widget>
</item>
<item row="5" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="m_btnTestSetup">
<property name="text">
<string>&amp;Test setup</string>
</property>
</widget>
</item>
<item>
<widget class="LabelWithStatus" name="m_lblTestResult" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>409</width>
<height>60</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LabelWithStatus</class>
<extends>QWidget</extends>
<header>labelwithstatus.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>LineEditWithStatus</class>
<extends>QWidget</extends>
<header>lineeditwithstatus.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>MessageCountSpinBox</class>
<extends>QSpinBox</extends>
<header>messagecountspinbox.h</header>
</customwidget>
<customwidget>
<class>HelpSpoiler</class>
<extends>QWidget</extends>
<header>helpspoiler.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>m_cbDownloadOnlyUnreadMessages</tabstop>
<tabstop>m_spinLimitMessages</tabstop>
<tabstop>m_btnTestSetup</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -1,42 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/newsblur/newsblurentrypoint.h"
#include "database/databasequeries.h"
#include "definitions/definitions.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "services/newsblur/gui/formeditnewsbluraccount.h"
#include "services/newsblur/newsblurserviceroot.h"
ServiceRoot* NewsBlurEntryPoint::createNewRoot() const {
FormEditNewsBlurAccount form_acc(qApp->mainFormWidget());
return form_acc.addEditAccount<NewsBlurServiceRoot>();
}
QList<ServiceRoot*> NewsBlurEntryPoint::initializeSubtree() const {
QSqlDatabase database = qApp->database()->driver()->connection(QSL("NewsBlurEntryPoint"));
return DatabaseQueries::getAccounts<NewsBlurServiceRoot>(database, code());
}
QString NewsBlurEntryPoint::name() const {
return QSL("NewsBlur");
}
QString NewsBlurEntryPoint::code() const {
return QSL(SERVICE_CODE_NEWSBLUR);
}
QString NewsBlurEntryPoint::description() const {
return QObject::tr("Personal news reader bringing people together to talk about the world.");
}
QString NewsBlurEntryPoint::author() const {
return QSL(APP_AUTHOR);
}
QIcon NewsBlurEntryPoint::icon() const {
return qApp->icons()->miscIcon(QSL("newsblur"));
}

View File

@ -1,19 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef NEWSBLURENTRYPOINT_H
#define NEWSBLURENTRYPOINT_H
#include "services/abstract/serviceentrypoint.h"
class NewsBlurEntryPoint : public ServiceEntryPoint {
public:
virtual ServiceRoot* createNewRoot() const;
virtual QList<ServiceRoot*> initializeSubtree() const;
virtual QString name() const;
virtual QString code() const;
virtual QString description() const;
virtual QString author() const;
virtual QIcon icon() const;
};
#endif // NEWSBLURENTRYPOINT_H

View File

@ -1,258 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/newsblur/newsblurnetwork.h"
#include "3rd-party/boolinq/boolinq.h"
#include "exceptions/applicationexception.h"
#include "exceptions/networkexception.h"
#include "miscellaneous/application.h"
#include "network-web/networkfactory.h"
#include "services/abstract/category.h"
#include "services/newsblur/definitions.h"
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
NewsBlurNetwork::NewsBlurNetwork(QObject* parent)
: QObject(parent), m_root(nullptr), m_username(QString()), m_password(QString()), m_baseUrl(QSL(NEWSBLUR_URL)),
m_batchSize(NEWSBLUR_DEFAULT_BATCH_SIZE), m_downloadOnlyUnreadMessages(false) {
clearCredentials();
}
RootItem* NewsBlurNetwork::categoriesFeedsLabelsTree(const QNetworkProxy& proxy) {
QJsonDocument json = feeds(proxy);
RootItem* root = new RootItem();
const auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
QMap<QString, RootItem*> cats;
QList<QPair<RootItem*, QJsonArray>> cats_array = {{root, json.object()["folders"].toArray()}};
while (!cats_array.isEmpty()) {
// Add direct descendants as categories to parent, then process their children.
QPair<RootItem*, QJsonArray> cats_for_parent = cats_array.takeFirst();
for (const QJsonValue& var : cats_for_parent.second) {
if (var.type() == QJsonValue::Type::Double) {
// We have feed.
Feed* feed = new Feed();
feed->setCustomId(QString::number(var.toInt()));
QJsonObject feed_json = json.object()["feeds"].toObject()[feed->customId()].toObject();
feed->setTitle(feed_json["feed_title"].toString());
feed->setSource(feed_json["feed_link"].toString());
QString favicon_url = feed_json["favicon_url"].toString();
if (!favicon_url.isEmpty()) {
QPixmap icon;
if (NetworkFactory::downloadIcon({{favicon_url, true}}, timeout, icon, {}, proxy) ==
QNetworkReply::NetworkError::NoError) {
feed->setIcon(icon);
}
}
cats_for_parent.first->appendChild(feed);
}
else if (var.type() == QJsonValue::Type::Object) {
const QString category_name = var.toObject().keys().first();
Category* category = new Category();
category->setTitle(category_name);
category->setCustomId(category_name);
cats_for_parent.first->appendChild(category);
cats_array.append({category, var.toObject()[category_name].toArray()});
}
}
}
return root;
}
QJsonDocument NewsBlurNetwork::feeds(const QNetworkProxy& proxy) {
ensureLogin(proxy);
const QString full_url = generateFullUrl(Operations::Feeds);
const auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
QByteArray output;
auto network_result = NetworkFactory::performNetworkOperation(full_url,
timeout,
{},
output,
QNetworkAccessManager::Operation::GetOperation,
{},
false,
{},
{},
proxy);
if (network_result.m_networkError == QNetworkReply::NetworkError::NoError) {
ApiResult res;
res.decodeBaseResponse(output);
return res.m_json;
}
else {
throw NetworkException(network_result.m_networkError, output);
}
}
LoginResult NewsBlurNetwork::login(const QNetworkProxy& proxy) {
const QString full_url = generateFullUrl(Operations::Login);
const auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
const QString data = QSL("username=%1&password=%2").arg(m_username, m_password);
QByteArray output;
auto network_result =
NetworkFactory::performNetworkOperation(full_url,
timeout,
data.toUtf8(),
output,
QNetworkAccessManager::Operation::PostOperation,
{{QSL(HTTP_HEADERS_CONTENT_TYPE).toLocal8Bit(),
QSL("application/x-www-form-urlencoded").toLocal8Bit()}},
false,
{},
{},
proxy);
if (network_result.m_networkError == QNetworkReply::NetworkError::NoError) {
LoginResult res;
res.decodeBaseResponse(output);
res.m_userId = res.m_json.object()["user_id"].toInt();
res.m_sessiodId = boolinq::from(network_result.m_cookies)
.firstOrDefault([](const QNetworkCookie& c) {
return c.name() == QSL(NEWSBLUS_AUTH_COOKIE);
})
.value();
return res;
}
else {
throw NetworkException(network_result.m_networkError, output);
}
}
QString NewsBlurNetwork::username() const {
return m_username;
}
void NewsBlurNetwork::setUsername(const QString& username) {
m_username = username;
}
QString NewsBlurNetwork::password() const {
return m_password;
}
void NewsBlurNetwork::setPassword(const QString& password) {
m_password = password;
}
QString NewsBlurNetwork::baseUrl() const {
return m_baseUrl;
}
void NewsBlurNetwork::setBaseUrl(const QString& base_url) {
m_baseUrl = base_url;
}
QPair<QByteArray, QByteArray> NewsBlurNetwork::authHeader() const {
return {QSL("Cookie").toLocal8Bit(), QSL("newsblur_sessionid=%1").arg(m_authSid).toLocal8Bit()};
}
void NewsBlurNetwork::ensureLogin(const QNetworkProxy& proxy) {
if (m_authSid.isEmpty()) {
try {
auto log = login(proxy);
if (log.m_authenticated && !log.m_sessiodId.isEmpty()) {
m_authSid = log.m_sessiodId;
}
else {
throw ApplicationException(log.m_errors.join(QSL(", ")));
}
}
catch (const NetworkException& ex) {
throw ex;
}
catch (const ApplicationException& ex) {
throw ex;
}
}
}
int NewsBlurNetwork::batchSize() const {
return m_batchSize;
}
void NewsBlurNetwork::setBatchSize(int batch_size) {
m_batchSize = batch_size;
}
void NewsBlurNetwork::clearCredentials() {
m_authSid = QString{};
m_userId = {};
}
QString NewsBlurNetwork::sanitizedBaseUrl() const {
QString base_url = m_baseUrl;
if (!base_url.endsWith('/')) {
base_url = base_url + QL1C('/');
}
return base_url;
}
QString NewsBlurNetwork::generateFullUrl(NewsBlurNetwork::Operations operation) const {
switch (operation) {
case Operations::Login:
return sanitizedBaseUrl() + QSL(NEWSBLUR_API_LOGIN);
case Operations::Feeds:
return sanitizedBaseUrl() + QSL(NEWSBLUR_API_FEEDS);
default:
return sanitizedBaseUrl();
}
}
void NewsBlurNetwork::setRoot(NewsBlurServiceRoot* root) {
m_root = root;
}
bool NewsBlurNetwork::downloadOnlyUnreadMessages() const {
return m_downloadOnlyUnreadMessages;
}
void NewsBlurNetwork::setDownloadOnlyUnreadMessages(bool download_only_unread) {
m_downloadOnlyUnreadMessages = download_only_unread;
}
void ApiResult::decodeBaseResponse(const QByteArray& json_data) {
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(json_data, &err);
if (err.error != QJsonParseError::ParseError::NoError) {
throw ApplicationException(err.errorString());
}
m_json = doc;
m_authenticated = doc.object()["authenticated"].toBool();
m_code = doc.object()["code"].toInt();
QStringList errs;
QJsonObject obj_errs = doc.object()["errors"].toObject();
for (const QString& key : obj_errs.keys()) {
for (const QJsonValue& val : obj_errs.value(key).toArray()) {
errs << val.toString();
}
}
m_errors = errs;
}

View File

@ -1,86 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef NEWSBLURNETWORK_H
#define NEWSBLURNETWORK_H
#include <QObject>
#include "network-web/networkfactory.h"
#include "services/abstract/feed.h"
#include "services/newsblur/newsblurserviceroot.h"
struct ApiResult {
bool m_authenticated;
int m_code;
QStringList m_errors;
QJsonDocument m_json;
void decodeBaseResponse(const QByteArray& json_data);
};
struct LoginResult : ApiResult {
QString m_sessiodId;
int m_userId;
};
class NewsBlurNetwork : public QObject {
Q_OBJECT
public:
enum class Operations {
Login,
Feeds
};
explicit NewsBlurNetwork(QObject* parent = nullptr);
// Convenience methods.
RootItem* categoriesFeedsLabelsTree(const QNetworkProxy& proxy);
// API.
QJsonDocument feeds(const QNetworkProxy& proxy);
// Misc.
void clearCredentials();
QString username() const;
void setUsername(const QString& username);
QString password() const;
void setPassword(const QString& password);
QString baseUrl() const;
void setBaseUrl(const QString& base_url);
int batchSize() const;
void setBatchSize(int batch_size);
bool downloadOnlyUnreadMessages() const;
void setDownloadOnlyUnreadMessages(bool download_only_unread);
void setRoot(NewsBlurServiceRoot* root);
// API methods.
LoginResult login(const QNetworkProxy& proxy);
private:
QPair<QByteArray, QByteArray> authHeader() const;
// Make sure we are logged in and if we are not, throw exception.
void ensureLogin(const QNetworkProxy& proxy);
QString sanitizedBaseUrl() const;
QString generateFullUrl(Operations operation) const;
private:
NewsBlurServiceRoot* m_root;
QString m_username;
QString m_password;
QString m_baseUrl;
int m_batchSize;
bool m_downloadOnlyUnreadMessages;
QString m_authSid;
int m_userId;
};
#endif // NEWSBLURNETWORK_H

View File

@ -1,138 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#include "services/newsblur/newsblurserviceroot.h"
#include "database/databasequeries.h"
#include "definitions/definitions.h"
#include "exceptions/feedfetchexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/textfactory.h"
#include "services/newsblur/gui/formeditnewsbluraccount.h"
#include "services/newsblur/newsblurentrypoint.h"
#include "services/newsblur/newsblurnetwork.h"
NewsBlurServiceRoot::NewsBlurServiceRoot(RootItem* parent) : ServiceRoot(parent), m_network(new NewsBlurNetwork(this)) {
m_network->setRoot(this);
setIcon(NewsBlurEntryPoint().icon());
}
bool NewsBlurServiceRoot::isSyncable() const {
return true;
}
bool NewsBlurServiceRoot::canBeEdited() const {
return true;
}
bool NewsBlurServiceRoot::editViaGui() {
FormEditNewsBlurAccount form_pointer(qApp->mainFormWidget());
form_pointer.addEditAccount(this);
return true;
}
QVariantHash NewsBlurServiceRoot::customDatabaseData() const {
QVariantHash data;
data[QSL("username")] = m_network->username();
data[QSL("password")] = TextFactory::encrypt(m_network->password());
data[QSL("url")] = m_network->baseUrl();
return data;
}
void NewsBlurServiceRoot::setCustomDatabaseData(const QVariantHash& data) {
m_network->setUsername(data[QSL("username")].toString());
m_network->setPassword(TextFactory::decrypt(data[QSL("password")].toString()));
m_network->setBaseUrl(data[QSL("url")].toString());
}
QList<Message> NewsBlurServiceRoot::obtainNewMessages(Feed* feed,
const QHash<ServiceRoot::BagOfMessages, QStringList>&
stated_messages,
const QHash<QString, QStringList>& tagged_messages) {
Feed::Status error = Feed::Status::Normal;
QList<Message> msgs;
// TODO::
if (error != Feed::Status::NewMessages && error != Feed::Status::Normal) {
throw FeedFetchException(error);
}
else {
return msgs;
}
}
void NewsBlurServiceRoot::start(bool freshly_activated) {
if (!freshly_activated) {
DatabaseQueries::loadRootFromDatabase<Category, Feed>(this);
loadCacheFromFile();
}
updateTitleIcon();
if (getSubTreeFeeds().isEmpty()) {
syncIn();
}
}
QString NewsBlurServiceRoot::code() const {
return NewsBlurEntryPoint().code();
}
void NewsBlurServiceRoot::saveAllCachedData(bool ignore_errors) {
auto msg_cache = takeMessageCache();
QMapIterator<RootItem::ReadStatus, QStringList> i(msg_cache.m_cachedStatesRead);
/*
// Save the actual data read/unread.
while (i.hasNext()) {
i.next();
auto key = i.key();
QStringList ids = i.value();
if (!ids.isEmpty()) {
if (network()->markMessagesRead(key, ids, networkProxy()) != QNetworkReply::NetworkError::NoError &&
!ignore_errors) {
addMessageStatesToCache(ids, key);
}
}
}
QMapIterator<RootItem::Importance, QList<Message>> j(msg_cache.m_cachedStatesImportant);
// Save the actual data important/not important.
while (j.hasNext()) {
j.next();
auto key = j.key();
QList<Message> messages = j.value();
if (!messages.isEmpty()) {
QStringList custom_ids; custom_ids.reserve(messages.size());
for (const Message& msg : messages) {
custom_ids.append(msg.m_customId);
}
if (network()->markMessagesStarred(key, custom_ids, networkProxy()) != QNetworkReply::NetworkError::NoError &&
!ignore_errors) {
addMessageStatesToCache(messages, key);
}
}
}
*/
}
ServiceRoot::LabelOperation NewsBlurServiceRoot::supportedLabelOperations() const {
return ServiceRoot::LabelOperation::Synchronised;
}
void NewsBlurServiceRoot::updateTitleIcon() {
setTitle(QSL("%1 (%2)").arg(m_network->username(), NewsBlurEntryPoint().name()));
}
RootItem* NewsBlurServiceRoot::obtainNewTreeForSyncIn() const {
return m_network->categoriesFeedsLabelsTree(networkProxy());
;
}

View File

@ -1,46 +0,0 @@
// For license of this file, see <project-root-folder>/LICENSE.md.
#ifndef NEWSBLURSERVICEROOT_H
#define NEWSBLURSERVICEROOT_H
#include "services/abstract/cacheforserviceroot.h"
#include "services/abstract/serviceroot.h"
class NewsBlurNetwork;
class NewsBlurServiceRoot : public ServiceRoot, public CacheForServiceRoot {
Q_OBJECT
public:
explicit NewsBlurServiceRoot(RootItem* parent = nullptr);
virtual bool isSyncable() const;
virtual bool canBeEdited() const;
virtual bool editViaGui();
virtual void start(bool freshly_activated);
virtual QString code() const;
virtual void saveAllCachedData(bool ignore_errors);
virtual LabelOperation supportedLabelOperations() const;
virtual QVariantHash customDatabaseData() const;
virtual void setCustomDatabaseData(const QVariantHash& data);
virtual QList<Message> obtainNewMessages(Feed* feed,
const QHash<ServiceRoot::BagOfMessages, QStringList>& stated_messages,
const QHash<QString, QStringList>& tagged_messages);
NewsBlurNetwork* network() const;
protected:
virtual RootItem* obtainNewTreeForSyncIn() const;
private:
void updateTitleIcon();
private:
NewsBlurNetwork* m_network;
};
inline NewsBlurNetwork* NewsBlurServiceRoot::network() const {
return m_network;
}
#endif // NEWSBLURSERVICEROOT_H

View File

@ -7,6 +7,7 @@
#include "exceptions/applicationexception.h"
#include "exceptions/networkexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/settings.h"
#include "network-web/networkfactory.h"
#include "network-web/oauth2service.h"
#include "services/reddit/definitions.h"

View File

@ -7,6 +7,7 @@
#include "exceptions/feedfetchexception.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
#include "miscellaneous/settings.h"
#include "miscellaneous/textfactory.h"
#include "network-web/networkfactory.h"
#include "services/abstract/category.h"