Use dynamic path for account online/offline state icon. Refresh GUI on connection...
authorallexzander <blackslayer4@gmail.com>
Mon, 23 Nov 2020 05:45:26 +0000 (07:45 +0200)
committerallexzander <blackslayer4@gmail.com>
Mon, 23 Nov 2020 15:49:25 +0000 (17:49 +0200)
Signed-off-by: Alex Zolotov <alex.zolotov.nextcloud.com>
Signed-off-by: allexzander <blackslayer4@gmail.com>
src/gui/tray/UserLine.qml
src/gui/tray/UserModel.cpp
src/gui/tray/UserModel.h
src/gui/tray/Window.qml
src/libsync/theme.cpp
src/libsync/theme.h
theme/Style/Style.qml

index 90cf8acf17d11135c9fc93099a1e7f26aca50f5d..654aa079c47c7eeed90d3738f38801f0eee5dd15 100644 (file)
@@ -81,7 +81,9 @@ MenuItem {
                         }\r
                         Image {\r
                             id: accountStateIndicator\r
-                            source: isConnected ? "qrc:///client/theme/colored/state-ok.svg" : "qrc:///client/theme/colored/state-offline.svg"\r
+                            source: model.isConnected\r
+                                    ? Style.stateOnlineImageSource\r
+                                    : Style.stateOfflineImageSource\r
                             cache: false\r
                             x: accountStateIndicatorBackground.x + 1\r
                             y: accountStateIndicatorBackground.y + 1\r
@@ -89,7 +91,7 @@ MenuItem {
                             sourceSize.height: Style.accountAvatarStateIndicatorSize\r
 \r
                             Accessible.role: Accessible.Indicator\r
-                            Accessible.name: isConnected ? qsTr("Account connected") : qsTr("Account not connected")\r
+                            Accessible.name: model.isConnected ? qsTr("Account connected") : qsTr("Account not connected")\r
                         }\r
                     }\r
 \r
@@ -163,11 +165,11 @@ MenuItem {
                     }\r
 \r
                     MenuItem {\r
-                        text: isConnected ? qsTr("Log out") : qsTr("Log in")\r
+                        text: model.isConnected ? qsTr("Log out") : qsTr("Log in")\r
                         font.pixelSize: Style.topLinePixelSize\r
                         hoverEnabled: true\r
                         onClicked: {\r
-                            isConnected ? UserModel.logout(index) : UserModel.login(index)\r
+                            model.isConnected ? UserModel.logout(index) : UserModel.login(index)\r
                             accountMenu.close()\r
                         }\r
 \r
@@ -182,10 +184,10 @@ MenuItem {
                         }\r
 \r
                         Accessible.role: Accessible.Button\r
-                        Accessible.name: isConnected ? qsTr("Log out") : qsTr("Log in")\r
+                        Accessible.name: model.isConnected ? qsTr("Log out") : qsTr("Log in")\r
 \r
                         onPressed: {\r
-                            if (isConnected) {\r
+                            if (model.isConnected) {\r
                                 UserModel.logout(index)\r
                             } else {\r
                                 UserModel.login(index)\r
@@ -221,4 +223,13 @@ MenuItem {
                 }\r
             }\r
         }\r
+\r
+        Connections {\r
+            target: UserModel\r
+            onRefreshCurrentUserGui: {\r
+                accountStateIndicator.source = model.isConnected\r
+                        ? Style.stateOnlineImageSource\r
+                        : Style.stateOfflineImageSource\r
+            }\r
+        }\r
 }   // MenuItem userLine\r
index 5f59e807463eabb9ff78fadcc12cd9dffc049662..9df3dd111c41b6d8cfc4579a9ce5d5daa3be9026 100644 (file)
@@ -41,6 +41,7 @@ User::User(AccountStatePtr &account, const bool &isCurrent, QObject *parent)
 
     connect(_account.data(), &AccountState::stateChanged,
             [=]() { if (isConnected()) {slotRefresh();} });
+    connect(_account.data(), &AccountState::stateChanged, this, &User::accountStateChanged);
     connect(_account.data(), &AccountState::hasFetchedNavigationApps,
         this, &User::slotRebuildNavigationAppList);
     connect(_account->account().data(), &Account::accountChangedDisplayName, this, &User::nameChanged);
@@ -552,6 +553,7 @@ void UserModel::buildUserList()
     }
     if (_init) {
         _users.first()->setCurrentUser(true);
+        connect(_users.first(), &User::accountStateChanged, this, &UserModel::refreshCurrentUserGui);
         _init = false;
     }
 }
@@ -613,6 +615,7 @@ void UserModel::addUser(AccountStatePtr &user, const bool &isCurrent)
         _users << u;
         if (isCurrent) {
             _currentUserId = _users.indexOf(_users.last());
+            connect(u, &User::accountStateChanged, this, &UserModel::refreshCurrentUserGui);
         }
 
         endInsertRows();
@@ -665,8 +668,10 @@ Q_INVOKABLE void UserModel::switchCurrentUser(const int &id)
     if (_users.isEmpty())
         return;
 
+    disconnect(_users[_currentUserId], &User::accountStateChanged, this, &UserModel::refreshCurrentUserGui);
     _users[_currentUserId]->setCurrentUser(false);
     _users[id]->setCurrentUser(true);
+    connect(_users[id], &User::accountStateChanged, this, &UserModel::refreshCurrentUserGui);
     _currentUserId = id;
     emit refreshCurrentUserGui();
     emit newUserSelected();
@@ -710,6 +715,10 @@ Q_INVOKABLE void UserModel::removeAccount(const int &id)
         return;
     }
 
+    if (_users[id]->isCurrentUser()) {
+        disconnect(_users[id], &User::accountStateChanged, this, &UserModel::refreshCurrentUserGui);
+    }
+
     if (_users[id]->isCurrentUser() && _users.count() > 1) {
         id == 0 ? switchCurrentUser(1) : switchCurrentUser(0);
     }
index 7c7d110967440732340c743e5c1b6dc25f5f649e..106ee5692e2c08de98ca81ff11a73a6149ecc053 100644 (file)
@@ -52,6 +52,7 @@ signals:
     void hasLocalFolderChanged();
     void serverHasTalkChanged();
     void avatarChanged();
+    void accountStateChanged(int state);
 
 public slots:
     void slotItemCompleted(const QString &folder, const SyncFileItemPtr &item);
index bb6be3ecb46d8c872a584c37c3f8242596d4ce7c..a007a9cb30c908376cb40a0f320952af794613ba 100644 (file)
@@ -36,7 +36,9 @@ Window {
 \r
     onVisibleChanged: {\r
         currentAccountStateIndicator.source = ""\r
-        currentAccountStateIndicator.source = UserModel.isUserConnected(UserModel.currentUserId) ? "qrc:///client/theme/colored/state-ok.svg" : "qrc:///client/theme/colored/state-offline.svg"\r
+        currentAccountStateIndicator.source = UserModel.isUserConnected(UserModel.currentUserId)\r
+                ? Style.stateOnlineImageSource\r
+                : Style.stateOfflineImageSource\r
 \r
         // HACK: reload account Instantiator immediately by restting it - could be done better I guess\r
         // see also id:accountMenu below\r
@@ -48,7 +50,9 @@ Window {
         target: UserModel\r
         onRefreshCurrentUserGui: {\r
             currentAccountStateIndicator.source = ""\r
-            currentAccountStateIndicator.source = UserModel.isUserConnected(UserModel.currentUserId) ? "qrc:///client/theme/colored/state-ok.svg" : "qrc:///client/theme/colored/state-offline.svg"\r
+            currentAccountStateIndicator.source = UserModel.isUserConnected(UserModel.currentUserId)\r
+                    ? Style.stateOnlineImageSource\r
+                    : Style.stateOfflineImageSource\r
         }\r
         onNewUserSelected: {\r
             accountMenu.close();\r
@@ -357,7 +361,9 @@ Window {
 \r
                             Image {\r
                                 id: currentAccountStateIndicator\r
-                                source: UserModel.isUserConnected(UserModel.currentUserId) ? "qrc:///client/theme/colored/state-ok.svg" : "qrc:///client/theme/colored/state-offline.svg"\r
+                                source: UserModel.isUserConnected(UserModel.currentUserId)\r
+                                        ? Style.stateOnlineImageSource\r
+                                        : Style.stateOfflineImageSource\r
                                 cache: false\r
                                 x: currentAccountStateIndicatorBackground.x + 1\r
                                 y: currentAccountStateIndicatorBackground.y + 1\r
index f792c493d731e2ec6837d18a76cf6e5ba5de8213..3941c9fce5445a641793fc2b00ed2137b8e63247 100644 (file)
 #undef Mirall
 #endif
 
+namespace {
+
+QUrl imagePathToUrl(const QString &imagePath)
+{
+    if (imagePath.startsWith(':')) {
+        auto url = QUrl();
+        url.setScheme(QStringLiteral("qrc"));
+        url.setPath(imagePath.mid(1));
+        return url;
+    } else {
+        return QUrl::fromLocalFile(imagePath);
+    }
+}
+
+}
+
 namespace OCC {
 
 Theme *Theme::_instance = nullptr;
@@ -106,6 +122,16 @@ QString Theme::appName() const
     return APPLICATION_SHORTNAME;
 }
 
+QUrl Theme::stateOnlineImageSource() const
+{
+    return imagePathToUrl(themeImagePath("state-ok"));
+}
+
+QUrl Theme::stateOfflineImageSource() const
+{
+    return imagePathToUrl(themeImagePath("state-offline", 16));
+}
+
 QString Theme::version() const
 {
     return MIRALL_VERSION_STRING;
@@ -188,6 +214,25 @@ QIcon Theme::themeIcon(const QString &name, bool sysTray) const
     return cached;
 }
 
+QString Theme::themeImagePath(const QString &name, int size, bool sysTray) const
+{
+    const auto flavor = (!isBranded() && sysTray) ? systrayIconFlavor(_mono) : QLatin1String("colored");
+
+    // branded client may have several sizes of the same icon
+    const QString filePath = (isBranded() && size > 0)
+            ? QString::fromLatin1(":/client/theme/%1/%2-%3").arg(flavor).arg(name).arg(size)
+            : QString::fromLatin1(":/client/theme/%1/%2").arg(flavor).arg(name);
+
+    const QString brandedImagePath = filePath + ".png";
+
+    // only return branded .png image path if it exists, or fall-back to non-branded .svg otherwise
+    if (isBranded() && QFile::exists(brandedImagePath)) {
+        return brandedImagePath;
+    }
+
+    return filePath + ".svg";
+}
+
 QIcon Theme::uiThemeIcon(const QString &iconName, bool uiHasDarkBg) const
 {
     QString themeResBasePath = ":/client/theme/";
index 12ac80132fd0d620b48f967877d0bb577c58ecfd..cede363b68b3f0c883d49c610b3d56b3827f6a42 100644 (file)
@@ -40,6 +40,8 @@ class OWNCLOUDSYNC_EXPORT Theme : public QObject
     Q_PROPERTY(bool branded READ isBranded CONSTANT)
     Q_PROPERTY(QString appNameGUI READ appNameGUI CONSTANT)
     Q_PROPERTY(QString appName READ appName CONSTANT)
+    Q_PROPERTY(QUrl stateOnlineImageSource READ stateOnlineImageSource CONSTANT)
+    Q_PROPERTY(QUrl stateOfflineImageSource READ stateOfflineImageSource CONSTANT)
 #ifndef TOKEN_AUTH_ONLY
     Q_PROPERTY(QIcon folderDisabledIcon READ folderDisabledIcon CONSTANT)
     Q_PROPERTY(QIcon folderOfflineIcon READ folderOfflineIcon CONSTANT)
@@ -109,6 +111,18 @@ public:
      */
     virtual QString appName() const;
 
+    /**
+     * @brief Returns full path to an online state icon
+     * @return QUrl full path to an icon
+     */
+    QUrl stateOnlineImageSource() const;
+
+    /**
+     * @brief Returns full path to an offline state icon
+     * @return QUrl full path to an icon
+     */
+    QUrl stateOfflineImageSource() const;
+
     /**
      * @brief configFileName
      * @return the name of the config file.
@@ -491,6 +505,14 @@ protected:
 #ifndef TOKEN_AUTH_ONLY
     QIcon themeIcon(const QString &name, bool sysTray = false) const;
 #endif
+    /**
+     * @brief Generates image path in the resources
+     * @param name Name of the image file
+     * @param size Size in the power of two (16, 32, 64, etc.)
+     * @param sysTray Whether the image requested is for Systray or not
+     * @return QString image path in the resources
+     **/
+    QString themeImagePath(const QString &name, int size = -1, bool sysTray = false) const;
     Theme();
 
 signals:
index 7a0679188512cd8e2b95f4aa4c29745070e8bcdf..332d8133dfc614cc09d5a97e3db8b7b1c73b3cb9 100644 (file)
@@ -28,6 +28,9 @@ QtObject {
     property int currentAccountButtonRadius: 2\r
     property int currentAccountLabelWidth: 128\r
 \r
+    property url stateOnlineImageSource: Theme.stateOnlineImageSource\r
+    property url stateOfflineImageSource: Theme.stateOfflineImageSource\r
+\r
     property int accountAvatarSize: (trayWindowHeaderHeight - 16)\r
     property int accountAvatarStateIndicatorSize: 16\r
     property int accountLabelWidth: 128\r