File indexing completed on 2025-02-09 05:58:34
0001 // SPDX-FileCopyrightText: 2021 kaniini <https://git.pleroma.social/kaniini> 0002 // SPDX-FileCopyrightText: 2021 Carl Schwan <carl@carlschwan.eu> 0003 // SPDX-License-Identifier: GPL-3.0-only 0004 0005 #pragma once 0006 0007 #include "post.h" 0008 0009 #include <KAboutData> 0010 0011 #include <QAbstractListModel> 0012 #include <QJSEngine> 0013 0014 class AbstractAccount; 0015 class QNetworkAccessManager; 0016 0017 /// Handles managing accounts in Tokodon, and tracks state such as which one is currently selected. 0018 class AccountManager : public QAbstractListModel 0019 { 0020 Q_OBJECT 0021 QML_ELEMENT 0022 QML_SINGLETON 0023 0024 Q_PROPERTY(bool isReady READ isReady NOTIFY accountsReady) 0025 Q_PROPERTY(bool hasAccounts READ hasAccounts NOTIFY accountsChanged) 0026 Q_PROPERTY(bool hasAnyAccounts READ hasAnyAccounts NOTIFY accountsChanged) 0027 Q_PROPERTY(AbstractAccount *selectedAccount READ selectedAccount WRITE selectAccount NOTIFY accountSelected) 0028 Q_PROPERTY(QString selectedAccountId READ selectedAccountId NOTIFY accountSelected) 0029 Q_PROPERTY(int selectedIndex READ selectedIndex NOTIFY accountSelected) 0030 Q_PROPERTY(KAboutData aboutData READ aboutData WRITE setAboutData NOTIFY aboutDataChanged) 0031 Q_PROPERTY(bool isFlatpak READ isFlatpak CONSTANT) 0032 Q_PROPERTY(bool selectedAccountHasIssue READ selectedAccountHasIssue NOTIFY accountSelected) 0033 Q_PROPERTY(bool testMode READ testMode CONSTANT) 0034 0035 public: 0036 static AccountManager *create(QQmlEngine *, QJSEngine *) 0037 { 0038 auto inst = &instance(); 0039 QJSEngine::setObjectOwnership(inst, QJSEngine::ObjectOwnership::CppOwnership); 0040 return inst; 0041 } 0042 0043 /// Custom roles for the AccountManager model 0044 enum CustomRoles { 0045 AccountRole = Qt::UserRole + 1, ///< Account object 0046 DisplayNameRole, ///< Display name of the account. Uses the display name if set, otherwise falls back to the username 0047 DescriptionRole, ///< Username of the account 0048 InstanceRole, ///< Instance name of the account 0049 }; 0050 0051 static AccountManager &instance(); 0052 0053 /// Load accounts from disk 0054 void loadFromSettings(); 0055 0056 /// Migrates old Tokodon settings to newer formats 0057 void migrateSettings(); 0058 0059 /// Enables or disables test mode. Used internally for tokodon-offline 0060 /// \param enabled Whether test mode should be enabled 0061 void setTestMode(bool enabled); 0062 0063 /// Returns if testing mode is enabled 0064 bool testMode() const; 0065 0066 /// Whether or not the account manager is completely ready 0067 /// This doesn't mean it has accounts, simply that it's done reading configs and the keychain 0068 bool isReady() const; 0069 0070 /// If there any valid accounts loaded 0071 bool hasAccounts() const; 0072 0073 /// If there are any accounts in the config 0074 bool hasAnyAccounts() const; 0075 0076 /// Adds a new account 0077 /// \param account The account to manage 0078 /// \param skipAuthenticationCheck Whether the account manager should internally check if the account is valid 0079 Q_INVOKABLE void addAccount(AbstractAccount *account, bool skipAuthenticationCheck); 0080 0081 /// Removes an existing account 0082 /// \param account The account to remove 0083 Q_INVOKABLE void removeAccount(AbstractAccount *account); 0084 0085 /// Re-validates every account's credentials 0086 void reloadAccounts(); 0087 void queueNotifications(); 0088 0089 /// Returns if the currently selected account has issues with authentication 0090 Q_INVOKABLE bool selectedAccountHasIssue() const; 0091 0092 /// If the selected account has a login issue, returns a localized string explaining why 0093 Q_INVOKABLE QString selectedAccountLoginIssue() const; 0094 0095 /// Switches to an existing account 0096 /// \param explicitUserAction If true, considers this an explicit user action and the new selected account will be written to disk 0097 void selectAccount(AbstractAccount *account, bool explicitUserAction = true); 0098 0099 /// The currently selected account 0100 AbstractAccount *selectedAccount() const; 0101 0102 /// The currently selected account's id 0103 QString selectedAccountId() const; 0104 0105 /// The index of the selected account in the account list 0106 int selectedIndex() const; 0107 0108 /// Sets the application about data 0109 /// \param aboutData The new about data 0110 void setAboutData(const KAboutData &aboutData); 0111 0112 /// Returns the application's about data 0113 [[nodiscard]] KAboutData aboutData() const; 0114 0115 int rowCount(const QModelIndex &index = QModelIndex()) const override; 0116 0117 QVariant data(const QModelIndex &index, int role) const override; 0118 0119 QHash<int, QByteArray> roleNames() const override; 0120 0121 /// Creates a new account, and adds it to the manager 0122 /// \param instanceUri The URI of the instance 0123 /// \param ignoreSslErrors Whether or ignore SSL errors from this URI 0124 /// \param admin Request admin scopes 0125 Q_INVOKABLE AbstractAccount *createNewAccount(const QString &instanceUri, bool ignoreSslErrors = false, bool admin = true); 0126 0127 /// Returns whether or not Tokodon is built as a Flatpak 0128 bool isFlatpak() const; 0129 0130 /// Returns the preferred settings group name for an account name and an instance uri. 0131 /// It's preferred to use AbstractAccount::settingsGroupName as it fills in the relevant information. 0132 static QString settingsGroupName(const QString &name, const QString &instanceUri); 0133 0134 /// Returns the preferred key name for the client secret given a settings group name. 0135 /// It's preferred to use AbstractAccount::clientSecretKey as it fills in the relevant information. 0136 /// \param name The settings group name, from AbstractAccount::settingsGroupName() 0137 static QString clientSecretKey(const QString &name); 0138 0139 /// Returns the preferred key name for the access token. 0140 /// It's preferred to use AbstractAccount::accessTokenKey as it fills in the relevant information. 0141 /// \param name The settings group name, from AbstractAccount::settingsGroupName() 0142 static QString accessTokenKey(const QString &name); 0143 0144 Q_SIGNALS: 0145 0146 void accountAdded(AbstractAccount *account); 0147 0148 void accountRemoved(AbstractAccount *account); 0149 0150 void accountsChanged(); 0151 0152 void accountsReady(); 0153 0154 void accountsReloaded(); 0155 0156 void accountSelected(AbstractAccount *account); 0157 0158 void identityChanged(AbstractAccount *account); 0159 0160 void fetchedTimeline(AbstractAccount *account, QString original_name, QList<Post *> posts); 0161 0162 void invalidated(AbstractAccount *account); 0163 0164 void fetchedInstanceMetadata(AbstractAccount *account); 0165 0166 void invalidatedPost(AbstractAccount *account, Post *post); 0167 0168 void notification(AbstractAccount *account, std::shared_ptr<Notification> n); 0169 0170 void aboutDataChanged(); 0171 0172 void webapLink(QString id); 0173 0174 void finishedNotificationQueue(); 0175 0176 public Q_SLOTS: 0177 0178 void childIdentityChanged(AbstractAccount *account); 0179 0180 private: 0181 explicit AccountManager(QObject *parent = nullptr); 0182 0183 ~AccountManager() override; 0184 0185 QList<AbstractAccount *> m_accounts; 0186 AbstractAccount *m_selected_account = nullptr; 0187 KAboutData m_aboutData; 0188 QNetworkAccessManager *m_qnam; 0189 0190 enum class AccountStatus { NotLoaded, Loaded, InvalidCredentials }; 0191 0192 QList<AccountStatus> m_accountStatus; 0193 QList<QString> m_accountStatusStrings; 0194 0195 bool m_ready = false; 0196 bool m_hasAnyAccounts = false; 0197 bool m_testMode = false; 0198 0199 void checkIfLoadingFinished(); 0200 };