/** * SPDX-FileCopyrightText: 2021 Tobias Fella * SPDX-FileCopyrightText: 2021 Bart De Vries * * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL */ #pragma once #include #include #include #include "error.h" #include "sync/syncutils.h" namespace QKeychain { class WritePasswordJob; class DeletePasswordJob; } class GPodder; class Sync : public QObject { Q_OBJECT QML_ELEMENT QML_SINGLETON Q_PROPERTY(bool syncEnabled READ syncEnabled WRITE setSyncEnabled NOTIFY syncEnabledChanged) Q_PROPERTY(QString username READ username NOTIFY credentialsChanged) Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY credentialsChanged) Q_PROPERTY(QString device READ device WRITE setDevice NOTIFY deviceChanged) Q_PROPERTY(QString deviceName READ deviceName WRITE setDeviceName NOTIFY deviceNameChanged) Q_PROPERTY(QString hostname READ hostname WRITE setHostname NOTIFY hostnameChanged) Q_PROPERTY(SyncUtils::Provider provider READ provider WRITE setProvider NOTIFY providerChanged) Q_PROPERTY(QString suggestedDevice READ suggestedDevice CONSTANT) Q_PROPERTY(QString suggestedDeviceName READ suggestedDeviceName CONSTANT) Q_PROPERTY(QVector deviceList READ deviceList NOTIFY deviceListReceived) Q_PROPERTY(SyncUtils::SyncStatus syncStatus MEMBER m_syncStatus NOTIFY syncProgressChanged) Q_PROPERTY(int syncProgress MEMBER m_syncProgress NOTIFY syncProgressChanged) Q_PROPERTY(int syncProgressTotal MEMBER m_syncProgressTotal CONSTANT) Q_PROPERTY(QString syncProgressText MEMBER m_syncProgressText NOTIFY syncProgressChanged) Q_PROPERTY(QString lastSuccessfulDownloadSync READ lastSuccessfulDownloadSync NOTIFY syncProgressChanged) Q_PROPERTY(QString lastSuccessfulUploadSync READ lastSuccessfulUploadSync NOTIFY syncProgressChanged) public: static Sync &instance() { static Sync _instance; return _instance; } static Sync *create(QQmlEngine *engine, QJSEngine *) { engine->setObjectOwnership(&instance(), QQmlEngine::CppOwnership); return &instance(); } bool syncEnabled() const; QString username() const; QString password() const; QString device() const; QString deviceName() const; QString hostname() const; SyncUtils::Provider provider() const; QString lastSuccessfulSync(const QStringList &matchingLabels = {}) const; QString lastSuccessfulDownloadSync() const; QString lastSuccessfulUploadSync() const; QString suggestedDevice() const; QString suggestedDeviceName() const; QVector deviceList() const; void setSyncEnabled(bool status); void setPassword(const QString &password); void setDevice(const QString &device); void setDeviceName(const QString &deviceName); void setHostname(const QString &hostname); void setProvider(const SyncUtils::Provider provider); Q_INVOKABLE void login(const QString &username, const QString &password); Q_INVOKABLE void retrieveCredentialsFromConfig(); Q_INVOKABLE void logout(); Q_INVOKABLE void registerNewDevice(const QString &id, const QString &caption, const QString &type = QStringLiteral("other")); Q_INVOKABLE void linkUpAllDevices(); void doSync(SyncUtils::SyncStatus status, bool forceFetchAll = false); // base method for syncing Q_INVOKABLE void doRegularSync(bool forceFetchAll = false); // regular sync; can be forced to update all feeds Q_INVOKABLE void doForceSync(); // force a full re-sync with the server; discarding local eposide acions Q_INVOKABLE void doSyncPushAll(); // upload all local episode states to the server; this will likely overwrite all actions stored on the server Q_INVOKABLE void doQuickSync(); // only upload pending local episode actions; intended to be run directly after an episode action has been created // Next are some generic methods to store and apply local changes to be synced void storeAddFeedAction(const QString &url); void storeRemoveFeedAction(const QString &url); void storePlayEpisodeAction(const QString &id, const qulonglong started, const qulonglong position); void storePlayedEpisodeAction(const QString &id); void applySubscriptionChangesLocally(const QStringList &addList, const QStringList &removeList); void applyEpisodeActionsLocally(const QHash> &episodeActionHash); Q_SIGNALS: void syncEnabledChanged(); void credentialsChanged(); void deviceChanged(); void deviceNameChanged(); void hostnameChanged(); void providerChanged(); void deviceCreated(); void passwordSaveFinished(bool success); void passwordRetrievalFinished(QString password); void passwordInputRequired(); void loginSucceeded(); void deviceListReceived(); void error(Error::Type type, const QString &url, const QString &id, const int errorId, const QString &errorString, const QString &title); void syncProgressChanged(); void abortSync(); private: Sync(); void clearSettings(); void savePasswordToKeyChain(const QString &username, const QString &password); void savePasswordToFile(const QString &username, const QString &password); void retrievePasswordFromKeyChain(const QString &username); QString retrievePasswordFromFile(const QString &username); void deletePasswordFromKeychain(const QString &username); void retrieveAllLocalEpisodeStates(); void onWriteDummyJobFinished(QKeychain::WritePasswordJob *writeDummyJob, const QString &username); void onWritePasswordJobFinished(QKeychain::WritePasswordJob *job, const QString &username, const QString &password); void onDeleteJobFinished(QKeychain::DeletePasswordJob *deleteJob, const QString &username); GPodder *m_gpodder = nullptr; bool m_syncEnabled; QString m_username; QString m_password; QString m_device; QString m_deviceName; QString m_hostname; SyncUtils::Provider m_provider; QVector m_deviceList; KFormat m_kformat; // variables needed for linkUpAllDevices() QStringList m_syncUpAllSubscriptions; int m_deviceResponses; // internal variables used while syncing bool m_allowSyncActionLogging = true; // internal variables used for UI notifications SyncUtils::SyncStatus m_syncStatus = SyncUtils::SyncStatus::NoSync; int m_syncProgress = 0; int m_syncProgressTotal = 7; QString m_syncProgressText = QLatin1String(""); };