mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
fix(notifications): bar bell dot = unread since history visit
This commit is contained in:
@@ -130,6 +130,10 @@ Application::Application() : m_weatherService(m_configService, m_httpClient) {
|
||||
const char* origin = (n.origin == NotificationOrigin::Internal) ? "internal" : "external";
|
||||
kLog.debug("notification {} id={} origin={}", kind, n.id, origin);
|
||||
|
||||
if (event == NotificationEvent::Added && m_panelManager.isActivePanelContext("notifications")) {
|
||||
m_notificationManager.markNotificationHistorySeen();
|
||||
}
|
||||
|
||||
// Keep bar widgets in sync with notification state changes.
|
||||
m_bar.refresh();
|
||||
if (shouldRefreshControlCenter()) {
|
||||
|
||||
@@ -164,6 +164,7 @@ uint32_t NotificationManager::addOrReplace(uint32_t replaces_id, std::string app
|
||||
const auto& n = m_notifications.back();
|
||||
log_notification(n, "added");
|
||||
upsertHistory(n, true, std::nullopt);
|
||||
m_unreadSinceHistoryVisit = true;
|
||||
|
||||
for (auto& [token, cb] : m_eventCallbacks) {
|
||||
cb(n, NotificationEvent::Added);
|
||||
@@ -270,6 +271,7 @@ void NotificationManager::clearHistory() {
|
||||
m_history.clear();
|
||||
m_historyIndex.clear();
|
||||
++m_changeSerial;
|
||||
markNotificationHistorySeen();
|
||||
}
|
||||
|
||||
std::vector<uint32_t> NotificationManager::expiredIds() const {
|
||||
@@ -344,3 +346,15 @@ bool NotificationManager::toggleDoNotDisturb() {
|
||||
void NotificationManager::setStateCallback(StateCallback callback) { m_stateCallback = std::move(callback); }
|
||||
|
||||
void NotificationManager::setSoundPlayer(SoundPlayer* soundPlayer) { m_soundPlayer = soundPlayer; }
|
||||
|
||||
bool NotificationManager::hasUnreadNotificationHistory() const noexcept { return m_unreadSinceHistoryVisit; }
|
||||
|
||||
void NotificationManager::markNotificationHistorySeen() {
|
||||
if (!m_unreadSinceHistoryVisit) {
|
||||
return;
|
||||
}
|
||||
m_unreadSinceHistoryVisit = false;
|
||||
if (m_stateCallback) {
|
||||
m_stateCallback();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,11 @@ public:
|
||||
void setStateCallback(StateCallback callback);
|
||||
void setSoundPlayer(class SoundPlayer* soundPlayer);
|
||||
|
||||
// Bar indicator: true when at least one notification was added since the user last
|
||||
// viewed the notification history (control center notifications tab).
|
||||
[[nodiscard]] bool hasUnreadNotificationHistory() const noexcept;
|
||||
void markNotificationHistorySeen();
|
||||
|
||||
private:
|
||||
void upsertHistory(const Notification& notification, bool active, std::optional<CloseReason> closeReason);
|
||||
void rebuildHistoryIndex();
|
||||
@@ -101,5 +106,6 @@ private:
|
||||
uint32_t m_nextId{1};
|
||||
std::uint64_t m_changeSerial{0};
|
||||
bool m_doNotDisturb = false;
|
||||
bool m_unreadSinceHistoryVisit = false;
|
||||
class SoundPlayer* m_soundPlayer = nullptr;
|
||||
};
|
||||
|
||||
@@ -78,7 +78,7 @@ void NotificationWidget::doLayout(Renderer& renderer, float /*containerWidth*/,
|
||||
void NotificationWidget::doUpdate(Renderer& /*renderer*/) { refreshIndicatorState(); }
|
||||
|
||||
void NotificationWidget::refreshIndicatorState() {
|
||||
const bool hasNotifications = (m_manager != nullptr) && !m_manager->all().empty();
|
||||
const bool hasNotifications = (m_manager != nullptr) && m_manager->hasUnreadNotificationHistory();
|
||||
const bool dndEnabled = (m_manager != nullptr) && m_manager->doNotDisturb();
|
||||
if (hasNotifications == m_hasNotifications && dndEnabled == m_dndEnabled) {
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "shell/control_center/control_center_panel.h"
|
||||
|
||||
#include "i18n/i18n.h"
|
||||
#include "notification/notification_manager.h"
|
||||
#include "render/core/renderer.h"
|
||||
#include "render/scene/input_area.h"
|
||||
#include "shell/panel/panel_manager.h"
|
||||
@@ -22,6 +23,7 @@ ControlCenterPanel::ControlCenterPanel(NotificationManager* notifications, PipeW
|
||||
noctalia::theme::ThemeService* theme, IdleInhibitor* idleInhibitor,
|
||||
WaylandConnection* wayland, Wallpaper* wallpaper) {
|
||||
(void)upower;
|
||||
m_notificationManager = notifications;
|
||||
m_tabs[tabIndex(TabId::Overview)] =
|
||||
std::make_unique<OverviewTab>(mpris, weather, audio, powerProfiles, config, network, bluetooth, nightLight, theme,
|
||||
notifications, idleInhibitor, wayland, wallpaper);
|
||||
@@ -275,6 +277,9 @@ bool ControlCenterPanel::deferPointerRelayout() const { return deferExternalRefr
|
||||
|
||||
void ControlCenterPanel::selectTab(TabId tab) {
|
||||
m_activeTab = tab;
|
||||
if (tab == TabId::Notifications && m_notificationManager != nullptr) {
|
||||
m_notificationManager->markNotificationHistorySeen();
|
||||
}
|
||||
for (const auto& meta : kTabs) {
|
||||
const std::size_t idx = tabIndex(meta.id);
|
||||
if (m_tabContainers[idx] != nullptr) {
|
||||
|
||||
@@ -134,4 +134,5 @@ private:
|
||||
std::array<Flex*, kTabCount> m_tabContainers{};
|
||||
std::array<Flex*, kTabCount> m_tabHeaderActions{};
|
||||
TabId m_activeTab = TabId::Overview;
|
||||
NotificationManager* m_notificationManager = nullptr;
|
||||
};
|
||||
|
||||
@@ -762,6 +762,13 @@ bool PanelManager::isAttachedOpen() const noexcept { return isOpen() && m_attach
|
||||
|
||||
const std::string& PanelManager::activePanelId() const noexcept { return m_activePanelId; }
|
||||
|
||||
bool PanelManager::isActivePanelContext(std::string_view context) const noexcept {
|
||||
if (!isOpen() || m_activePanel == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return m_activePanel->isContextActive(context);
|
||||
}
|
||||
|
||||
void PanelManager::refresh() {
|
||||
if (!isOpen() || m_renderContext == nullptr || m_activePanel == nullptr || m_surface == nullptr) {
|
||||
return;
|
||||
|
||||
@@ -77,6 +77,8 @@ public:
|
||||
[[nodiscard]] bool isOpen() const noexcept;
|
||||
[[nodiscard]] bool isAttachedOpen() const noexcept;
|
||||
[[nodiscard]] const std::string& activePanelId() const noexcept;
|
||||
// True when a panel is open and it reports the given context as active (e.g. control-center tab).
|
||||
[[nodiscard]] bool isActivePanelContext(std::string_view context) const noexcept;
|
||||
[[nodiscard]] std::optional<LayerPopupParentContext> popupParentContextForSurface(wl_surface* surface) const noexcept;
|
||||
[[nodiscard]] std::optional<LayerPopupParentContext> fallbackPopupParentContext() const noexcept;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user