greader plugin now has ability to export/import feeds via API usage
This commit is contained in:
parent
95df21e385
commit
edc30fbe48
@ -241,6 +241,7 @@ void FeedsView::clearSelectedItems() {
|
|||||||
{},
|
{},
|
||||||
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No,
|
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No,
|
||||||
QMessageBox::StandardButton::No) != QMessageBox::StandardButton::Yes) {
|
QMessageBox::StandardButton::No) != QMessageBox::StandardButton::Yes) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto* it : selectedItems()) {
|
for (auto* it : selectedItems()) {
|
||||||
@ -257,6 +258,7 @@ void FeedsView::clearAllItems() {
|
|||||||
{},
|
{},
|
||||||
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No,
|
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No,
|
||||||
QMessageBox::StandardButton::No) != QMessageBox::StandardButton::Yes) {
|
QMessageBox::StandardButton::No) != QMessageBox::StandardButton::Yes) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_sourceModel->markItemCleared(m_sourceModel->rootItem(), false);
|
m_sourceModel->markItemCleared(m_sourceModel->rootItem(), false);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "gui/notifications/basetoastnotification.h"
|
#include "gui/notifications/basetoastnotification.h"
|
||||||
|
|
||||||
#include "miscellaneous/iconfactory.h"
|
#include "miscellaneous/iconfactory.h"
|
||||||
|
#include "miscellaneous/settings.h"
|
||||||
|
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
@ -14,7 +15,7 @@ using namespace std::chrono_literals;
|
|||||||
|
|
||||||
BaseToastNotification::BaseToastNotification(QWidget* parent) : QDialog(parent), m_timerId(-1) {
|
BaseToastNotification::BaseToastNotification(QWidget* parent) : QDialog(parent), m_timerId(-1) {
|
||||||
setAttribute(Qt::WidgetAttribute::WA_ShowWithoutActivating);
|
setAttribute(Qt::WidgetAttribute::WA_ShowWithoutActivating);
|
||||||
setFixedWidth(NOTIFICATIONS_WIDTH);
|
setFixedWidth(qApp->settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsWidth)).toInt());
|
||||||
setFocusPolicy(Qt::FocusPolicy::NoFocus);
|
setFocusPolicy(Qt::FocusPolicy::NoFocus);
|
||||||
|
|
||||||
setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose, false);
|
setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose, false);
|
||||||
|
@ -56,6 +56,8 @@ void ToastNotificationsManager::setPosition(NotificationPosition position) {
|
|||||||
m_position = position;
|
m_position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ToastNotificationsManager::resetNotifications() {}
|
||||||
|
|
||||||
void ToastNotificationsManager::clear() {
|
void ToastNotificationsManager::clear() {
|
||||||
for (BaseToastNotification* notif : m_activeNotifications) {
|
for (BaseToastNotification* notif : m_activeNotifications) {
|
||||||
closeNotification(notif, true);
|
closeNotification(notif, true);
|
||||||
|
@ -42,6 +42,8 @@ class ToastNotificationsManager : public QObject {
|
|||||||
NotificationPosition position() const;
|
NotificationPosition position() const;
|
||||||
void setPosition(NotificationPosition position);
|
void setPosition(NotificationPosition position);
|
||||||
|
|
||||||
|
void resetNotifications();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clear();
|
void clear();
|
||||||
void showNotification(Notification::Event event, const GuiMessage& msg, const GuiAction& action);
|
void showNotification(Notification::Event event, const GuiMessage& msg, const GuiAction& action);
|
||||||
|
@ -17,11 +17,12 @@
|
|||||||
SettingsLocalization::SettingsLocalization(Settings* settings, QWidget* parent)
|
SettingsLocalization::SettingsLocalization(Settings* settings, QWidget* parent)
|
||||||
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsLocalization) {
|
: SettingsPanel(settings, parent), m_ui(new Ui::SettingsLocalization) {
|
||||||
m_ui->setupUi(this);
|
m_ui->setupUi(this);
|
||||||
m_ui->m_treeLanguages->setColumnCount(4);
|
m_ui->m_lblAuthors->label()->setWordWrap(true);
|
||||||
|
m_ui->m_treeLanguages->setColumnCount(3);
|
||||||
m_ui->m_treeLanguages->setHeaderHidden(false);
|
m_ui->m_treeLanguages->setHeaderHidden(false);
|
||||||
m_ui->m_treeLanguages->setHeaderLabels(QStringList() << /*: Language column of language list. */ tr("Language")
|
m_ui->m_treeLanguages->setHeaderLabels(QStringList() << /*: Language column of language list. */ tr("Language")
|
||||||
<< /*: Lang. code column of language list. */ tr("Code")
|
<< /*: Lang. code column of language list. */ tr("Code")
|
||||||
<< tr("Translation progress") << tr("Author"));
|
<< tr("Translation progress"));
|
||||||
|
|
||||||
m_ui->m_lblHelp->setText(tr(R"(Help us to improve %1 <a href="%2">translations</a>.)")
|
m_ui->m_lblHelp->setText(tr(R"(Help us to improve %1 <a href="%2">translations</a>.)")
|
||||||
.arg(QSL(APP_NAME), QSL("https://crowdin.com/project/rssguard")));
|
.arg(QSL(APP_NAME), QSL("https://crowdin.com/project/rssguard")));
|
||||||
@ -32,7 +33,6 @@ SettingsLocalization::SettingsLocalization(Settings* settings, QWidget* parent)
|
|||||||
m_ui->m_treeLanguages->header()->setSectionResizeMode(0, QHeaderView::ResizeMode::ResizeToContents);
|
m_ui->m_treeLanguages->header()->setSectionResizeMode(0, QHeaderView::ResizeMode::ResizeToContents);
|
||||||
m_ui->m_treeLanguages->header()->setSectionResizeMode(1, QHeaderView::ResizeMode::ResizeToContents);
|
m_ui->m_treeLanguages->header()->setSectionResizeMode(1, QHeaderView::ResizeMode::ResizeToContents);
|
||||||
m_ui->m_treeLanguages->header()->setSectionResizeMode(2, QHeaderView::ResizeMode::ResizeToContents);
|
m_ui->m_treeLanguages->header()->setSectionResizeMode(2, QHeaderView::ResizeMode::ResizeToContents);
|
||||||
m_ui->m_treeLanguages->header()->setSectionResizeMode(3, QHeaderView::ResizeMode::ResizeToContents);
|
|
||||||
|
|
||||||
connect(m_ui->m_treeLanguages, &QTreeWidget::currentItemChanged, this, &SettingsLocalization::requireRestart);
|
connect(m_ui->m_treeLanguages, &QTreeWidget::currentItemChanged, this, &SettingsLocalization::requireRestart);
|
||||||
connect(m_ui->m_treeLanguages, &QTreeWidget::currentItemChanged, this, &SettingsLocalization::dirtifySettings);
|
connect(m_ui->m_treeLanguages, &QTreeWidget::currentItemChanged, this, &SettingsLocalization::dirtifySettings);
|
||||||
@ -48,20 +48,46 @@ void SettingsLocalization::loadSettings() {
|
|||||||
auto langs = qApp->localization()->installedLanguages();
|
auto langs = qApp->localization()->installedLanguages();
|
||||||
|
|
||||||
// Also, load statistics with restricted access token.
|
// Also, load statistics with restricted access token.
|
||||||
QByteArray stats_out;
|
QList<QPair<QByteArray, QByteArray>> hdrs = {
|
||||||
|
{"Authorization",
|
||||||
|
"Bearer "
|
||||||
|
"0fbcad4c39d21a55f63f8a1b6d07cc56bb1e2eb2047bfaf1ee22425e3edf1c2b217f4d13b3cebba9"}};
|
||||||
|
QByteArray stats_out, people_out;
|
||||||
QMap<QString, int> percentages_langs;
|
QMap<QString, int> percentages_langs;
|
||||||
|
QString all_translators;
|
||||||
|
|
||||||
NetworkResult stats_res = NetworkFactory::
|
NetworkResult stats_res = NetworkFactory::
|
||||||
performNetworkOperation(QSL("https://api.crowdin.com/api/v2/projects/608575/languages/progress"),
|
performNetworkOperation(QSL("https://api.crowdin.com/api/v2/projects/608575/languages/progress?limit=100"),
|
||||||
qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(),
|
qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt(),
|
||||||
{},
|
{},
|
||||||
stats_out,
|
stats_out,
|
||||||
QNetworkAccessManager::Operation::GetOperation,
|
QNetworkAccessManager::Operation::GetOperation,
|
||||||
{{"Authorization",
|
hdrs);
|
||||||
"Bearer "
|
|
||||||
"0fbcad4c39d21a55f63f8a1b6d07cc56bb1e2eb2047bfaf1ee22425e3edf1c2b217f4d13b3cebba9"}});
|
NetworkResult people_res =
|
||||||
|
NetworkFactory::performNetworkOperation(QSL("https://api.crowdin.com/api/v2/projects/608575/members?limit=500"),
|
||||||
|
qApp->settings()
|
||||||
|
->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout))
|
||||||
|
.toInt(),
|
||||||
|
{},
|
||||||
|
people_out,
|
||||||
|
QNetworkAccessManager::Operation::GetOperation,
|
||||||
|
hdrs);
|
||||||
|
|
||||||
if (stats_res.m_networkError == QNetworkReply::NetworkError::NoError) {
|
if (stats_res.m_networkError == QNetworkReply::NetworkError::NoError) {
|
||||||
QJsonDocument stats_doc = QJsonDocument::fromJson(stats_out);
|
QJsonDocument stats_doc = QJsonDocument::fromJson(stats_out);
|
||||||
|
QJsonDocument people_doc = QJsonDocument::fromJson(people_out);
|
||||||
|
QJsonArray people_arr = people_doc.object()["data"].toArray();
|
||||||
|
std::vector<QString> people_desc;
|
||||||
|
|
||||||
|
std::transform(people_arr.begin(), people_arr.end(), std::back_inserter(people_desc), [](const QJsonValue& b) {
|
||||||
|
return b.toObject()["data"].toObject()["username"].toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
all_translators =
|
||||||
|
std::accumulate(std::next(people_desc.begin()), people_desc.end(), people_desc.at(0), [](auto lhs, auto rhs) {
|
||||||
|
return std::move(lhs) + ", " + rhs;
|
||||||
|
});
|
||||||
|
|
||||||
for (const QJsonValue& val_lang : stats_doc.object()["data"].toArray()) {
|
for (const QJsonValue& val_lang : stats_doc.object()["data"].toArray()) {
|
||||||
QString lang_id = val_lang.toObject()["data"].toObject()["languageId"].toString().replace(QSL("-"), QSL("_"));
|
QString lang_id = val_lang.toObject()["data"].toObject()["languageId"].toString().replace(QSL("-"), QSL("_"));
|
||||||
@ -75,6 +101,17 @@ void SettingsLocalization::loadSettings() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (all_translators.isEmpty()) {
|
||||||
|
m_ui->m_lblAuthors->setStatus(WidgetWithStatus::StatusType::Information,
|
||||||
|
tr("Big thanks to all translators!"),
|
||||||
|
tr("Big thanks to all translators!"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_ui->m_lblAuthors->setStatus(WidgetWithStatus::StatusType::Information,
|
||||||
|
tr("Translations provided by: %1").arg(all_translators),
|
||||||
|
tr("Big thanks to all translators!"));
|
||||||
|
}
|
||||||
|
|
||||||
for (const Language& language : qAsConst(langs)) {
|
for (const Language& language : qAsConst(langs)) {
|
||||||
auto* item = new QTreeWidgetItem(m_ui->m_treeLanguages);
|
auto* item = new QTreeWidgetItem(m_ui->m_treeLanguages);
|
||||||
int perc_translated = percentages_langs.value(language.m_code);
|
int perc_translated = percentages_langs.value(language.m_code);
|
||||||
@ -87,7 +124,6 @@ void SettingsLocalization::loadSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
item->setText(2, QSL("%1 %").arg(perc_translated >= 0 ? QString::number(perc_translated) : QSL("-")));
|
item->setText(2, QSL("%1 %").arg(perc_translated >= 0 ? QString::number(perc_translated) : QSL("-")));
|
||||||
item->setText(3, language.m_author);
|
|
||||||
item->setIcon(0, qApp->icons()->miscIcon(QSL(FLAG_ICON_SUBFOLDER) + QDir::separator() + language.m_code));
|
item->setIcon(0, qApp->icons()->miscIcon(QSL(FLAG_ICON_SUBFOLDER) + QDir::separator() + language.m_code));
|
||||||
|
|
||||||
QColor col_translated = QColor::fromHsv(perc_translated, 200, 230);
|
QColor col_translated = QColor::fromHsv(perc_translated, 200, 230);
|
||||||
|
@ -36,11 +36,22 @@
|
|||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="LabelWithStatus" name="m_lblAuthors" native="true"/>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="m_lblHelp"/>
|
<widget class="QLabel" name="m_lblHelp"/>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>LabelWithStatus</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>labelwithstatus.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
@ -30,6 +30,9 @@ SettingsNotifications::SettingsNotifications(Settings* settings, QWidget* parent
|
|||||||
connect(m_ui.m_sbScreen, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::dirtifySettings);
|
connect(m_ui.m_sbScreen, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::dirtifySettings);
|
||||||
connect(m_ui.m_sbScreen, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::requireRestart);
|
connect(m_ui.m_sbScreen, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::requireRestart);
|
||||||
|
|
||||||
|
connect(m_ui.m_sbMargin, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::dirtifySettings);
|
||||||
|
connect(m_ui.m_sbWidth, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::dirtifySettings);
|
||||||
|
|
||||||
connect(m_ui.m_sbScreen, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::showScreenInfo);
|
connect(m_ui.m_sbScreen, QOverload<int>::of(&QSpinBox::valueChanged), this, &SettingsNotifications::showScreenInfo);
|
||||||
|
|
||||||
connect(m_ui.m_cbCustomNotificationsPosition,
|
connect(m_ui.m_cbCustomNotificationsPosition,
|
||||||
@ -65,6 +68,8 @@ void SettingsNotifications::loadSettings() {
|
|||||||
m_ui.m_rbNativeNotifications
|
m_ui.m_rbNativeNotifications
|
||||||
->setChecked(!settings()->value(GROUP(GUI), SETTING(GUI::UseToastNotifications)).toBool());
|
->setChecked(!settings()->value(GROUP(GUI), SETTING(GUI::UseToastNotifications)).toBool());
|
||||||
m_ui.m_sbScreen->setValue(settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsScreen)).toInt());
|
m_ui.m_sbScreen->setValue(settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsScreen)).toInt());
|
||||||
|
m_ui.m_sbWidth->setValue(settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsWidth)).toInt());
|
||||||
|
m_ui.m_sbMargin->setValue(settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsMargin)).toInt());
|
||||||
|
|
||||||
m_ui.m_cbCustomNotificationsPosition
|
m_ui.m_cbCustomNotificationsPosition
|
||||||
->setCurrentIndex(m_ui.m_cbCustomNotificationsPosition
|
->setCurrentIndex(m_ui.m_cbCustomNotificationsPosition
|
||||||
@ -84,12 +89,15 @@ void SettingsNotifications::saveSettings() {
|
|||||||
|
|
||||||
settings()->setValue(GROUP(GUI), GUI::UseToastNotifications, m_ui.m_rbCustomNotifications->isChecked());
|
settings()->setValue(GROUP(GUI), GUI::UseToastNotifications, m_ui.m_rbCustomNotifications->isChecked());
|
||||||
settings()->setValue(GROUP(GUI), GUI::ToastNotificationsScreen, m_ui.m_sbScreen->value());
|
settings()->setValue(GROUP(GUI), GUI::ToastNotificationsScreen, m_ui.m_sbScreen->value());
|
||||||
|
settings()->setValue(GROUP(GUI), GUI::ToastNotificationsWidth, m_ui.m_sbWidth->value());
|
||||||
|
settings()->setValue(GROUP(GUI), GUI::ToastNotificationsMargin, m_ui.m_sbMargin->value());
|
||||||
|
|
||||||
settings()->setValue(GROUP(GUI),
|
settings()->setValue(GROUP(GUI),
|
||||||
GUI::ToastNotificationsPosition,
|
GUI::ToastNotificationsPosition,
|
||||||
m_ui.m_cbCustomNotificationsPosition->currentData()
|
m_ui.m_cbCustomNotificationsPosition->currentData()
|
||||||
.value<ToastNotificationsManager::NotificationPosition>());
|
.value<ToastNotificationsManager::NotificationPosition>());
|
||||||
|
|
||||||
|
// qApp->m_toastNotifications
|
||||||
onEndSaveSettings();
|
onEndSaveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>367</width>
|
<width>407</width>
|
||||||
<height>300</height>
|
<height>357</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QFormLayout" name="formLayout">
|
<layout class="QFormLayout" name="formLayout">
|
||||||
@ -76,27 +76,64 @@
|
|||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="m_cbCustomNotificationsPosition"/>
|
<widget class="QComboBox" name="m_cbCustomNotificationsPosition"/>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="3" column="1">
|
||||||
<widget class="QSpinBox" name="m_sbScreen">
|
<widget class="QSpinBox" name="m_sbScreen">
|
||||||
<property name="value">
|
<property name="value">
|
||||||
<number>99</number>
|
<number>99</number>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="3" column="0">
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Screen</string>
|
<string>Screen</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QLabel" name="m_lblScreenInfo">
|
<widget class="QLabel" name="m_lblScreenInfo">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string/>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QSpinBox" name="m_sbWidth">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> px</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>50</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>1000</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Width</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QSpinBox" name="m_sbMargin">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> px</string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Margins</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -149,9 +149,6 @@ Application::Application(const QString& id, int& argc, char** argv, const QStrin
|
|||||||
|
|
||||||
determineFirstRuns();
|
determineFirstRuns();
|
||||||
|
|
||||||
//: Name of translator - optional.
|
|
||||||
QObject::tr("LANG_AUTHOR");
|
|
||||||
|
|
||||||
// Add an extra path for non-system icon themes and set current icon theme
|
// Add an extra path for non-system icon themes and set current icon theme
|
||||||
// and skin.
|
// and skin.
|
||||||
m_icons->setupSearchPaths();
|
m_icons->setupSearchPaths();
|
||||||
|
@ -27,7 +27,7 @@ void Localization::loadActiveLanguage() {
|
|||||||
<< QUOTE_W_SPACE_DOT(desired_localization);
|
<< QUOTE_W_SPACE_DOT(desired_localization);
|
||||||
|
|
||||||
if (app_translator->load(QLocale(desired_localization), QSL("rssguard"), QSL("_"), APP_LANG_PATH)) {
|
if (app_translator->load(QLocale(desired_localization), QSL("rssguard"), QSL("_"), APP_LANG_PATH)) {
|
||||||
const QString real_loaded_locale = app_translator->translate("QObject", "LANG_ABBREV");
|
const QString real_loaded_locale = app_translator->language();
|
||||||
|
|
||||||
QCoreApplication::installTranslator(app_translator);
|
QCoreApplication::installTranslator(app_translator);
|
||||||
|
|
||||||
@ -76,8 +76,7 @@ QList<Language> Localization::installedLanguages() const {
|
|||||||
if (translator.load(file.absoluteFilePath())) {
|
if (translator.load(file.absoluteFilePath())) {
|
||||||
Language new_language;
|
Language new_language;
|
||||||
|
|
||||||
new_language.m_code = translator.language().replace(QSL("-"), QSL("_"));
|
new_language.m_code = translator.language();
|
||||||
new_language.m_author = translator.translate("QObject", "LANG_AUTHOR");
|
|
||||||
new_language.m_name = QLocale(new_language.m_code).nativeLanguageName();
|
new_language.m_name = QLocale(new_language.m_code).nativeLanguageName();
|
||||||
languages << new_language;
|
languages << new_language;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
struct Language {
|
struct Language {
|
||||||
QString m_name;
|
QString m_name;
|
||||||
QString m_code;
|
QString m_code;
|
||||||
QString m_author;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RSSGUARD_DLLSPEC Localization : public QObject {
|
class RSSGUARD_DLLSPEC Localization : public QObject {
|
||||||
|
@ -295,6 +295,12 @@ GUI::ToastNotificationsPositionDef = ToastNotificationsManager::NotificationPosi
|
|||||||
DKEY GUI::ToastNotificationsScreen = "toast_notifications_screen";
|
DKEY GUI::ToastNotificationsScreen = "toast_notifications_screen";
|
||||||
DVALUE(int) GUI::ToastNotificationsScreenDef = -1;
|
DVALUE(int) GUI::ToastNotificationsScreenDef = -1;
|
||||||
|
|
||||||
|
DKEY GUI::ToastNotificationsMargin = "toast_notifications_margin";
|
||||||
|
DVALUE(int) GUI::ToastNotificationsMarginDef = NOTIFICATIONS_MARGIN;
|
||||||
|
|
||||||
|
DKEY GUI::ToastNotificationsWidth = "toast_notifications_width";
|
||||||
|
DVALUE(int) GUI::ToastNotificationsWidthDef = NOTIFICATIONS_WIDTH;
|
||||||
|
|
||||||
DKEY GUI::HideMainWindowWhenMinimized = "hide_when_minimized";
|
DKEY GUI::HideMainWindowWhenMinimized = "hide_when_minimized";
|
||||||
DVALUE(bool) GUI::HideMainWindowWhenMinimizedDef = false;
|
DVALUE(bool) GUI::HideMainWindowWhenMinimizedDef = false;
|
||||||
|
|
||||||
|
@ -228,6 +228,12 @@ namespace GUI {
|
|||||||
KEY ToastNotificationsScreen;
|
KEY ToastNotificationsScreen;
|
||||||
VALUE(int) ToastNotificationsScreenDef;
|
VALUE(int) ToastNotificationsScreenDef;
|
||||||
|
|
||||||
|
KEY ToastNotificationsMargin;
|
||||||
|
VALUE(int) ToastNotificationsMarginDef;
|
||||||
|
|
||||||
|
KEY ToastNotificationsWidth;
|
||||||
|
VALUE(int) ToastNotificationsWidthDef;
|
||||||
|
|
||||||
KEY MessageViewState;
|
KEY MessageViewState;
|
||||||
VALUE(QString) MessageViewStateDef;
|
VALUE(QString) MessageViewStateDef;
|
||||||
|
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
#define GREADER_DEFAULT_BATCH_SIZE 100
|
#define GREADER_DEFAULT_BATCH_SIZE 100
|
||||||
|
|
||||||
// URLs.
|
// URLs.
|
||||||
#define GREADER_URL_REEDAH "https://www.reedah.com"
|
#define GREADER_URL_REEDAH "https://www.reedah.com"
|
||||||
#define GREADER_URL_TOR "https://theoldreader.com"
|
#define GREADER_URL_TOR "https://theoldreader.com"
|
||||||
#define GREADER_URL_BAZQUX "https://bazqux.com"
|
#define GREADER_URL_BAZQUX "https://bazqux.com"
|
||||||
#define GREADER_URL_INOREADER "https://www.inoreader.com"
|
#define GREADER_URL_INOREADER "https://www.inoreader.com"
|
||||||
|
|
||||||
// States.
|
// States.
|
||||||
@ -14,29 +14,31 @@
|
|||||||
|
|
||||||
// Means "read" message. If both "reading-list" and "read" are specified, message is READ. If this state
|
// Means "read" message. If both "reading-list" and "read" are specified, message is READ. If this state
|
||||||
// is not present, message is UNREAD.
|
// is not present, message is UNREAD.
|
||||||
#define GREADER_API_STATE_READ "state/com.google/read"
|
#define GREADER_API_STATE_READ "state/com.google/read"
|
||||||
#define GREADER_API_STATE_IMPORTANT "state/com.google/starred"
|
#define GREADER_API_STATE_IMPORTANT "state/com.google/starred"
|
||||||
|
|
||||||
#define GREADER_API_FULL_STATE_READING_LIST "user/-/state/com.google/reading-list"
|
#define GREADER_API_FULL_STATE_READING_LIST "user/-/state/com.google/reading-list"
|
||||||
#define GREADER_API_FULL_STATE_READ "user/-/state/com.google/read"
|
#define GREADER_API_FULL_STATE_READ "user/-/state/com.google/read"
|
||||||
#define GREADER_API_FULL_STATE_IMPORTANT "user/-/state/com.google/starred"
|
#define GREADER_API_FULL_STATE_IMPORTANT "user/-/state/com.google/starred"
|
||||||
|
|
||||||
// API.
|
// API.
|
||||||
#define GREADER_API_CLIENT_LOGIN "accounts/ClientLogin"
|
#define GREADER_API_CLIENT_LOGIN "accounts/ClientLogin"
|
||||||
#define GREADER_API_TAG_LIST "reader/api/0/tag/list?output=json"
|
#define GREADER_API_TAG_LIST "reader/api/0/tag/list?output=json"
|
||||||
#define GREADER_API_SUBSCRIPTION_LIST "reader/api/0/subscription/list?output=json"
|
#define GREADER_API_SUBSCRIPTION_LIST "reader/api/0/subscription/list?output=json"
|
||||||
#define GREADER_API_STREAM_CONTENTS "reader/api/0/stream/contents/%1?output=json&n=%2"
|
#define GREADER_API_STREAM_CONTENTS "reader/api/0/stream/contents/%1?output=json&n=%2"
|
||||||
#define GREADER_API_EDIT_TAG "reader/api/0/edit-tag"
|
#define GREADER_API_EDIT_TAG "reader/api/0/edit-tag"
|
||||||
#define GREADER_API_ITEM_IDS "reader/api/0/stream/items/ids?output=json&n=%2&s=%1"
|
#define GREADER_API_SUBSCRIPTION_EXPORT "reader/api/0/subscription/export"
|
||||||
#define GREADER_API_ITEM_CONTENTS "reader/api/0/stream/items/contents?output=json&n=200000"
|
#define GREADER_API_SUBSCRIPTION_IMPORT "reader/api/0/subscription/import"
|
||||||
#define GREADER_API_TOKEN "reader/api/0/token"
|
#define GREADER_API_ITEM_IDS "reader/api/0/stream/items/ids?output=json&n=%2&s=%1"
|
||||||
#define GREADER_API_USER_INFO "reader/api/0/user-info?output=json"
|
#define GREADER_API_ITEM_CONTENTS "reader/api/0/stream/items/contents?output=json&n=200000"
|
||||||
|
#define GREADER_API_TOKEN "reader/api/0/token"
|
||||||
|
#define GREADER_API_USER_INFO "reader/api/0/user-info?output=json"
|
||||||
|
|
||||||
// Misc.
|
// Misc.
|
||||||
#define GREADET_API_ITEM_IDS_MAX 200000
|
#define GREADER_API_ITEM_IDS_MAX 200000
|
||||||
#define GREADER_API_EDIT_TAG_BATCH 200
|
#define GREADER_API_EDIT_TAG_BATCH 200
|
||||||
#define GREADER_API_ITEM_CONTENTS_BATCH 999
|
#define GREADER_API_ITEM_CONTENTS_BATCH 999
|
||||||
#define GREADER_GLOBAL_UPDATE_THRES 0.3
|
#define GREADER_GLOBAL_UPDATE_THRES 0.3
|
||||||
|
|
||||||
// The Old Reader.
|
// The Old Reader.
|
||||||
#define TOR_SPONSORED_STREAM_ID "tor/sponsored"
|
#define TOR_SPONSORED_STREAM_ID "tor/sponsored"
|
||||||
@ -45,14 +47,14 @@
|
|||||||
// Inoreader.
|
// Inoreader.
|
||||||
#define INO_ITEM_CONTENTS_BATCH 250
|
#define INO_ITEM_CONTENTS_BATCH 250
|
||||||
|
|
||||||
#define INO_HEADER_APPID "AppId"
|
#define INO_HEADER_APPID "AppId"
|
||||||
#define INO_HEADER_APPKEY "AppKey"
|
#define INO_HEADER_APPKEY "AppKey"
|
||||||
|
|
||||||
#define INO_OAUTH_REDIRECT_URI_PORT 14488
|
#define INO_OAUTH_REDIRECT_URI_PORT 14488
|
||||||
#define INO_OAUTH_SCOPE "read write"
|
#define INO_OAUTH_SCOPE "read write"
|
||||||
#define INO_OAUTH_TOKEN_URL "https://www.inoreader.com/oauth2/token"
|
#define INO_OAUTH_TOKEN_URL "https://www.inoreader.com/oauth2/token"
|
||||||
#define INO_OAUTH_AUTH_URL "https://www.inoreader.com/oauth2/auth"
|
#define INO_OAUTH_AUTH_URL "https://www.inoreader.com/oauth2/auth"
|
||||||
#define INO_REG_API_URL "https://www.inoreader.com/developers/register-app"
|
#define INO_REG_API_URL "https://www.inoreader.com/developers/register-app"
|
||||||
|
|
||||||
// FreshRSS.
|
// FreshRSS.
|
||||||
#define FRESHRSS_BASE_URL_PATH "api/greader.php/"
|
#define FRESHRSS_BASE_URL_PATH "api/greader.php/"
|
||||||
|
@ -341,6 +341,61 @@ QNetworkReply::NetworkError GreaderNetwork::markMessagesStarred(RootItem::Import
|
|||||||
proxy);
|
proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GreaderNetwork::subscriptionImport(const QByteArray& opml_data, const QNetworkProxy& proxy) {
|
||||||
|
if (!ensureLogin(proxy)) {
|
||||||
|
throw ApplicationException(tr("login failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString full_url = generateFullUrl(Operations::SubscriptionImport);
|
||||||
|
auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||||
|
|
||||||
|
QByteArray output;
|
||||||
|
auto result = NetworkFactory::performNetworkOperation(full_url,
|
||||||
|
timeout,
|
||||||
|
opml_data,
|
||||||
|
output,
|
||||||
|
QNetworkAccessManager::Operation::PostOperation,
|
||||||
|
{authHeader()},
|
||||||
|
false,
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
proxy);
|
||||||
|
|
||||||
|
if (result.m_networkError != QNetworkReply::NetworkError::NoError) {
|
||||||
|
qCriticalNN << LOGSEC_GREADER << "Cannot get OPML data, network error:" << QUOTE_W_SPACE_DOT(result.m_networkError);
|
||||||
|
throw NetworkException(result.m_networkError, output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray GreaderNetwork::subscriptionExport(const QNetworkProxy& proxy) {
|
||||||
|
if (!ensureLogin(proxy)) {
|
||||||
|
throw ApplicationException(tr("login failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString full_url = generateFullUrl(Operations::SubscriptionExport);
|
||||||
|
auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||||
|
|
||||||
|
QByteArray output;
|
||||||
|
auto result = NetworkFactory::performNetworkOperation(full_url,
|
||||||
|
timeout,
|
||||||
|
{},
|
||||||
|
output,
|
||||||
|
QNetworkAccessManager::Operation::GetOperation,
|
||||||
|
{authHeader()},
|
||||||
|
false,
|
||||||
|
{},
|
||||||
|
{},
|
||||||
|
proxy);
|
||||||
|
|
||||||
|
if (result.m_networkError != QNetworkReply::NetworkError::NoError) {
|
||||||
|
qCriticalNN << LOGSEC_GREADER << "Cannot get OPML data, network error:" << QUOTE_W_SPACE_DOT(result.m_networkError);
|
||||||
|
throw NetworkException(result.m_networkError, output);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QStringList GreaderNetwork::itemIds(const QString& stream_id,
|
QStringList GreaderNetwork::itemIds(const QString& stream_id,
|
||||||
bool unread_only,
|
bool unread_only,
|
||||||
const QNetworkProxy& proxy,
|
const QNetworkProxy& proxy,
|
||||||
@ -357,7 +412,7 @@ QStringList GreaderNetwork::itemIds(const QString& stream_id,
|
|||||||
QString full_url =
|
QString full_url =
|
||||||
generateFullUrl(Operations::ItemIds)
|
generateFullUrl(Operations::ItemIds)
|
||||||
.arg(m_service == GreaderServiceRoot::Service::TheOldReader ? stream_id : QUrl::toPercentEncoding(stream_id),
|
.arg(m_service == GreaderServiceRoot::Service::TheOldReader ? stream_id : QUrl::toPercentEncoding(stream_id),
|
||||||
QString::number(max_count <= 0 ? GREADET_API_ITEM_IDS_MAX : max_count));
|
QString::number(max_count <= 0 ? GREADER_API_ITEM_IDS_MAX : max_count));
|
||||||
auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
auto timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||||
|
|
||||||
if (unread_only) {
|
if (unread_only) {
|
||||||
@ -1066,6 +1121,12 @@ QString GreaderNetwork::generateFullUrl(GreaderNetwork::Operations operation) co
|
|||||||
case Operations::ClientLogin:
|
case Operations::ClientLogin:
|
||||||
return sanitizedBaseUrl() + QSL(GREADER_API_CLIENT_LOGIN);
|
return sanitizedBaseUrl() + QSL(GREADER_API_CLIENT_LOGIN);
|
||||||
|
|
||||||
|
case Operations::SubscriptionExport:
|
||||||
|
return sanitizedBaseUrl() + QSL(GREADER_API_SUBSCRIPTION_EXPORT);
|
||||||
|
|
||||||
|
case Operations::SubscriptionImport:
|
||||||
|
return sanitizedBaseUrl() + QSL(GREADER_API_SUBSCRIPTION_IMPORT);
|
||||||
|
|
||||||
case Operations::Token:
|
case Operations::Token:
|
||||||
return sanitizedBaseUrl() + QSL(GREADER_API_TOKEN);
|
return sanitizedBaseUrl() + QSL(GREADER_API_TOKEN);
|
||||||
|
|
||||||
|
@ -24,7 +24,9 @@ class GreaderNetwork : public QObject {
|
|||||||
Token,
|
Token,
|
||||||
UserInfo,
|
UserInfo,
|
||||||
ItemIds,
|
ItemIds,
|
||||||
ItemContents
|
ItemContents,
|
||||||
|
SubscriptionExport,
|
||||||
|
SubscriptionImport
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit GreaderNetwork(QObject* parent = nullptr);
|
explicit GreaderNetwork(QObject* parent = nullptr);
|
||||||
@ -82,6 +84,8 @@ class GreaderNetwork : public QObject {
|
|||||||
void setOauth(OAuth2Service* oauth);
|
void setOauth(OAuth2Service* oauth);
|
||||||
|
|
||||||
// API methods.
|
// API methods.
|
||||||
|
void subscriptionImport(const QByteArray& opml_data, const QNetworkProxy& proxy);
|
||||||
|
QByteArray subscriptionExport(const QNetworkProxy& proxy);
|
||||||
QNetworkReply::NetworkError editLabels(const QString& state,
|
QNetworkReply::NetworkError editLabels(const QString& state,
|
||||||
bool assign,
|
bool assign,
|
||||||
const QStringList& msg_custom_ids,
|
const QStringList& msg_custom_ids,
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "database/databasequeries.h"
|
#include "database/databasequeries.h"
|
||||||
#include "definitions/definitions.h"
|
#include "definitions/definitions.h"
|
||||||
|
#include "gui/messagebox.h"
|
||||||
#include "miscellaneous/application.h"
|
#include "miscellaneous/application.h"
|
||||||
#include "miscellaneous/iconfactory.h"
|
#include "miscellaneous/iconfactory.h"
|
||||||
#include "miscellaneous/textfactory.h"
|
#include "miscellaneous/textfactory.h"
|
||||||
@ -13,6 +14,8 @@
|
|||||||
#include "services/greader/greadernetwork.h"
|
#include "services/greader/greadernetwork.h"
|
||||||
#include "services/greader/gui/formeditgreaderaccount.h"
|
#include "services/greader/gui/formeditgreaderaccount.h"
|
||||||
|
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
GreaderServiceRoot::GreaderServiceRoot(RootItem* parent) : ServiceRoot(parent), m_network(new GreaderNetwork(this)) {
|
GreaderServiceRoot::GreaderServiceRoot(RootItem* parent) : ServiceRoot(parent), m_network(new GreaderNetwork(this)) {
|
||||||
setIcon(GreaderEntryPoint().icon());
|
setIcon(GreaderEntryPoint().icon());
|
||||||
m_network->setRoot(this);
|
m_network->setRoot(this);
|
||||||
@ -130,6 +133,59 @@ QString GreaderServiceRoot::serviceToString(Service service) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GreaderServiceRoot::importFeeds() {
|
||||||
|
const QString filter_opml20 = tr("OPML 2.0 files (*.opml *.xml)");
|
||||||
|
const QString selected_file = QFileDialog::getOpenFileName(qApp->mainFormWidget(),
|
||||||
|
tr("Select file for feeds import"),
|
||||||
|
qApp->homeFolder(),
|
||||||
|
filter_opml20);
|
||||||
|
|
||||||
|
if (!QFile::exists(selected_file)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
m_network->subscriptionImport(IOFactory::readFile(selected_file), networkProxy());
|
||||||
|
MsgBox::show(qApp->mainFormWidget(),
|
||||||
|
QMessageBox::Icon::Information,
|
||||||
|
tr("Done"),
|
||||||
|
tr("Data imported successfully. Reloading feed tree."));
|
||||||
|
|
||||||
|
syncIn();
|
||||||
|
}
|
||||||
|
catch (const ApplicationException& ex) {
|
||||||
|
MsgBox::show(qApp->mainFormWidget(),
|
||||||
|
QMessageBox::Icon::Critical,
|
||||||
|
tr("Cannot import feeds"),
|
||||||
|
tr("Error: %1").arg(ex.message()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GreaderServiceRoot::exportFeeds() {
|
||||||
|
const QString the_file = qApp->homeFolder() + QDir::separator() +
|
||||||
|
QSL("rssguard_feeds_%1.opml").arg(QDate::currentDate().toString(Qt::DateFormat::ISODate));
|
||||||
|
const QString filter_opml20 = tr("OPML 2.0 files (*.opml *.xml)");
|
||||||
|
const QString selected_file =
|
||||||
|
QFileDialog::getSaveFileName(qApp->mainFormWidget(), tr("Select file for feeds export"), the_file, filter_opml20);
|
||||||
|
|
||||||
|
if (selected_file.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
QByteArray data = m_network->subscriptionExport(networkProxy());
|
||||||
|
IOFactory::writeFile(selected_file, data);
|
||||||
|
|
||||||
|
MsgBox::show(qApp->mainFormWidget(), QMessageBox::Icon::Information, tr("Done"), tr("Data exported successfully."));
|
||||||
|
}
|
||||||
|
catch (const ApplicationException& ex) {
|
||||||
|
MsgBox::show(qApp->mainFormWidget(),
|
||||||
|
QMessageBox::Icon::Critical,
|
||||||
|
tr("Cannot export feeds"),
|
||||||
|
tr("Error: %1").arg(ex.message()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QList<Message> GreaderServiceRoot::obtainNewMessages(Feed* feed,
|
QList<Message> GreaderServiceRoot::obtainNewMessages(Feed* feed,
|
||||||
const QHash<ServiceRoot::BagOfMessages, QStringList>&
|
const QHash<ServiceRoot::BagOfMessages, QStringList>&
|
||||||
stated_messages,
|
stated_messages,
|
||||||
@ -178,6 +234,23 @@ QString GreaderServiceRoot::code() const {
|
|||||||
return GreaderEntryPoint().code();
|
return GreaderEntryPoint().code();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<QAction*> GreaderServiceRoot::serviceMenu() {
|
||||||
|
if (m_serviceMenu.isEmpty()) {
|
||||||
|
ServiceRoot::serviceMenu();
|
||||||
|
|
||||||
|
auto* action_export_feeds = new QAction(qApp->icons()->fromTheme(QSL("document-export")), tr("Export feeds"), this);
|
||||||
|
auto* action_import_feeds = new QAction(qApp->icons()->fromTheme(QSL("document-import")), tr("Import feeds"), this);
|
||||||
|
|
||||||
|
connect(action_export_feeds, &QAction::triggered, this, &GreaderServiceRoot::exportFeeds);
|
||||||
|
connect(action_import_feeds, &QAction::triggered, this, &GreaderServiceRoot::importFeeds);
|
||||||
|
|
||||||
|
m_serviceMenu.append(action_export_feeds);
|
||||||
|
m_serviceMenu.append(action_import_feeds);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_serviceMenu;
|
||||||
|
}
|
||||||
|
|
||||||
void GreaderServiceRoot::saveAllCachedData(bool ignore_errors) {
|
void GreaderServiceRoot::saveAllCachedData(bool ignore_errors) {
|
||||||
auto msg_cache = takeMessageCache();
|
auto msg_cache = takeMessageCache();
|
||||||
QMapIterator<RootItem::ReadStatus, QStringList> i(msg_cache.m_cachedStatesRead);
|
QMapIterator<RootItem::ReadStatus, QStringList> i(msg_cache.m_cachedStatesRead);
|
||||||
|
@ -32,6 +32,7 @@ class GreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
|||||||
virtual FormAccountDetails* accountSetupDialog() const;
|
virtual FormAccountDetails* accountSetupDialog() const;
|
||||||
virtual void start(bool freshly_activated);
|
virtual void start(bool freshly_activated);
|
||||||
virtual QString code() const;
|
virtual QString code() const;
|
||||||
|
virtual QList<QAction*> serviceMenu();
|
||||||
virtual void saveAllCachedData(bool ignore_errors);
|
virtual void saveAllCachedData(bool ignore_errors);
|
||||||
virtual LabelOperation supportedLabelOperations() const;
|
virtual LabelOperation supportedLabelOperations() const;
|
||||||
virtual QVariantHash customDatabaseData() const;
|
virtual QVariantHash customDatabaseData() const;
|
||||||
@ -49,6 +50,10 @@ class GreaderServiceRoot : public ServiceRoot, public CacheForServiceRoot {
|
|||||||
|
|
||||||
static QString serviceToString(Service service);
|
static QString serviceToString(Service service);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void importFeeds();
|
||||||
|
void exportFeeds();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual RootItem* obtainNewTreeForSyncIn() const;
|
virtual RootItem* obtainNewTreeForSyncIn() const;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user