From 251ad1e695739b2fc16a2be2bae4830fa4f9428c Mon Sep 17 00:00:00 2001
From: liuxinhao <liuxinhao@kylinsec.com.cn>
Date: Mon, 21 Aug 2023 17:32:45 +0800
Subject: [PATCH 5/7] fix(avatar): Update authentication users and user list
 avatars in real time
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

- 实时更新认证用户以及用户列表头像

Closes #12711
---
 lib/common-widgets/user-avatar.cpp        |  7 ++++
 lib/common-widgets/user-avatar.h          |  2 ++
 lib/login-frame/login-frame.cpp           | 44 ++++++++++++++++++-----
 lib/login-frame/login-frame.h             |  3 +-
 src/lightdm-greeter/widgets/user-list.cpp | 44 +++++++++++++++++++++--
 src/lightdm-greeter/widgets/user-list.h   |  1 +
 6 files changed, 90 insertions(+), 11 deletions(-)

diff --git a/lib/common-widgets/user-avatar.cpp b/lib/common-widgets/user-avatar.cpp
index 8716461..c23a1f4 100644
--- a/lib/common-widgets/user-avatar.cpp
+++ b/lib/common-widgets/user-avatar.cpp
@@ -31,10 +31,16 @@ UserAvatar::UserAvatar(QWidget *parent) : QWidget(parent)
     setDefaultImage();
 }
 
+QString UserAvatar::getCurrentImage()
+{
+    return m_pixmapPath;
+}
+
 void UserAvatar::setImage(const QString &path)
 {
     if (m_pixmap.load(path))
     {
+        m_pixmap = path;
         m_scaledPixmap = scalePixmapAdjustSize(m_pixmap);
     }
     else
@@ -95,6 +101,7 @@ void UserAvatar::setDefaultImage()
         KLOG_WARNING() << "user avatar load default avatar failed";
         return;
     }
+    m_pixmapPath = DEFAULT_USER_AVATAR;
     m_scaledPixmap = scalePixmapAdjustSize(m_pixmap);
     update();
 }
diff --git a/lib/common-widgets/user-avatar.h b/lib/common-widgets/user-avatar.h
index 78cf832..3bb825f 100644
--- a/lib/common-widgets/user-avatar.h
+++ b/lib/common-widgets/user-avatar.h
@@ -26,6 +26,7 @@ class UserAvatar : public QWidget
 public:
     explicit UserAvatar(QWidget *parent = nullptr);
 
+    QString getCurrentImage();
     void setImage(const QString &path);
     void setDefaultImage();
 
@@ -37,6 +38,7 @@ private:
     QPixmap scalePixmapAdjustSize(const QPixmap &pixmap);
 
 private:
+    QString m_pixmapPath;
     QPixmap m_scaledPixmap;
     QPixmap m_pixmap;
 };
diff --git a/lib/login-frame/login-frame.cpp b/lib/login-frame/login-frame.cpp
index 8e49d84..1657296 100644
--- a/lib/login-frame/login-frame.cpp
+++ b/lib/login-frame/login-frame.cpp
@@ -26,6 +26,7 @@
 #include <QTime>
 #include <QTimer>
 #include <QToolButton>
+#include <QDBusConnection>
 
 namespace Kiran
 {
@@ -184,9 +185,18 @@ void LoginFrame::initUI()
             respond(text);
         }
     });
-    connect(ui->btn_reAuth, &QPushButton::clicked, [this]{ 
+    connect(ui->btn_reAuth, &QPushButton::clicked, [this]{
         startAuthUser(m_specifyUser);
     });
+
+    // 连接至AccountServce, 处理用户属性变更信号,用于更新正在登录用户头像
+    auto connected = QDBusConnection::systemBus().connect("", "", "org.freedesktop.Accounts.User",
+                                                          "Changed", this,
+                                                          SLOT(onAuthUserPropertyChanged()));
+    if (!connected)
+    {
+        KLOG_WARNING() << "login frame: can not connect to user property changed!";
+    }
     // clang-format on
 
     QBoxLayout* centerBottomLayout = qobject_cast<QBoxLayout*>(ui->center_bottom->layout());
@@ -280,15 +290,15 @@ void LoginFrame::onAuthComplete(bool authRes)
     KLOG_DEBUG() << "auth complete" << authRes;
     authenticateComplete(authRes, m_authController->authenticationUser());
 
-    if( !authRes )
+    if (!authRes)
     {
-        #if 0
+#if 0
         if (m_prompted)
         {
             startAuthUser(m_authController->authenticationUser());
         }
         else
-        #endif
+#endif
         {
             // 未存在prompt消息,应切换至显示重新认真按钮,点击重新认证按钮再开始认证
             switchControlPage(CONTROL_PAGE_REAUTH);
@@ -306,6 +316,25 @@ void LoginFrame::onSupportedAuthTypeChanged(QList<KADAuthType> supportedTypes)
     m_switcher->setAuthTypes(supportedTypes);
 }
 
+//  检查当前认证的用户头像变更
+void LoginFrame::onAuthUserPropertyChanged()
+{
+    if (m_specifyUser.isEmpty())
+    {
+        return;
+    }
+
+    QString imagePath = UserManager::getUserIcon(m_specifyUser);
+    QString currentImagePath = ui->avatar->getCurrentImage();
+    if (imagePath == currentImagePath)
+    {
+        return;
+    }
+
+    ui->avatar->setImage(imagePath);
+    return;
+}
+
 void LoginFrame::onAuthTypeChanged(KADAuthType type)
 {
     if (m_switcher->getCurrentAuthType() != type)
@@ -315,13 +344,12 @@ void LoginFrame::onAuthTypeChanged(KADAuthType type)
 
     ui->tips->clear();
 
-    static QSet<KADAuthType> emptyControlAuthType= {
+    static QSet<KADAuthType> emptyControlAuthType = {
         KAD_AUTH_TYPE_FINGERPRINT,
         KAD_AUTH_TYPE_FINGERVEIN,
         KAD_AUTH_TYPE_IRIS,
-        KAD_AUTH_TYPE_FACE
-    };
-    if ( emptyControlAuthType.contains(type) )
+        KAD_AUTH_TYPE_FACE};
+    if (emptyControlAuthType.contains(type))
     {
         switchControlPage(CONTROL_PAGE_EMPTY);
     }
diff --git a/lib/login-frame/login-frame.h b/lib/login-frame/login-frame.h
index f3c55ee..01299f6 100644
--- a/lib/login-frame/login-frame.h
+++ b/lib/login-frame/login-frame.h
@@ -87,13 +87,14 @@ private:
     // 认证完成,子类根据认证结果以及用户名执行各自操作
     virtual void authenticateComplete(bool authRes, const QString& userName) = 0;
 
-private:
+private slots:
     void onShowMessage(const QString& text, MessageType type);
     void onShowPrmpt(const QString& text, PromptType type);
     void onAuthComplete(bool authRes);
     void onNotifyAuthMode(KADAuthMode mode);
     void onSupportedAuthTypeChanged(QList<KADAuthType> supportedTypes);
     void onAuthTypeChanged(KADAuthType type);
+    void onAuthUserPropertyChanged();
 
 private:
     Ui::LoginFrame* ui;
diff --git a/src/lightdm-greeter/widgets/user-list.cpp b/src/lightdm-greeter/widgets/user-list.cpp
index c84ed1d..b83efdf 100644
--- a/src/lightdm-greeter/widgets/user-list.cpp
+++ b/src/lightdm-greeter/widgets/user-list.cpp
@@ -42,7 +42,7 @@ UserList::UserList(QWidget *parent)
 
 UserList::~UserList()
 {
-    disconnect(qApp, &QApplication::focusChanged,this,&UserList::onAppFocusChanged);
+    disconnect(qApp, &QApplication::focusChanged, this, &UserList::onAppFocusChanged);
     delete ui;
 }
 
@@ -138,7 +138,7 @@ void UserList::initUI()
     /// 连接QApplication的焦点切换信号
     /// 处理ListWidget内部焦点切换或焦点切换出ListWidge，滑动条特殊处理
     /// 处理当焦点从外部到UserItem时，应默认到当前行
-    connect(qApp, &QApplication::focusChanged,this,&UserList::onAppFocusChanged);
+    connect(qApp, &QApplication::focusChanged, this, &UserList::onAppFocusChanged);
 }
 
 void UserList::loadUserList()
@@ -162,6 +162,7 @@ void UserList::loadUserList()
 
     connect(&m_filterModel, &QLightDM::UsersModel::rowsRemoved, this, &UserList::onModelRowsRemoved);
     connect(&m_filterModel, &QLightDM::UsersModel::rowsInserted, this, &UserList::onModelRowsInserted);
+    connect(&m_filterModel, &QLightDM::UsersModel::dataChanged, this, &UserList::onDataChanged);
 }
 
 bool UserList::getCurrentSelected(UserInfo &userInfo)
@@ -380,6 +381,45 @@ void UserList::onAppFocusChanged(QWidget *oldFocus, QWidget *newFocus)
     }
 }
 
+void UserList::onDataChanged(const QModelIndex &topLeft,
+                             const QModelIndex &bottomRight,
+                             const QVector<int> roles)
+{
+    auto userInfoUpdateFunc = [this](const UserInfo &newInfo) -> void
+    {
+        for (int i = 0; i < ui->userList->count(); i++)
+        {
+            auto item = ui->userList->item(i);
+            auto userItem = dynamic_cast<UserItem *>(ui->userList->itemWidget(item));
+            auto itemUserInfo = userItem->getUserInfo();
+            if (newInfo.name != itemUserInfo.name)
+            {
+                continue;
+            }
+
+            if (itemUserInfo.imagePath != newInfo.imagePath ||
+                itemUserInfo.loggedIn != newInfo.loggedIn)
+            {
+                itemUserInfo.imagePath = newInfo.imagePath;
+                itemUserInfo.loggedIn = newInfo.loggedIn;
+                userItem->setUserInfo(itemUserInfo);
+            }
+            break;
+        }
+    };
+    int startRow = topLeft.row();
+    int endRow = topLeft.row();
+
+    // FIXME: QLightdDM此处信号发出时roles为默认参数, 无法判断数据变化范围
+    // 检查图片更新,用户列表中的顺序可能和用户不一致
+    for (int i = startRow; i <= endRow; i++)
+    {
+        UserInfo userInfo;
+        getUserInfoFromModel(i, userInfo);
+        userInfoUpdateFunc(userInfo);
+    }
+}
+
 QSize UserList::sizeHint() const
 {
     QSize size(0, (ui->userList->count() * 62) + 2);
diff --git a/src/lightdm-greeter/widgets/user-list.h b/src/lightdm-greeter/widgets/user-list.h
index 9e45f61..e58b39c 100644
--- a/src/lightdm-greeter/widgets/user-list.h
+++ b/src/lightdm-greeter/widgets/user-list.h
@@ -62,6 +62,7 @@ private slots:
     void onModelRowsRemoved(const QModelIndex &parent, int first, int last);
     void onModelRowsInserted(const QModelIndex &parent, int first, int last);
     void onAppFocusChanged(QWidget* oldFocus,QWidget* newFocus);
+    void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> roles);
 
 Q_SIGNALS:
     void userActivated(const UserInfo &userInfo);
-- 
2.27.0

