fix: start notification expire timer only after bubble is displayed - #1691
fix: start notification expire timer only after bubble is displayed#1691Ivy233 wants to merge 1 commit into
Conversation
|
Skipping CI for Draft Pull Request. |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: Ivy233 The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Reviewer's GuideThis PR defers starting the notification expiration timer until a bubble is actually inserted into the UI model, wiring a new bubbleDisplayed signal through BubblePanel to NotificationManager, which now schedules timeouts based on the stored client expire timeout only when notifications are displayed, with thread-safe forwarding from the applet and added unit tests. Sequence diagram for deferred notification timeout start when bubble is displayedsequenceDiagram
participant BubbleModel
participant BubblePanel
participant NotifyServerApplet
participant NotificationManager
BubbleModel->>BubbleModel: insertBubble / replaceBubble
BubbleModel-->>BubblePanel: bubbleDisplayed(id)
BubblePanel->>NotifyServerApplet: notificationDisplayed(id)
NotifyServerApplet->>NotificationManager: notificationDisplayed(id)
NotificationManager->>NotificationManager: fetchEntity(id)
NotificationManager->>NotificationManager: pushPendingEntity(entity, entity.timeout())
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
deepin pr auto review★ 总体评分:95分■ 【总体评价】
■ 【详细分析】
■ 【改进建议代码示例】 // tests/panels/notification/server/notifyserverapplet_test.cpp
// 建议增加对核心逻辑的Mock测试,验证超时启动的拦截条件
TEST_F(NotifyServerAppletTest, NotificationDisplayedLogicTest) {
applet->init();
// 假设已通过依赖注入将 m_persistence 替换为 MockPersistence
MockPersistence *mockPersistence = static_cast<MockPersistence*>(applet->getManager()->persistence());
MockNotificationManager *mockManager = static_cast<MockNotificationManager*>(applet->getManager());
NotifyEntity validEntity;
validEntity.setProcessedType(NotifyEntity::NotProcessed);
validEntity.setTimeout(5000); // 非0且非Critical
validEntity.setHints(QVariantMap());
// 场景1:正常未处理通知,应触发 pushPendingEntity
mockPersistence->setMockEntity(validEntity);
EXPECT_CALL(*mockManager, pushPendingEntity(testing::_, 5000)).Times(1);
applet->notificationDisplayed(validEntity.id());
// 场景2:已处理的通知,不应触发 pushPendingEntity
validEntity.setProcessedType(NotifyEntity::Processed);
mockPersistence->setMockEntity(validEntity);
EXPECT_CALL(*mockManager, pushPendingEntity(testing::_, testing::_)).Times(0);
applet->notificationDisplayed(validEntity.id());
// 场景3:Critical紧急通知,不应触发 pushPendingEntity
validEntity.setProcessedType(NotifyEntity::NotProcessed);
validEntity.setHints(QVariantMap{{"urgency", QVariant::fromValue<uint>(NotifyEntity::Critical)}});
mockPersistence->setMockEntity(validEntity);
EXPECT_CALL(*mockManager, pushPendingEntity(testing::_, testing::_)).Times(0);
applet->notificationDisplayed(validEntity.id());
} |
The notification expire timer previously ran in the notification server (worker thread) and was started when the notification was received, so a notification waiting in a long display queue could expire before its bubble was shown. The timeout is now owned by the bubble frontend and only starts once the bubble is actually displayed. 1. Add a per-bubble single-shot QTimer in BubbleModel that starts when a bubble is shown (insert/replace) using the client expireTimeout (0: never expire, -1: 5000ms default, Critical urgency: never expire). 2. On expiry the frontend closes the bubble and calls notificationClosed(id, bubbleId, Expired) on the server, which moves the notification from the in-memory store to the center database and emits NotificationStateChanged(Processed) and the DBus NotificationClosed signal. 3. Move the hover block to the frontend: setBlockedId pauses/resumes the per-bubble timer so hovering keeps the bubble on screen, keeping the 1s grace after unhover and the replaced-bubble blocking behavior. 4. Remove the server-side timeout bookkeeping: notificationDisplayed, setBlockClosedId, pushPendingEntity, onHandingPendingEntities, removePendingEntity and the pending-timeout QTimer. 5. Expose BubbleItem::timeout() and NotifyEntity::timeout() for the frontend timeout computation. 6. Remove the obsolete NotificationDisplayed/SetBlockClosedId tests. Log: Fixed notifications expiring before their bubble was displayed. Influence: 1. Send several notifications at once and verify each bubble stays for the full expire timeout. 2. Verify critical notifications and expireTimeout 0 never close. 3. Hover a bubble and verify it does not expire, then closes 1s after unhover. 4. Verify expired bubbles are moved to the notification center and the DBus NotificationClosed(Expired) signal is emitted. 5. Run the notification server unit tests. fix: 将通知过期计时迁移到气泡前端 通知过期计时此前在通知服务器(工作线程)中运行,收到通知时即启动,导致 长显示队列中的通知可能在显示前就已过期。现将超时逻辑交由气泡前端持有, 气泡真正显示后才开始计时。 1. 在 BubbleModel 中为每个气泡增加单次 QTimer,气泡显示(插入/替换)时 根据客户端 expireTimeout 启动(0:永不过期,-1:默认 5000ms,Critical 优先级:永不过期)。 2. 到期后前端关闭气泡并调用服务器 notificationClosed(id, bubbleId, Expired),将通知从内存存储迁移到通知中心数据库,并发送 NotificationStateChanged(Processed) 与 DBus NotificationClosed 信号。 3. 将悬停阻塞移到前端:setBlockedId 暂停/恢复对应气泡定时器,使悬停时 气泡不关闭,并保留取消悬停后 1s 缓冲及替换气泡继续阻塞的行为。 4. 移除服务端超时簿记:notificationDisplayed、setBlockClosedId、 pushPendingEntity、onHandingPendingEntities、removePendingEntity 以及 pending-timeout 定时器。 5. 为前端超时计算暴露 BubbleItem::timeout() 与 NotifyEntity::timeout()。 6. 移除过时的 NotificationDisplayed/SetBlockClosedId 测试。 Log: 修复通知在气泡显示前就过期的问题。 Influence: 1. 一次性发送多条通知,验证每个气泡都能保持完整的过期时间。 2. 验证 Critical 通知与 expireTimeout 为 0 的通知永不过期。 3. 悬停气泡验证其不关闭,取消悬停 1s 后关闭。 4. 验证过期气泡进入通知中心,并发出 DBus NotificationClosed(Expired)。 5. 运行通知服务器单元测试。 PMS: BUG-372279
430dd63 to
fcf70d8
Compare
| if (interval <= 0) | ||
| return; | ||
|
|
||
| auto *timer = new QTimer(this); |
| timer->setSingleShot(true); | ||
| timer->setInterval(interval); | ||
| connect(timer, &QTimer::timeout, this, [this, id, bubbleId = bubble->bubbleId()] { | ||
| m_timeoutTimers.remove(id); |
| } | ||
| } | ||
|
|
||
| void BubbleModel::setBlockedId(qint64 id) |
There was a problem hiding this comment.
这样的话,进入了暂存区域的通知没有超时的机制了,
pushPendingEntitycall fromNotify(), so the expire timer no longer starts as soon as a notification is receivedbubbleDisplayedsignal toBubbleModel, emitted when a bubble is actually inserted into the display modelbubbleDisplayedinBubblePaneland forward it to the notification server throughnotificationDisplayedtimeout()accessor toNotifyEntityto read the client provided expire timeoutNotificationManager::notificationDisplayedto schedule the timeout only when the bubble is shown, avoiding premature expiry while notifications are still queuednotificationDisplayedviaQt::QueuedConnectioninNotifyServerAppletso the pending timeout timer is started in the worker thread it belongs tonotificationDisplayedLog: Defer the notification expire timer until the bubble is actually displayed on screen
Influence:
fix: 通知气泡显示后才启动过期计时
Notify()中立即调用pushPendingEntity的逻辑,通知收到后不再 马上启动过期计时BubbleModel中新增bubbleDisplayed信号,在气泡实际插入显示模型 时发出BubblePanel中连接bubbleDisplayed,通过notificationDisplayed转发给通知服务端NotifyEntity新增timeout()访问器,用于读取客户端传入的过期时间NotificationManager::notificationDisplayed,仅在气泡显示时才调度 超时,避免通知在排队期间提前过期NotifyServerApplet中通过Qt::QueuedConnection转发notificationDisplayed,确保过期定时器在其所属的 worker 线程中启动notificationDisplayed补充单元测试Log: 将通知过期计时推迟到气泡真正显示之后
Influence:
PMS: BUG-372279
Summary by Sourcery
Defer starting notification expiry timers until bubbles are actually displayed on screen.
New Features:
Bug Fixes:
Enhancements:
Tests: