ukui-sidebar/ 0000775 0001750 0001750 00000000000 15167643374 012104 5 ustar feng feng ukui-sidebar/src/ 0000775 0001750 0001750 00000000000 15167643374 012673 5 ustar feng feng ukui-sidebar/src/sidebar-dbus-service.h 0000664 0001750 0001750 00000002523 15167606206 017041 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_SIDEBAR_DBUS_SERVICE_H
#define UKUI_SIDEBAR_SIDEBAR_DBUS_SERVICE_H
#include
#include "sidebar-main.h"
class SidebarAdaptor;
namespace Sidebar {
class SidebarDbusService : public QObject, public QDBusContext
{
Q_OBJECT
public:
explicit SidebarDbusService(SidebarMain *parent = nullptr);
SidebarMain *parent();
public Q_SLOTS:
void sidebarActive();
void shortcutsActive();
void active(const QString &module);
void shortcutWidgetActive(const QString &id, bool showReturnButton);
private:
SidebarAdaptor *m_adaptor {nullptr};
};
} // Sidebar
#endif //UKUI_SIDEBAR_SIDEBAR_DBUS_SERVICE_H
ukui-sidebar/src/windows/ 0000775 0001750 0001750 00000000000 15167643374 014365 5 ustar feng feng ukui-sidebar/src/windows/urgency-notification-window.h 0000664 0001750 0001750 00000002606 15167606206 022200 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef URGENCYNOTIFICATIONWINDOW_H
#define URGENCYNOTIFICATIONWINDOW_H
#include
#include
#include
#include "urgency-notification-model.h"
namespace UkuiNotification {
class UrgencyNotificationWindow : public UkuiQuick::SharedEngineView
{
Q_OBJECT
public:
explicit UrgencyNotificationWindow(QWindow *parent = nullptr);
private:
UrgencyNotificationModel *m_urgencyModel;
void setWindowProperties();
void setWindowPosition();
protected:
bool event(QEvent *event) override;
private Q_SLOTS:
void showUrgencyNotificationWindow();
void closeUrgencyNotificationWindow();
};
} // Notification
#endif // URGENCYNOTIFICATIONWINDOW_H
ukui-sidebar/src/windows/status-bar-view.h 0000664 0001750 0001750 00000002657 15167606206 017576 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Author: hxf
*
*/
#ifndef UKUI_SIDEBAR_STATUS_BAR_VIEW_H
#define UKUI_SIDEBAR_STATUS_BAR_VIEW_H
#include
#include "window-helper.h"
class StatusBarView : public UkuiQuick::SharedEngineView
{
Q_OBJECT
Q_PROPERTY(bool isTabletModel READ isTabletModel NOTIFY isTabletModelChanged)
public:
explicit StatusBarView(QWindow *parent = nullptr);
void init();
bool isTabletModel() const;
Q_SIGNALS:
void isTabletModelChanged();
protected:
bool event(QEvent *event) override;
private:
QWindow* targetWindow(QTouchEvent* touchEvent);
bool m_isPressed {false};
UkuiQuick::WindowProxy* m_windowProxy;
void updateGeometry();
};
#endif //UKUI_SIDEBAR_STATUS_BAR_VIEW_H
ukui-sidebar/src/windows/window-blur-helper.cpp 0000664 0001750 0001750 00000007331 15167643374 020623 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "window-blur-helper.h"
#include
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include
#else
#include
#endif
#include
#include
#include
#include
// 窗管特效接口
#include
#include
using namespace Sidebar;
WindowBlurHelper::WindowBlurHelper(QObject *parent) : QObject(parent)
{
}
void WindowBlurHelper::setWindow(QWindow *window)
{
m_window = window;
}
void WindowBlurHelper::setEnable(bool enable)
{
if (m_enable == enable) {
return;
}
m_enable = enable;
updateBlurArea();
}
void WindowBlurHelper::setRadius(quint32 radius)
{
if (m_radius == radius) {
return;
}
if (radius > 4000) {
m_radius = 4000;
} else {
m_radius = radius;
}
updateBlurArea();
Q_EMIT radiusChanged();
}
void WindowBlurHelper::setRegion(qreal x, qreal y, qreal w, qreal h, qreal radius)
{
QPainterPath path;
path.addRoundedRect(x, y, w, h, radius, radius);
m_region = QRegion(path.toFillPolygon().toPolygon());
updateBlurArea();
}
void WindowBlurHelper::enableBlurBehind(WId window, bool enable, const QRegion ®ion, uint32_t radius)
{
xcb_connection_t *c = QX11Info::connection();
if (!c) {
return;
}
const QByteArray effectName = QByteArrayLiteral("_KDE_NET_WM_BLUR_BEHIND_REGION");
xcb_intern_atom_cookie_t atomCookie = xcb_intern_atom_unchecked(c, false, effectName.length(), effectName.constData());
QScopedPointer atom(xcb_intern_atom_reply(c, atomCookie, nullptr));
if (!atom) {
return;
}
if (enable) {
QVector data;
data.reserve(region.rectCount() * 4 + 1); // 1 means radius
for (const QRect &r : region) {
// kwin on X uses device pixels, convert from logical
auto dpr = qApp->devicePixelRatio();
data << r.x() * dpr << r.y() * dpr << r.width() * dpr << r.height() * dpr;
}
data << radius;
xcb_change_property(c, XCB_PROP_MODE_REPLACE, window, atom->atom, XCB_ATOM_CARDINAL, 32, data.size(), data.constData());
} else {
xcb_delete_property(c, window, atom->atom);
xcb_flush(c);
}
}
QWindow *WindowBlurHelper::window()
{
return m_window;
}
bool WindowBlurHelper::enable()
{
return m_enable;
}
quint32 WindowBlurHelper::radius()
{
return m_radius;
}
bool WindowBlurHelper::updateBlurArea()
{
if (!m_window) {
qWarning() << "WindowBlurHelper::updateBlurArea: window in not init.";
return false;
}
bool enable = (m_enable && m_radius > 0 && !m_region.isEmpty());
// other.
//enableBlurBehind(m_window->winId(), enable, m_region, m_radius);
// openkylin.
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
KWindowEffects::enableBlurBehindWithStrength(m_window, enable, m_region, m_radius);
#else
KWindowEffects::enableBlurBehind(m_window, enable, m_region);
#endif
return enable;
} ukui-sidebar/src/windows/window-type.h 0000664 0001750 0001750 00000002175 15167606206 017022 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
//
// Created by hxf on 22-11-11.
//
#ifndef UKUI_SIDEBAR_WINDOWTYPE_H
#define UKUI_SIDEBAR_WINDOWTYPE_H
#include
namespace Sidebar {
/**
* 预定义的全部窗口类型,可以增加
*/
class SidebarWindowType
{
Q_GADGET
public:
enum Type {
Normal,
Sidebar,
NotificationCenter,
StatusBar,
RightHandGesture
};
Q_ENUM(Type)
};
}
#endif //UKUI_SIDEBAR_WINDOWTYPE_H
ukui-sidebar/src/windows/notification-window.h 0000664 0001750 0001750 00000003672 15167606206 020532 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_NOTIFICATION_WINDOW_H
#define UKUI_SIDEBAR_NOTIFICATION_WINDOW_H
#include
#include "notification-group-model.h"
#include
#include
class QScreen;
namespace UkuiNotification {
class NotificationCenterWindow : public UkuiQuick::SharedEngineView
{
Q_OBJECT
Q_PROPERTY(bool contentVisible READ contentVisible WRITE setContentVisible NOTIFY contentVisibleChanged)
public:
static NotificationGroupModel *globalGroupModel();
explicit NotificationCenterWindow(QWindow *parent = nullptr);
void init();
bool contentVisible() const;
void setContentVisible(bool contentVisible);
Q_SIGNALS:
void contentVisibleChanged();
public Q_SLOTS:
void activeNotificationCenter(bool active);
private Q_SLOTS:
void onPrimaryScreenChanged(QScreen *newScreen);
void updateGeometry();
void callNotificationCenter(int posY);
void callNotificationCenterEnd(int posX, int posY);
private:
bool event(QEvent *event) override;
private:
bool m_isTabletMode = false;
bool m_contentVisible = false;
UkuiQuick::WindowProxy *m_windowProxy {nullptr};
QPointer m_screen {nullptr};
};
} // Notification
#endif //UKUI_SIDEBAR_NOTIFICATION_WINDOW_H
ukui-sidebar/src/windows/tablet-popup-view.h 0000664 0001750 0001750 00000004133 15167606206 020114 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_TABLET_POPUP_VIEW_H
#define UKUI_SIDEBAR_TABLET_POPUP_VIEW_H
#include
#include
#include
#include "window-helper.h"
class QScreen;
namespace UkuiNotification {
class TabletPopupView : public UkuiQuick::SharedEngineView
{
Q_OBJECT
Q_PROPERTY(int windowWidth READ windowWidth NOTIFY windowWidthChanged)
Q_PROPERTY(int windowMaxHeight READ windowMaxHeight NOTIFY windowMaxHeightChanged)
Q_PROPERTY(bool enableAnimation READ enableAnimation NOTIFY enableAnimationChanged)
public:
explicit TabletPopupView(QWindow *parent = nullptr);
void init();
int windowWidth() const;
int windowMaxHeight() const;
bool enableAnimation() const;
Q_INVOKABLE void enableWindowBlur(int radius, bool enable = true);
Q_INVOKABLE void updateHeight(int height);
Q_SIGNALS:
void windowWidthChanged();
void windowMaxHeightChanged();
void enableAnimationChanged();
private Q_SLOTS:
void onPrimaryScreenChanged(QScreen *newScreen);
void onScreenGeometryChanged();
void updateGeometry();
private:
bool event(QEvent *event) override;
private:
bool m_enableAnimation = {true};
int m_windowMargin = 12;
int m_windowWidth = 0;
QPoint m_topLeft;
UkuiQuick::WindowProxy* m_windowProxy {nullptr};
QPointer m_screen {nullptr};
};
} // Notification
#endif //UKUI_SIDEBAR_TABLET_POPUP_VIEW_H
ukui-sidebar/src/windows/urgency-notification-window.cpp 0000664 0001750 0001750 00000010615 15167606206 022532 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "urgency-notification-window.h"
#include
#include
#include
#include
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include
#else
#include
#endif
#include
#include
#include
#include "color-helper.h"
#include "screen-monitor.h"
using namespace UkuiNotification;
const QByteArray PANEL_GSETTINGS = "org.ukui.panel.settings";
#define PANEL_TOP 1
#define PANEL_LEFT 2
#define PANEL_RIGHT 3
UrgencyNotificationWindow::UrgencyNotificationWindow(QWindow *parent)
:SharedEngineView(parent)
{
setResizeMode(SharedEngineView::SizeRootObjectToView);
setWindowProperties();
m_urgencyModel = new UrgencyNotificationModel(this);
m_urgencyModel->setSourceModel(NotificationModel::instance());
m_urgencyModel->sort(0, Qt::DescendingOrder);
engine()->addImportPath("qrc:/qml");
rootContext()->setContextProperty("urgencyNotificationModel", m_urgencyModel);
rootContext()->setContextProperty("urgencyNotificationWindow", this);
setSource(QUrl("qrc:/qml/UrgencyNotificationView.qml"));
connect(m_urgencyModel, &UrgencyNotificationModel::rowsInserted, this, &UrgencyNotificationWindow::showUrgencyNotificationWindow);
connect(m_urgencyModel, &UrgencyNotificationModel::rowsRemoved, this, &UrgencyNotificationWindow::closeUrgencyNotificationWindow);
}
void UrgencyNotificationWindow::setWindowProperties()
{
setColor(Qt::transparent); //背景透明
setFlags(Qt::FramelessWindowHint);
//跳过任务栏属性
kdk::WindowManager::setSkipTaskBar(this, true);
kdk::WindowManager::setSkipSwitcher(this, true);
KWindowSystem::setType(this->winId(), NET::Notification);
KWindowEffects::enableBlurBehind(this->winId(), true, QRegion()); //背景模糊
setWindowPosition();
}
void UrgencyNotificationWindow::setWindowPosition()
{
QRect rect = QApplication::primaryScreen()->geometry();
if(QGSettings::isSchemaInstalled(PANEL_GSETTINGS)) {
QGSettings setting(PANEL_GSETTINGS);
if (setting.keys().contains(QString("panelposition")) && setting.keys().contains(QString("panelsize"))) {
int panelPosition = setting.get("panelposition").toInt();
int panelHeight = setting.get("panelsize").toInt();
switch (panelPosition) {
case PANEL_TOP:
rect = QRect(rect.x(), rect.y() + panelHeight, rect.width(), rect.height() - panelHeight);
break;
case PANEL_LEFT:
rect = QRect(rect.x() + panelHeight, rect.y(), rect.width() - panelHeight, rect.height());
break;
case PANEL_RIGHT:
rect = QRect(rect.x(), rect.y(), rect.width() - panelHeight, rect.height());
break;
default:
rect = QRect(rect.x(), rect.y(), rect.width(), rect.height() - panelHeight);
break;
}
}
}
if (QX11Info::isPlatformX11()) {
this->setGeometry(rect);
} else {
kdk::WindowManager::setGeometry(this, rect);
}
}
bool UrgencyNotificationWindow::event(QEvent *event)
{
switch (event->type()) {
case QEvent::Expose:
if (isExposed()) {
setWindowProperties();
}
break;
default:
break;
}
// qDebug() << QApplication::primaryScreen()->geometry() << geometry() << __LINE__;
return QQuickWindow::event(event);
}
void UrgencyNotificationWindow::showUrgencyNotificationWindow()
{
this->show();
}
void UrgencyNotificationWindow::closeUrgencyNotificationWindow()
{
if (m_urgencyModel->rowCount() == 0) {
this->hide();
}
}
ukui-sidebar/src/windows/right-hand-gesture-view.h 0000664 0001750 0001750 00000002716 15167606206 021206 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Author: hxf
*
*/
#ifndef UKUI_SIDEBAR_RIGHT_HAND_GESTURE_VIEW_H
#define UKUI_SIDEBAR_RIGHT_HAND_GESTURE_VIEW_H
#include
#include "window-helper.h"
namespace Sidebar {
class RightHandGestureView : public UkuiQuick::SharedEngineView
{
Q_OBJECT
public:
explicit RightHandGestureView(QWindow *parent = nullptr);
void updateGeometry();
void init();
protected:
bool event(QEvent *event) override;
private:
QRect windowGeometry();
void callControlCenter(int x);
void callControlCenterEnd(int x, int y);
QWindow* targetWindow(QTouchEvent* touchEvent);
bool m_isPressed {false};
UkuiQuick::WindowProxy* m_windowProxy {nullptr};
};
} // Sidebar
#endif //UKUI_SIDEBAR_RIGHT_HAND_GESTURE_VIEW_H
ukui-sidebar/src/windows/sidebar-window-helper.cpp 0000664 0001750 0001750 00000007442 15167643374 021273 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "sidebar-window-helper.h"
#include "screen-monitor.h"
//#include "layout-config.h"
#include "hand-gesture-helper.h"
#include "global-settings.h"
// 窗管特效接口
#include
#include
// Qt
#include
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include
#else
#include
#endif
#include
#include
#define HAND_GESTURE_WIDTH 2
namespace Sidebar {
static SidebarWindowHelper *globalWindowHelperInstance = nullptr;
void SidebarWindowDefineModule::defineModules(const char *uri, int versionMajor, int versionMinor)
{
qRegisterMetaType("SidebarWindowType::Type");
qmlRegisterUncreatableType(uri, versionMajor, versionMinor, "SidebarWindowType", "Enum");
qmlRegisterRevision(uri, versionMajor, versionMinor);
qmlRegisterRevision(uri, versionMajor, versionMinor);
}
SidebarWindowHelper *SidebarWindowHelper::instance(QObject *parent)
{
if (!globalWindowHelperInstance) {
globalWindowHelperInstance = new SidebarWindowHelper(parent);
}
return globalWindowHelperInstance;
}
SidebarWindowHelper::SidebarWindowHelper(QObject *parent) : QObject(parent)
{
updateRects();
ScreenMonitor *screenMonitor = ScreenMonitor::getInstance();
connect(screenMonitor, &ScreenMonitor::geometryChanged, this, &SidebarWindowHelper::updateRects);
connect(screenMonitor, &ScreenMonitor::primaryScreenChanged, this, &SidebarWindowHelper::updateRects);
connect(screenMonitor, &ScreenMonitor::layoutDirectionChanged, this, &SidebarWindowHelper::updateRects);
}
QRect SidebarWindowHelper::getWindowGeometry(SidebarWindowType::Type type)
{
switch (type) {
case SidebarWindowType::NotificationCenter:
return m_notificationCenterRect;
case SidebarWindowType::StatusBar:
return m_statusBarRect;
case SidebarWindowType::RightHandGesture:
return m_rightGestureRect;
default:
return {};
}
}
Qt::LayoutDirection SidebarWindowHelper::getLayoutDirection()
{
return ScreenMonitor::getInstance()->getLayoutDirection();
}
/**
* 根据不同的窗口类型与主屏幕参数设置每一个窗口的geometry属性
*/
void SidebarWindowHelper::updateRects()
{
QRect primaryScreenRect = ScreenMonitor::getInstance()->getGeometry();
bool isMirrored = ScreenMonitor::getInstance()->getLayoutDirection() == Qt::LayoutDirection::RightToLeft;
m_notificationCenterRect = primaryScreenRect;
m_statusBarRect.setRect(primaryScreenRect.x(), primaryScreenRect.y(), primaryScreenRect.width(), HAND_GESTURE_WIDTH);
m_rightGestureRect.setRect(isMirrored ?
primaryScreenRect.x() : primaryScreenRect.x() + primaryScreenRect.width() - HAND_GESTURE_WIDTH,
primaryScreenRect.y() + HAND_GESTURE_WIDTH,
HAND_GESTURE_WIDTH,
primaryScreenRect.height() - HAND_GESTURE_WIDTH);
Q_EMIT geometryChanged();
}
} // Sidebar
ukui-sidebar/src/windows/sidebar-view.cpp 0000664 0001750 0001750 00000030112 15167643374 017447 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "sidebar-view.h"
#include "sidebar-window-helper.h"
#include "global-settings.h"
#include "window-blur-helper.h"
#include "notification-window.h"
#include "screen-monitor.h"
#include
#include
#include
#include
#include
#include
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include
#else
#include
#endif
#include
#define UKUI_PANEL_SETTING "org.ukui.panel.settings"
#define UKUI_PANEL_POSITION_KEY "panelposition"
// 两种模式下侧边栏按钮区域的宽度
#define PC_SIDEBAR_WIDTH 384
#define TABLET_SIDEBAR_WIDTH 540
using namespace Sidebar;
SidebarView::SidebarView(QWindow *parent) : SharedEngineView(parent)
{
setColor(Qt::transparent);
setResizeMode(SharedEngineView::SizeRootObjectToView);
setFlags(Qt::FramelessWindowHint | Qt::Window);
m_windowProxy = new UkuiQuick::WindowProxy(this);
m_windowProxy->setWindowType(UkuiQuick::WindowType::SystemWindow);
m_windowBlurHelper = new WindowBlurHelper(this);
m_windowBlurHelper->setWindow(this);
connect(m_windowBlurHelper, &WindowBlurHelper::radiusChanged, this, [this] {
// * wm...
update();
});
// 初始化窗口,监听任务栏变化
m_screen = QGuiApplication::primaryScreen();
setScreen(m_screen);
connect(m_screen, &QScreen::geometryChanged, this, &SidebarView::updateWindowGeometry);
connect(ScreenMonitor::getInstance(), &ScreenMonitor::screenRemoved, this, [&](QScreen *screen) {
if(screen == m_screen) {
activeWindow(false);
}
}, Qt::UniqueConnection);
setIsNotificationEmpty(UkuiNotification::NotificationCenterWindow::globalGroupModel()->rowCount(QModelIndex()) == 0);
connect(UkuiNotification::NotificationCenterWindow::globalGroupModel(), &UkuiNotification::NotificationGroupModel::rowsInserted,
this, [this] {
setIsNotificationEmpty(UkuiNotification::NotificationCenterWindow::globalGroupModel()->rowCount(QModelIndex()) == 0);
});
connect(UkuiNotification::NotificationCenterWindow::globalGroupModel(), &UkuiNotification::NotificationGroupModel::rowsRemoved,
this, [this] {
setIsNotificationEmpty(UkuiNotification::NotificationCenterWindow::globalGroupModel()->rowCount(QModelIndex()) == 0);
});
// 2.平板模式切换
onSystemModeChanged();
connect(GlobalSettings::globalInstance(), &GlobalSettings::valueChanged, this, [this] (const QString &key) {
if (key == TABLET_MODE) {
onSystemModeChanged();
} else if (key == UKUI_PANEL_POSITION_KEY || key == UKUI_PANEL_SIZE_KEY ||
key == UKUI_PANEL_TYPE_KEY || key == UKUI_SETTINGS_ISLAND_POSITION_KEY ||
key == UKUI_DATA_ISLAND_POSITION_KEY || key == UKUI_TOPBAR_SIZE_KEY ) {
updateWindowGeometry();
}
});
connect(this, &QQuickView::activeFocusItemChanged, this, [this] {
if (!activeFocusItem()) {
activeWindow(false);
}
});
connect(this, &QQuickView::visibleChanged, this, [this] (bool visible) {
if (visible) {
if (m_screen != UkuiQuick::WindowProxy::currentScreen()) {
if (m_screen) {
m_screen->disconnect(this);
}
m_screen = UkuiQuick::WindowProxy::currentScreen();
setScreen(m_screen);
connect(m_screen, &QScreen::geometryChanged, this, &SidebarView::updateWindowGeometry, Qt::UniqueConnection);
updateWindowGeometry();
}
}
});
rootContext()->setContextProperty("sidebarWindow", this);
rootContext()->setContextProperty("windowBlurHelper", m_windowBlurHelper);
updateWindowGeometry();
}
void SidebarView::init()
{
// init
engine()->addImportPath("qrc:/qml");
setSource(QUrl("qrc:/qml/Sidebar.qml"));
}
void SidebarView::activeWindow(bool active)
{
if (!rootObject()) {
return;
}
// 获取是否存在执行中的动画
QVariant isRunning(false);
QMetaObject::invokeMethod(rootObject(), "isRunning", Qt::DirectConnection, Q_RETURN_ARG(QVariant, isRunning), Q_ARG(QVariant, active));
if (isRunning.toBool() || (active == isVisible())) {
return;
}
// 初始化动画属性
QMetaObject::invokeMethod(rootObject(), "updateProperty", Qt::DirectConnection, Q_ARG(QVariant, active));
if (active) {
show();
Q_EMIT requestShowContent();
} else {
Q_EMIT requestHideContent();
}
}
void SidebarView::onSystemModeChanged()
{
bool isTabletMode = GlobalSettings::globalInstance()->getValue(TABLET_MODE).toBool();
if (isTabletMode == m_isTabletMode) {
return;
}
m_isTabletMode = isTabletMode;
// TODO: 平板切换隐藏动画
// activeWindow(false);
setWindowVisible(false);
//LayoutConfig::getInstance()->updateLayout(m_isTabletMode);
updateWindowGeometry();
Q_EMIT isTabletModeChanged();
}
bool SidebarView::isTabletMode()
{
return m_isTabletMode;
}
void SidebarView::updateWindowGeometry()
{
if (!m_screen || m_screen->geometry().isEmpty()) return;
QRect screenRect = m_screen->geometry();
// 8%的屏幕宽度为最小滑动距离
m_minimumThreshold = static_cast(screenRect.width() * 0.05);
m_primaryScreenRight = screenRect.right();
updateGeometryOfWindow();
updateGeometryOfMask();
if (m_windowGeometry.isEmpty()) return;
setGeometry(m_windowGeometry);
m_windowProxy->setPosition(m_windowGeometry.topLeft());
setMask(m_maskGeometry);
m_windowBlurHelper->setRegion(m_padding, m_windowGeometry.height() - m_blurHeight - m_padding, m_windowGeometry.width() - m_padding*2, m_blurHeight, radius());
if (rootObject()) {
rootObject()->setSize(m_windowGeometry.size());
}
Q_EMIT minimumThresholdChanged();
Q_EMIT primaryScreenRightChanged();
}
qint32 SidebarView::windowPadding() const
{
return m_padding;
}
qint32 SidebarView::minimumThreshold() const
{
return m_minimumThreshold;
}
qint32 SidebarView::primaryScreenRight() const
{
return m_primaryScreenRight;
}
qint32 SidebarView::minWindowSize() const
{
return m_minWindowSize - m_padding*2;
}
void SidebarView::setBlurHeight(int height)
{
m_windowBlurHelper->setRegion(m_padding, m_windowGeometry.height() - height - m_padding, PC_SIDEBAR_WIDTH , height, radius());
m_blurHeight = height;
}
qint32 SidebarView::radius() const
{
bool isOpenGLEnv = rootContext()->contextProperty("isOpenGLEnv").toBool();
return isOpenGLEnv ? m_radius : 0;
}
void SidebarView::setRadius(int radius)
{
if (m_radius != radius) {
m_radius = radius;
setBlurHeight(m_blurHeight);
Q_EMIT radiusChanged();
}
}
void SidebarView::updateGeometryOfWindow()
{
// QRect screenRect = screen()->availableGeometry();
QRect screenRect = m_screen->geometry();
int width = PC_SIDEBAR_WIDTH + m_padding * 2;
int panelPos = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_PANEL_POSITION_KEY).toInt();
int panelSize = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_PANEL_SIZE_KEY).toInt();
bool isMirrored = (SidebarWindowHelper::instance()->getLayoutDirection() == Qt::LayoutDirection::RightToLeft);
int panelType = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_PANEL_TYPE_KEY).toInt();
int dataIslandPosition = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_DATA_ISLAND_POSITION_KEY).toInt();
int settingsIslandPosition = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_SETTINGS_ISLAND_POSITION_KEY).toInt();
int topbarSize = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_TOPBAR_SIZE_KEY).toInt();
if (panelType == 1) {
if (dataIslandPosition == 1 || settingsIslandPosition == 1) {
m_windowGeometry = isMirrored
? screenRect.adjusted(0, topbarSize, -(screenRect.width() - width), -panelSize)
: screenRect.adjusted(screenRect.width() - width, topbarSize, 0, -panelSize);
} else {
m_windowGeometry = isMirrored
? screenRect.adjusted(0, 0, -(screenRect.width() - width), -panelSize)
: screenRect.adjusted(screenRect.width() - width, 0, 0, -panelSize);
}
} else {
// 任务栏位置 上: 1, 下: 0, 左: 2, 右: 3
switch(panelPos) {
default:
case 0:
m_windowGeometry = isMirrored
? screenRect.adjusted(0, 0, -(screenRect.width() - width), -panelSize)
: screenRect.adjusted(screenRect.width() - width, 0, 0, -panelSize);
break;
case 1:
m_windowGeometry = isMirrored
? screenRect.adjusted(0, panelSize, -(screenRect.width() - width), 0)
: screenRect.adjusted(screenRect.width() - width, panelSize, 0, 0);
break;
case 2:
m_windowGeometry = isMirrored
? screenRect.adjusted(panelSize, 0, -(screenRect.width() - width - panelSize), 0)
: screenRect.adjusted(screenRect.width() - width, 0, 0, 0);
break;
case 3:
m_windowGeometry = isMirrored
? screenRect.adjusted(0, 0, -(screenRect.width() - width), 0)
: screenRect.adjusted(screenRect.width() - width - panelSize, 0, -panelSize, 0);
break;
}
}
}
void SidebarView::updateGeometryOfMask()
{
m_maskGeometry = QRect(0,
m_isNotificationEmpty ? (m_windowGeometry.height() - m_minWindowSize) : 0,
m_windowGeometry.width(),
m_isNotificationEmpty ? m_minWindowSize : m_windowGeometry.height());
}
void SidebarView::focusInEvent(QFocusEvent *event)
{
QQuickWindow::focusInEvent(event);
}
void SidebarView::focusOutEvent(QFocusEvent *event)
{
QQuickWindow::focusOutEvent(event);
}
void SidebarView::resizeEvent(QResizeEvent *event)
{
SharedEngineView::resizeEvent(event);
}
bool SidebarView::event(QEvent *event)
{
if (event->type() == QEvent::Move) {
updateWindowGeometry();
return true;
}
return QQuickWindow::event(event);
}
void SidebarView::exposeEvent(QExposeEvent *event)
{
if (isExposed()) {
if (QX11Info::isPlatformX11()) {
requestActivate();
}
}
QQuickWindow::exposeEvent(event);
}
bool SidebarView::contentVisible() const
{
return m_contentVisible;
}
void SidebarView::setContentVisible(bool visible)
{
m_contentVisible = visible;
Q_EMIT contentVisibleChanged();
}
bool SidebarView::isNotificationEmpty() const
{
return m_isNotificationEmpty;
}
void SidebarView::setIsNotificationEmpty(bool isEmpty)
{
if (m_isNotificationEmpty == isEmpty) return;
m_isNotificationEmpty = isEmpty;
Q_EMIT isNotificationEmptyChanged();
}
bool SidebarView::isWindowFold() const
{
return m_isWindowFold;
}
void SidebarView::setIsWindowFold(bool isFold)
{
if (m_isWindowFold == isFold) return;
m_isWindowFold = isFold;
updateGeometryOfMask();
setMask(m_maskGeometry);
Q_EMIT isWindowFoldChanged();
}
void SidebarView::setWindowVisible(bool visible)
{
setVisible(visible);
if (!visible) {
setContentVisible(visible);
}
}
ukui-sidebar/src/windows/popup-notification-window.h 0000664 0001750 0001750 00000004762 15167606206 021674 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_POPUP_NOTIFICATION_WINDOW_H
#define UKUI_SIDEBAR_POPUP_NOTIFICATION_WINDOW_H
#include
#include
#include
#include
namespace UkuiQuick {
class WindowProxy;
}
namespace UkuiNotification {
class PopupNotificationWindow : public UkuiQuick::SharedEngineView
{
Q_OBJECT
Q_PROPERTY(int itemWidth READ itemWidth NOTIFY itemWidthChanged)
Q_PROPERTY(int viewWidth READ viewWidth NOTIFY viewWidthChanged)
Q_PROPERTY(bool screenLockState READ screenLockState NOTIFY screenLockStatehChanged)
public:
explicit PopupNotificationWindow(QWindow *parent = nullptr);
~PopupNotificationWindow() = default;
Q_INVOKABLE void updataWindowRegion(QVariantMap windowRect, int contentY);
Q_INVOKABLE void updataGroupsPosition(int relativeY);
Q_INVOKABLE void enableWindowBlur(bool enable);
void updatePopupWindowGeometry(bool needDisplace, int sidebarWidth);
void loadQML();
int itemWidth() const;
int viewWidth() const;
bool screenLockState() const;
Q_SIGNALS:
void itemWidthChanged();
void viewWidthChanged();
void screenLockStatehChanged();
protected:
bool event(QEvent *event) override;
private Q_SLOTS:
void onPrimaryScreenChanged(QScreen *newScreen);
void onRootWidthChanged();
private:
void initWindow();
void updateGeometry();
void initNotificationModel();
private:
bool m_needDisplace = false;
bool m_enable = false;
bool m_screenLockState = false;
QPoint m_notificationPoint;
QRegion m_windowRegion;
int m_sidebarWidth = 400;
int m_itemWidth = 374;
int m_viewWidth = 374 + 8; // margin = 8
UkuiQuick::WindowProxy *m_windowProxy {nullptr};
QPointer m_screen {nullptr};
};
}
#endif //UKUI_SIDEBAR_POPUP_NOTIFICATION_WINDOW_H
ukui-sidebar/src/windows/shortcuts-window.h 0000664 0001750 0001750 00000005476 15167643374 020115 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_SHORTCUTS_WINDOW_H
#define UKUI_SIDEBAR_SHORTCUTS_WINDOW_H
#include
#include
class QScreen;
namespace Sidebar {
class WindowBlurHelper;
}
class ShortcutsWindow : public UkuiQuick::SharedEngineView
{
Q_OBJECT
Q_PROPERTY(bool isTabletMode READ isTabletMode NOTIFY tabletModeChanged)
Q_PROPERTY(int windowMargin READ windowMargin NOTIFY windowMarginChanged)
Q_PROPERTY(int panelPos READ panelPos NOTIFY panelPosChanged)
Q_PROPERTY(QPoint position MEMBER m_position NOTIFY positionChanged)
Q_PROPERTY(QString currentId READ currentId WRITE setCurrentId NOTIFY currentIdChanged)
public:
explicit ShortcutsWindow(QWindow *parent = nullptr);
bool isTabletMode() const;
int windowMargin() const;
int panelPos() const;
QString currentId() const;
void setCurrentId(QString currentId);
void activeShortcutsWindow(bool active = true);
bool requestMenuWidget(QString widgetId = "", bool showReturnButton = false);
void backToShortcuts();
public Q_SLOTS:
void setBlurStrength(quint32 strength = 4000);
Q_SIGNALS:
void tabletModeChanged();
void windowMarginChanged();
void panelPosChanged();
void currentIdChanged();
void showMenuWidget(QString widgetId, bool showReturnButton, QString returnButtonName);
void hideMenuWidget();
void positionChanged();
private Q_SLOTS:
void updateGeometry();
void onTabletModeChanged();
void moveShortcutPanel(int distance);
void onRight2LeftReleased(int posX, int posY);
protected:
bool event(QEvent *event) override;
private:
void initUI();
void initSettings();
void initConnections();
void updateEffects();
bool m_isTabletMode {false};
int m_panelPos{4};
int m_panelSize{48};
int m_panelType{0};
int m_settingsIslandPosition{0};
int m_topbarSize{0};
QPoint m_position{0,0};
QString m_currentId{""};
Qt::LayoutDirection m_layoutDirection{Qt::LayoutDirection::LeftToRight};
UkuiQuick::WindowProxy *m_windowProxy {nullptr};
QPointer m_screen {nullptr};
};
#endif //UKUI_SIDEBAR_SHORTCUTS_WINDOW_H
ukui-sidebar/src/windows/sidebar-view.h 0000664 0001750 0001750 00000007576 15167643374 017136 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_SIDEBAR_VIEW_H
#define UKUI_SIDEBAR_SIDEBAR_VIEW_H
#include "window-type.h"
#include "window-helper.h"
#include
#include
namespace Sidebar {
class WindowBlurHelper;
class SidebarView : public UkuiQuick::SharedEngineView
{
Q_OBJECT
Q_PROPERTY(bool contentVisible READ contentVisible WRITE setContentVisible NOTIFY contentVisibleChanged)
Q_PROPERTY(bool isNotificationEmpty READ isNotificationEmpty WRITE setIsNotificationEmpty NOTIFY isNotificationEmptyChanged)
Q_PROPERTY(bool isWindowFold READ isWindowFold WRITE setIsWindowFold NOTIFY isWindowFoldChanged)
Q_PROPERTY(bool isTabletMode READ isTabletMode NOTIFY isTabletModeChanged)
Q_PROPERTY(qint32 radius READ radius WRITE setRadius NOTIFY radiusChanged)
Q_PROPERTY(qint32 windowPadding READ windowPadding NOTIFY windowPaddingChanged)
Q_PROPERTY(qint32 minimumThreshold READ minimumThreshold NOTIFY minimumThresholdChanged)
Q_PROPERTY(qint32 primaryScreenRight READ primaryScreenRight NOTIFY primaryScreenRightChanged)
Q_PROPERTY(qint32 minWindowSize READ minWindowSize NOTIFY minWindowSizeChanged)
public:
explicit SidebarView(QWindow *parent = nullptr);
void init();
bool isTabletMode();
bool contentVisible() const;
void setContentVisible(bool visible);
bool isNotificationEmpty() const;
void setIsNotificationEmpty(bool isEmpty);
bool isWindowFold() const;
void setIsWindowFold(bool isFold);
qint32 radius() const;
void setRadius(int radius);
qint32 windowPadding() const;
qint32 minimumThreshold() const;
qint32 primaryScreenRight() const;
qint32 minWindowSize() const;
Q_INVOKABLE void setBlurHeight(int height);
Q_SIGNALS:
void isTabletModeChanged();
void contentVisibleChanged();
void isNotificationEmptyChanged();
void isWindowFoldChanged();
void radiusChanged();
void windowPaddingChanged();
void minimumThresholdChanged();
void primaryScreenRightChanged();
void minWindowSizeChanged();
void requestShowContent();
void requestHideContent();
public Q_SLOTS:
void activeWindow(bool active);
void setWindowVisible(bool visible);
protected:
bool event(QEvent *event) override;
void focusInEvent(QFocusEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void exposeEvent(QExposeEvent *event) override;
private Q_SLOTS:
void updateWindowGeometry();
void onSystemModeChanged();
private:
void updateGeometryOfWindow();
void updateGeometryOfMask();
private:
bool m_isTabletMode {false};
bool m_contentVisible {false};
bool m_isNotificationEmpty {true};
bool m_isWindowFold {true};
qint32 m_radius = 12;
qint32 m_blurHeight = 144;
qint32 m_padding = 8;
qint32 m_minimumThreshold = 100;
qint32 m_primaryScreenRight = 0;
qint32 m_minWindowSize = 160;
QRect m_windowGeometry = QRect(0,0,0,0);
QRect m_maskGeometry = QRect(0,0,0,0);
WindowBlurHelper *m_windowBlurHelper {nullptr};
UkuiQuick::WindowProxy* m_windowProxy {nullptr};
QPointer m_screen {nullptr};
};
} // Sidebar
#endif //UKUI_SIDEBAR_SIDEBAR_VIEW_H
ukui-sidebar/src/windows/status-bar-view.cpp 0000664 0001750 0001750 00000013252 15167606206 020122 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Author: hxf
*
*/
#include
#include "status-bar-view.h"
#include "global-settings.h"
#include "sidebar-window-helper.h"
#include "hand-gesture-helper.h"
StatusBarView::StatusBarView(QWindow *parent) : SharedEngineView(parent)
{
setColor("transparent");
setResizeMode(SharedEngineView::SizeRootObjectToView);
rootContext()->setContextProperty("statusBarView", this);
rootContext()->setContextProperty("handGestureHelper", Sidebar::HandGestureHelper::getInstance());
setFlags(Qt::FramelessWindowHint);
m_windowProxy = new UkuiQuick::WindowProxy(this);
m_windowProxy->setWindowType(UkuiQuick::WindowType::Switcher);
updateGeometry();
connect(Sidebar::SidebarWindowHelper::instance(), &Sidebar::SidebarWindowHelper::geometryChanged,
this, &StatusBarView::updateGeometry);
setVisible(isTabletModel());
connect(Sidebar::GlobalSettings::globalInstance(), &Sidebar::GlobalSettings::valueChanged, this, [this] (const QString &key) {
if (key == TABLET_MODE) {
setVisible(isTabletModel());
Q_EMIT isTabletModelChanged();
}
});
}
bool StatusBarView::isTabletModel() const
{
return Sidebar::GlobalSettings::globalInstance()->getValue(TABLET_MODE).toBool();
}
void StatusBarView::updateGeometry()
{
QRect geometry = Sidebar::SidebarWindowHelper::instance()->getWindowGeometry(Sidebar::SidebarWindowType::StatusBar);
if (geometry.isEmpty()) return;
setGeometry(geometry);
m_windowProxy->setPosition(geometry.topLeft());
}
bool StatusBarView::event(QEvent *event)
{
switch (event->type()) {
case QEvent::TouchBegin: {
auto *touchEvent = static_cast(event);
if (targetWindow(touchEvent) == this) {
m_isPressed = true;
return true;
}
break;
}
case QEvent::TouchUpdate: {
auto *touchEvent = static_cast(event);
if (targetWindow(touchEvent) == this && m_isPressed) {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
int touchY = touchEvent->touchPoints().first().pos().y();
#else
int touchY = touchEvent->points().first().position().y();
#endif
Sidebar::HandGestureHelper::getInstance()->callNotificationCenter(touchY);
return true;
}
break;
}
case QEvent::TouchEnd: {
auto *touchEvent = static_cast(event);
if (targetWindow(touchEvent) == this) {
m_isPressed = false;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
int touchX = touchEvent->touchPoints().first().pos().x();
int touchY = touchEvent->touchPoints().first().pos().y();
#else
int touchX = touchEvent->points().first().position().x();
int touchY = touchEvent->points().first().position().y();
#endif
Sidebar::HandGestureHelper::getInstance()->top2BottomRelease(touchX, touchY);
return true;
}
break;
}
case QEvent::MouseButtonPress: {
auto *mouseEvent = static_cast(event);
if (mouseEvent->button() == Qt::LeftButton) {
m_isPressed = true;
return true;
}
break;
}
case QEvent::MouseButtonRelease: {
auto *mouseEvent = static_cast(event);
if (mouseEvent->button() == Qt::LeftButton) {
m_isPressed = false;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
Sidebar::HandGestureHelper::getInstance()->top2BottomRelease(mouseEvent->x(), mouseEvent->y());
#else
Sidebar::HandGestureHelper::getInstance()->top2BottomRelease(
mouseEvent->position().x(), mouseEvent->position().y());
#endif
return true;
}
break;
}
case QEvent::MouseMove: {
if (m_isPressed) {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
Sidebar::HandGestureHelper::getInstance()->callNotificationCenter(static_cast(event)->y());
#else
Sidebar::HandGestureHelper::getInstance()->callNotificationCenter(dynamic_cast(event)->position().y());
#endif
return true;
}
break;
}
case QEvent::Expose: {
break;
}
case QEvent::Move: {
updateGeometry();
return true;
}
default:
break;
}
return QQuickWindow::event(event);
}
QWindow* StatusBarView::targetWindow(QTouchEvent* touchEvent)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
return touchEvent->window();
#else
if (const QWidget *targetWidget = qobject_cast(touchEvent->target())) {
return targetWidget->windowHandle();
}
return nullptr;
#endif
}
void StatusBarView::init()
{
setSource(QUrl("qrc:/qml/StatusBar.qml"));
}
ukui-sidebar/src/windows/notification-window.cpp 0000664 0001750 0001750 00000014400 15167606206 021054 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "notification-window.h"
#include "notification-model.h"
#include "sidebar-window-helper.h"
#include "hand-gesture-helper.h"
#include "global-settings.h"
#include "event-track.h"
#include
#include
#include
#include
#include
#include
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include
#else
#include
#endif
#include
static std::once_flag flag;
using namespace UkuiNotification;
class IsStoredFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit IsStoredFilterModel(QObject *parent = nullptr);
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
};
IsStoredFilterModel::IsStoredFilterModel(QObject *parent) : QSortFilterProxyModel(parent)
{
}
bool IsStoredFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
return idx.data(UkuiNotification::NotificationItem::IsStored).toBool();
}
NotificationGroupModel *NotificationCenterWindow::globalGroupModel()
{
static NotificationGroupModel groupModel;
std::call_once(flag, [&] {
auto filterModel = new IsStoredFilterModel(&groupModel);
filterModel->setSourceModel(NotificationModel::instance());
groupModel.setSourceModel(filterModel);
});
return &groupModel;
}
NotificationCenterWindow::NotificationCenterWindow(QWindow *parent) : SharedEngineView(parent)
{
setColor(Qt::transparent);
setResizeMode(SharedEngineView::SizeRootObjectToView);
setFlags(Qt::FramelessWindowHint);
m_windowProxy = new UkuiQuick::WindowProxy(this);
m_windowProxy->setWindowType(UkuiQuick::WindowType::SystemWindow);
rootContext()->setContextProperty("groupModel", NotificationCenterWindow::globalGroupModel());
rootContext()->setContextProperty("sourceModel", NotificationModel::instance());
rootContext()->setContextProperty("notificationWindow", this);
onPrimaryScreenChanged(qGuiApp->primaryScreen());
connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &NotificationCenterWindow::onPrimaryScreenChanged);
m_isTabletMode = Sidebar::GlobalSettings::globalInstance()->getValue(TABLET_MODE).toBool();
connect(Sidebar::GlobalSettings::globalInstance(), &Sidebar::GlobalSettings::valueChanged, this, [this] (const QString &key) {
if (key == TABLET_MODE) {
m_isTabletMode = Sidebar::GlobalSettings::globalInstance()->getValue(key).toBool();
if (!m_isTabletMode) {
callNotificationCenterEnd(0, 0);
}
}
});
connect(Sidebar::HandGestureHelper::getInstance(), &Sidebar::HandGestureHelper::notificationCenterCalled,
this, &NotificationCenterWindow::callNotificationCenter);
connect(Sidebar::HandGestureHelper::getInstance(), &Sidebar::HandGestureHelper::top2BottomReleased,
this, &NotificationCenterWindow::callNotificationCenterEnd);
}
void NotificationCenterWindow::init()
{
engine()->addImportPath("qrc:/qml");
setSource(QUrl("qrc:/qml/NotificationView.qml"));
}
bool NotificationCenterWindow::event(QEvent *event)
{
switch (event->type()) {
case QEvent::Expose: {
if (QX11Info::isPlatformX11()) {
requestActivate();
}
break;
}
default:
break;
}
return SharedEngineView::event(event);
}
void NotificationCenterWindow::updateGeometry()
{
if (!m_screen || m_screen->geometry().isEmpty()) {
return;
}
setGeometry(m_screen->geometry());
m_windowProxy->setPosition(m_screen->geometry().topLeft());
}
void NotificationCenterWindow::onPrimaryScreenChanged(QScreen *newScreen)
{
if (!newScreen) {
return;
}
if (m_screen) {
m_screen->disconnect(this);
}
m_screen = newScreen;
setScreen(m_screen);
updateGeometry();
connect(m_screen, &QScreen::geometryChanged, this, &NotificationCenterWindow::updateGeometry);
}
void NotificationCenterWindow::callNotificationCenter(int posY)
{
if (!rootObject() || !m_isTabletMode || m_contentVisible) {
return;
}
if (!isVisible()) {
QMetaObject::invokeMethod(rootObject(), "updateContentY", Qt::DirectConnection, Q_ARG(QVariant, -height()));
setVisible(true);
}
if (posY > height()) {
posY = height();
} else if (posY < 0) {
posY = 0;
}
posY -= height();
QMetaObject::invokeMethod(rootObject(), "updateContentY", Qt::DirectConnection, Q_ARG(QVariant, posY));
}
void NotificationCenterWindow::callNotificationCenterEnd(int posX, int posY)
{
Q_UNUSED(posX)
if (!isVisible()) {
return;
}
bool isShow = posY > (height() * 0.25);
QMetaObject::invokeMethod(rootObject(), "startAnimation", Qt::DirectConnection, Q_ARG(QVariant, isShow));
QVariantMap map;
map.insert("type", "slide");
Sidebar::EventTrack().sendSlideEvent("open_notification_center", "notificationCenter", map);
}
bool NotificationCenterWindow::contentVisible() const
{
return m_contentVisible;
}
void NotificationCenterWindow::setContentVisible(bool contentVisible)
{
m_contentVisible = contentVisible;
Q_EMIT contentVisibleChanged();
}
void NotificationCenterWindow::activeNotificationCenter(bool active)
{
if (active) {
callNotificationCenter(0);
callNotificationCenterEnd(0, height());
} else {
callNotificationCenterEnd(0, 0);
}
}
#include "notification-window.moc"
ukui-sidebar/src/windows/window-blur-helper.h 0000664 0001750 0001750 00000003317 15167643374 020270 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef WINDOWBLURHELPER_H
#define WINDOWBLURHELPER_H
#include
#include
namespace Sidebar {
class WindowBlurHelper : public QObject
{
Q_OBJECT
Q_PROPERTY(QWindow* window READ window WRITE setWindow)
Q_PROPERTY(bool enable READ enable WRITE setEnable)
//radius: 0-4000
Q_PROPERTY(quint32 radius READ radius WRITE setRadius NOTIFY radiusChanged)
public:
explicit WindowBlurHelper(QObject *parent = nullptr);
QWindow* window();
void setWindow(QWindow* window);
bool enable();
void setEnable(bool enable);
quint32 radius();
void setRadius(quint32 radius);
Q_INVOKABLE void setRegion(qreal x, qreal y, qreal w, qreal h, qreal radius);
private:
inline bool updateBlurArea();
void enableBlurBehind(WId window, bool enable, const QRegion ®ion, uint32_t radius);
private:
QWindow* m_window = nullptr;
QRegion m_region;
bool m_enable = false;
quint32 m_radius = 0;
Q_SIGNALS:
void radiusChanged();
};
}
#endif // WINDOWBLURHELPER_H
ukui-sidebar/src/windows/sidebar-window-helper.h 0000664 0001750 0001750 00000003215 15167643374 020732 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_SIDEBAR_WINDOW_HELPER_H
#define UKUI_SIDEBAR_SIDEBAR_WINDOW_HELPER_H
#include
#include
#include "window-type.h"
namespace Sidebar {
/**
* 1.管理不同平台设置geometry的接口
* 2.为某类型的窗口提供geometry属性
*/
class SidebarWindowHelper : public QObject
{
Q_OBJECT
public:
static SidebarWindowHelper *instance(QObject *parent = nullptr);
QRect getWindowGeometry(SidebarWindowType::Type type);
Qt::LayoutDirection getLayoutDirection();
Q_SIGNALS:
void geometryChanged();
private Q_SLOTS:
void updateRects();
private:
explicit SidebarWindowHelper(QObject *parent = nullptr);
private:
QRect m_statusBarRect;
QRect m_rightGestureRect;
QRect m_notificationCenterRect;
};
class SidebarWindowDefineModule
{
public:
static void defineModules(const char *uri, int versionMajor, int versionMinor);
};
} // Sidebar
#endif //UKUI_SIDEBAR_SIDEBAR_WINDOW_HELPER_H
ukui-sidebar/src/windows/shortcuts-window.cpp 0000664 0001750 0001750 00000035031 15167643374 020436 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "shortcuts-window.h"
#include "global-settings.h"
#include "shortcut-filter-model.h"
#include "shortcut-model.h"
#include "hand-gesture-helper.h"
#include "event-track.h"
#include "short-cut-manager.h"
#include "screen-monitor.h"
#include "account-information.h"
#include
#include
#include
#include
#include
#include
#include
#include
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
#include
#else
#include
#endif
#include
#include
#include
#include
#include
ShortcutsWindow::ShortcutsWindow(QWindow *parent) : SharedEngineView(parent)
{
// 窗口透明通道需要优先设置
setColor(Qt::transparent);
setResizeMode(UkuiQuick::SharedEngineView::SizeViewToRootObject);
// 去除标题栏等
//setFlags(flags() | Qt::FramelessWindowHint);
m_isTabletMode = Sidebar::GlobalSettings::globalInstance()->getValue(TABLET_MODE).toBool();
m_layoutDirection = QGuiApplication::layoutDirection();
m_windowProxy = new UkuiQuick::WindowProxy(this);
m_windowProxy->setWindowType(UkuiQuick::WindowType::SystemWindow);
m_screen = QGuiApplication::primaryScreen();
setScreen(m_screen);
connect(m_screen, &QScreen::geometryChanged, this, &ShortcutsWindow::updateGeometry, Qt::UniqueConnection);
// 加载数据
initUI();
initSettings();
// 信号
initConnections();
// 测试切换功能
//QPushButton *button = new QPushButton("hahahah");
//connect(button, &QPushButton::clicked, this, [this] {
// onTabletModeChanged();
//});
//button->resize(200, 100);
//button->show();
//KWindowSystem::setType(button->winId(), NET::ScreenLock);
}
void ShortcutsWindow::initUI()
{
// 上下文属性
auto editModel = new UkuiShortcut::ShortcutModel(this);
auto powerButton = new UkuiShortcut::PowerButton(this);
rootContext()->setContextProperty("editModel", editModel);
rootContext()->setContextProperty("powerButton", powerButton);
rootContext()->setContextProperty("mainWindow", this);
// 加载ui
engine()->addImportPath("qrc:///qml");
setSource(QUrl("qrc:///qml/Shortcuts.qml"));
updateEffects();
connect(editModel, &UkuiShortcut::ShortcutModel::requestExecAction, this, [this] (UkuiShortcut::PluginMetaType::PredefinedAction action) {
switch (action) {
default:
case UkuiShortcut::PluginMetaType::NoAction:
break;
case UkuiShortcut::PluginMetaType::Hide:
hide();
break;
}
});
}
void ShortcutsWindow::initSettings()
{
QStringList keys = Sidebar::GlobalSettings::globalInstance()->getKeys();
if (keys.contains(UKUI_PANEL_POSITION_KEY)) {
m_panelPos = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_PANEL_POSITION_KEY).toInt();
}
if (keys.contains(UKUI_PANEL_SIZE_KEY)) {
m_panelSize = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_PANEL_SIZE_KEY).toInt();
}
if (keys.contains(UKUI_PANEL_TYPE_KEY)) {
m_panelType = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_PANEL_TYPE_KEY).toInt();
}
if (keys.contains(UKUI_SETTINGS_ISLAND_POSITION_KEY)) {
m_settingsIslandPosition = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_SETTINGS_ISLAND_POSITION_KEY).toInt();
}
if (keys.contains(UKUI_TOPBAR_SIZE_KEY)) {
m_topbarSize = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_TOPBAR_SIZE_KEY).toInt();
}
}
void ShortcutsWindow::initConnections()
{
// 信号
connect(Sidebar::GlobalSettings::globalInstance(), &Sidebar::GlobalSettings::valueChanged, this, [this] (const QString &key) {
if (key == UKUI_PANEL_POSITION_KEY) {
m_panelPos = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_PANEL_POSITION_KEY).toInt();
Q_EMIT panelPosChanged();
updateGeometry();
} else if (key == UKUI_PANEL_SIZE_KEY) {
m_panelSize = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_PANEL_SIZE_KEY).toInt();
updateGeometry();
} else if (key == UKUI_PANEL_TYPE_KEY) {
m_panelType = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_PANEL_TYPE_KEY).toInt();
updateGeometry();
} else if (key == UKUI_SETTINGS_ISLAND_POSITION_KEY) {
m_settingsIslandPosition = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_SETTINGS_ISLAND_POSITION_KEY).toInt();
updateGeometry();
} else if (key == UKUI_TOPBAR_SIZE_KEY) {
m_topbarSize = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_TOPBAR_SIZE_KEY).toInt();
updateGeometry();
} else if (key == UKUI_PANEL_LENGTH_KEY) {
updateGeometry();
} else if (key == TABLET_MODE) {
onTabletModeChanged();
}
});
connect(Sidebar::ScreenMonitor::getInstance(), &Sidebar::ScreenMonitor::screenRemoved, this, [&](QScreen *screen) {
if(screen == m_screen) {
activeShortcutsWindow(false);
}
}, Qt::UniqueConnection);
// 失焦退出
connect(this, &QQuickWindow::activeFocusItemChanged, this, [this] {
if (!activeFocusItem()) {
activeShortcutsWindow(false);
}
});
//布局方向
connect(qGuiApp, &QGuiApplication::layoutDirectionChanged, this, [this] {
m_layoutDirection = QGuiApplication::layoutDirection();
});
connect(this, &QWindow::widthChanged, this, &ShortcutsWindow::updateGeometry);
connect(this, &QWindow::heightChanged, this, &ShortcutsWindow::updateGeometry);
}
void ShortcutsWindow::updateGeometry()
{
if (!m_screen || m_screen->geometry().isEmpty()) {
return;
}
QRect newGeometry;
if (m_isTabletMode) {
newGeometry = m_screen->geometry();
} else {
int margin = windowMargin();
//QRect rect = screen()->availableGeometry();
QRect rect = m_screen->geometry();
QPoint point;
UkuiQuick::WindowProxy::SlideFromEdge slideFromEdge = UkuiQuick::WindowProxy::NoEdge;
if (m_panelType == 1) {
//三岛任务栏
if (m_settingsIslandPosition == 0) {
if (m_layoutDirection == Qt::LayoutDirection::RightToLeft) {
point.setX(rect.left() +
(rect.width() - Sidebar::GlobalSettings::globalInstance()->getPanelLength(m_screen->name()))/2);
} else {
point.setX(rect.right() -
(rect.width() - Sidebar::GlobalSettings::globalInstance()->getPanelLength(m_screen->name()))/2 - width());
}
point.setY(rect.bottom() - height() - margin - m_panelSize);
slideFromEdge = UkuiQuick::WindowProxy::BottomEdge;
} else if (m_settingsIslandPosition == 1) {
if (m_layoutDirection == Qt::LayoutDirection::RightToLeft) {
point.setX(rect.left() + margin);
} else {
point.setX(rect.right() - width() - margin);
}
point.setY(rect.top() + margin + m_topbarSize);
slideFromEdge = UkuiQuick::WindowProxy::TopEdge;
}
} else {
// 上: 1, 下: 0, 左: 2, 右: 3
switch (m_panelPos) {
default:
case 0:
if (m_layoutDirection == Qt::LayoutDirection::RightToLeft) {
point.setX(rect.left() + margin);
} else {
point.setX(rect.right() - width() - margin);
}
point.setY(rect.bottom() - height() - margin - m_panelSize);
slideFromEdge = UkuiQuick::WindowProxy::BottomEdge;
break;
case 1:
if (m_layoutDirection == Qt::LayoutDirection::RightToLeft) {
point.setX(rect.left() + margin);
} else {
point.setX(rect.right() - width() - margin);
}
point.setY(rect.top() + margin + m_panelSize);
slideFromEdge = UkuiQuick::WindowProxy::TopEdge;
break;
case 2:
point.setX(rect.left() + margin + m_panelSize);
point.setY(rect.bottom() - height() - margin);
slideFromEdge = UkuiQuick::WindowProxy::LeftEdge;
break;
case 3:
point.setX(rect.right() - width() - margin - m_panelSize);
point.setY(rect.bottom() - height() - margin);
slideFromEdge = UkuiQuick::WindowProxy::RightEdge;
break;
}
}
QRect geometry(point, ShortcutsWindow::size());
if (rootObject()) {
geometry.setSize(rootObject()->size().toSize());
}
newGeometry = geometry;
m_windowProxy->slideWindow(slideFromEdge, 0);
}
if (newGeometry.isEmpty()) return;
setGeometry(newGeometry);
if (m_position != newGeometry.topLeft()) {
m_position = newGeometry.topLeft();
m_windowProxy->setPosition(m_position);
Q_EMIT positionChanged();
}
}
bool ShortcutsWindow::event(QEvent *event)
{
switch (event->type()) {
case QEvent::Show:
if (QX11Info::isPlatformX11()) {
requestActivate();
}
break;
default:
break;
}
return SharedEngineView::event(event);
}
bool ShortcutsWindow::isTabletMode() const
{
return m_isTabletMode;
}
int ShortcutsWindow::windowMargin() const
{
return 8;
}
int ShortcutsWindow::panelPos() const
{
return m_panelPos;
}
QString ShortcutsWindow::currentId() const
{
return m_currentId;
}
void ShortcutsWindow::setCurrentId(QString currentId)
{
if (m_currentId == currentId) return;
m_currentId = currentId;
Q_EMIT currentIdChanged();
}
void ShortcutsWindow::onTabletModeChanged()
{
//bool toTabletMode = !m_isTabletMode;
bool toTabletMode = Sidebar::GlobalSettings::globalInstance()->getValue(TABLET_MODE).toBool();
if (toTabletMode) {
activeShortcutsWindow(false);
} else {
hide();
}
m_isTabletMode = toTabletMode;
updateEffects();
Q_EMIT tabletModeChanged();
}
void ShortcutsWindow::updateEffects()
{
setResizeMode(m_isTabletMode ? SizeRootObjectToView : SizeViewToRootObject);
updateGeometry();
Sidebar::HandGestureHelper::getInstance()->disconnect(this);
if (m_isTabletMode) {
//KWindowEffects::slideWindow(this, KWindowEffects::NoEdge);
connect(Sidebar::HandGestureHelper::getInstance(),&Sidebar::HandGestureHelper::controlCenterCalled,
this, &ShortcutsWindow::moveShortcutPanel);
connect(Sidebar::HandGestureHelper::getInstance(), &Sidebar::HandGestureHelper::right2LeftReleased,
this, &ShortcutsWindow::onRight2LeftReleased);
} else {
setBlurStrength();
}
}
void ShortcutsWindow::moveShortcutPanel(int posX)
{
if (!rootObject()) {
return;
}
if (!isVisible()) {
QMetaObject::invokeMethod(rootObject(), "initTabletProp", Qt::DirectConnection);
show();
}
int dx = (m_layoutDirection == Qt::LayoutDirection::RightToLeft)
? posX
: geometry().right() - posX;
QMetaObject::invokeMethod(rootObject(), "moveShortcutPanel", Qt::DirectConnection, Q_ARG(QVariant, (dx < 0 ? 0 : dx)));
}
void ShortcutsWindow::onRight2LeftReleased(int posX, int posY)
{
Q_UNUSED(posY)
if (rootObject()) {
int dx = (m_layoutDirection == Qt::LayoutDirection::RightToLeft)
? posX : geometry().right() - posX;
bool active = (dx >= geometry().width() * 0.05);
QMetaObject::invokeMethod(rootObject(), "activePanelOnTablet", Qt::DirectConnection, Q_ARG(QVariant, active));
if (active) {
QVariantMap map;
map.insert("type", "slide");
Sidebar::EventTrack::instance()->sendSlideEvent("open_sidebar", "sidebar", map);
}
}
}
void ShortcutsWindow::setBlurStrength(quint32 strength)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
KWindowEffects::enableBlurBehindWithStrength(this, true, QRegion(), strength);
#else
KWindowEffects::enableBlurBehind(this, true);
#endif
}
void ShortcutsWindow::activeShortcutsWindow(bool active)
{
if (!rootObject()) {
hide();
return;
}
if (active == isVisible()) {
return;
}
if (m_isTabletMode) {
if (active) {
QMetaObject::invokeMethod(rootObject(), "initTabletProp", Qt::DirectConnection);
show();
}
QMetaObject::invokeMethod(rootObject(), "activePanelOnTablet", Qt::DirectConnection, Q_ARG(QVariant, active));
} else {
if (active) {
if (m_screen != UkuiQuick::WindowProxy::currentScreen()) {
if (m_screen) {
m_screen->disconnect(this);
}
m_screen = UkuiQuick::WindowProxy::currentScreen();
this->setScreen(m_screen);
connect(m_screen, &QScreen::geometryChanged, this, &ShortcutsWindow::updateGeometry, Qt::UniqueConnection);
updateGeometry();
}
} else {
backToShortcuts();
}
setVisible(active);
}
}
bool ShortcutsWindow::requestMenuWidget(QString widgetId, bool showReturnButton)
{
QPair pair = UkuiShortcut::ShortcutManager::getInstance()->getWidgetInfo(widgetId);
if (pair.first) {
Q_EMIT showMenuWidget(widgetId, showReturnButton, pair.second);
return true;
}
return false;
}
void ShortcutsWindow::backToShortcuts()
{
Q_EMIT hideMenuWidget();
}
ukui-sidebar/src/windows/tablet-popup-view.cpp 0000664 0001750 0001750 00000021713 15167643374 020461 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "tablet-popup-view.h"
#include "notification-model.h"
#include "global-settings.h"
#include "date-time-utils.h"
#include "color-helper.h"
#include "notification-group-model.h"
#include "group-cache-proxy-model.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class NotificationFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit NotificationFilterModel(QObject *parent = nullptr);
void setSourceModel(QAbstractItemModel *sourceModel) override;
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
private:
bool m_isTabletMode = true;
};
NotificationFilterModel::NotificationFilterModel(QObject *parent) : QSortFilterProxyModel(parent)
{
m_isTabletMode = Sidebar::GlobalSettings::globalInstance()->getValue(TABLET_MODE).toBool();
connect(Sidebar::GlobalSettings::globalInstance(), &Sidebar::GlobalSettings::valueChanged, this, [this] (const QString &key) {
if (key == TABLET_MODE) {
m_isTabletMode = Sidebar::GlobalSettings::globalInstance()->getValue(key).toBool();
invalidateFilter();
}
});
}
void NotificationFilterModel::setSourceModel(QAbstractItemModel *sourceModel)
{
if (QSortFilterProxyModel::sourceModel()) {
QSortFilterProxyModel::sourceModel()->disconnect(this);
}
QSortFilterProxyModel::setSourceModel(sourceModel);
if (sourceModel) {
connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &NotificationFilterModel::invalidateFilter);
connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, &NotificationFilterModel::invalidateFilter);
}
}
bool NotificationFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (!sourceModel() || !m_isTabletMode) {
return false;
}
QModelIndex idx = sourceModel()->index(source_row, 0, source_parent);
bool isStored = idx.data(UkuiNotification::NotificationItem::IsStored).toBool();
// bool isExpired = idx.data(UkuiNotification::NotificationItem::IsExpired).toBool();
return !isStored;
}
class TabletNotificationModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit TabletNotificationModel(QObject *parent = nullptr);
void setSourceModel(QAbstractItemModel *sourceModel) override;
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
QSet m_readMsg;
};
TabletNotificationModel::TabletNotificationModel(QObject *parent) : QSortFilterProxyModel(parent) {}
void TabletNotificationModel::setSourceModel(QAbstractItemModel *sourceModel)
{
if (QSortFilterProxyModel::sourceModel()) {
QSortFilterProxyModel::sourceModel()->disconnect(this);
}
QSortFilterProxyModel::setSourceModel(sourceModel);
if (sourceModel) {
connect(sourceModel, &QAbstractItemModel::rowsInserted, this, [this] (const QModelIndex &parent, int first, int last) {
invalidateFilter();
for (int i = first; i <= last; ++i) {
m_readMsg.insert(QSortFilterProxyModel::sourceModel()->index(i, 0, parent).data(UkuiNotification::NotificationItem::Id).toUInt());
}
});
connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, [this] (const QModelIndex &parent, int first, int last) {
invalidateFilter();
for (int i = first; i <= last; ++i) {
m_readMsg.remove(QSortFilterProxyModel::sourceModel()->index(i, 0, parent).data(UkuiNotification::NotificationItem::Id).toUInt());
}
});
}
}
bool TabletNotificationModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
uint id = sourceModel()->index(source_row, 0, source_parent).data(UkuiNotification::NotificationItem::Id).toUInt();
return !m_readMsg.contains(id) && (source_row == (sourceModel()->rowCount() - 1));
}
// =====TabletPopupView==
UkuiNotification::TabletPopupView::TabletPopupView(QWindow *parent) : SharedEngineView(parent)
{
setColor(Qt::transparent);
setResizeMode(SharedEngineView::SizeRootObjectToView);
setFlags(Qt::FramelessWindowHint);
m_windowProxy = new UkuiQuick::WindowProxy(this);
m_windowProxy->setWindowType(UkuiQuick::WindowType::Notification);
new UkuiQuick::WindowProxy(this, UkuiQuick::WindowProxy::SkipTaskBar | UkuiQuick::WindowProxy::SkipSwitcher);
qmlRegisterType("org.ukui.notification.model", 1, 0, "GroupCacheProxyModel");
onPrimaryScreenChanged(qGuiApp->primaryScreen());
connect(qGuiApp, &QGuiApplication::primaryScreenChanged, this, &TabletPopupView::onPrimaryScreenChanged);
auto filterModel = new NotificationFilterModel(this);
filterModel->setSourceModel(NotificationModel::instance());
// auto model = new TabletNotificationModel(this);
// model->setSourceModel(filterModel);
auto group = new NotificationGroupModel(this);
group->setSourceModel(filterModel);
setVisible(group->rowCount(QModelIndex()) > 0);
connect(group, &TabletNotificationModel::rowsInserted, this, [this, group] {
setVisible(group->rowCount(QModelIndex()) > 0);
});
// connect(group, &TabletNotificationModel::rowsRemoved, this, [this, group] {
// qDebug() << "==rowsRemoved==" << group << group->rowCount(QModelIndex());
// setVisible(group->rowCount(QModelIndex()) > 0);
// });
rootContext()->setContextProperty("tabletPopupView", this);
// rootContext()->setContextProperty("notificationModel", model);
rootContext()->setContextProperty("groupModel", group);
rootContext()->setContextProperty("sourceModel", NotificationModel::instance());
init();
}
void UkuiNotification::TabletPopupView::init()
{
engine()->addImportPath("qrc:/qml");
setSource(QUrl("qrc:/qml/TabletPopupView.qml"));
}
void UkuiNotification::TabletPopupView::onPrimaryScreenChanged(QScreen *newScreen)
{
if (!newScreen) {
return;
}
if (m_screen) {
m_screen->disconnect(this);
}
m_screen = newScreen;
setScreen(m_screen);
connect(m_screen, &QScreen::geometryChanged, this, &TabletPopupView::onScreenGeometryChanged);
onScreenGeometryChanged();
}
void UkuiNotification::TabletPopupView::onScreenGeometryChanged()
{
int screenWidth = m_screen->geometry().width();
m_windowWidth = static_cast(screenWidth * 0.45);
m_topLeft.setX(m_screen->geometry().x() + ((screenWidth - m_windowWidth) / 2));
m_topLeft.setY(m_screen->geometry().y() + m_windowMargin);
Q_EMIT windowWidthChanged();
updateGeometry();
}
void UkuiNotification::TabletPopupView::updateGeometry()
{
QRect geometry = QRect(m_topLeft, QSize(m_windowWidth, height()));
if (geometry.isEmpty()) return;
setGeometry(geometry);
m_windowProxy->setPosition(m_topLeft);
}
bool UkuiNotification::TabletPopupView::event(QEvent *event)
{
switch (event->type()) {
case QEvent::Show:
case QEvent::Expose: {
break;
}
default:
break;
}
return SharedEngineView::event(event);
}
int UkuiNotification::TabletPopupView::windowWidth() const
{
return m_windowWidth;
}
void UkuiNotification::TabletPopupView::enableWindowBlur(int radius, bool enable)
{
QPainterPath path;
path.addRoundedRect(0, 0, width(), height(), radius, radius);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
KWindowEffects::enableBlurBehindWithStrength(this, enable, QRegion(path.toFillPolygon().toPolygon()), 800);
#else
KWindowEffects::enableBlurBehind(this, enable, QRegion(path.toFillPolygon().toPolygon()));
#endif
}
int UkuiNotification::TabletPopupView::windowMaxHeight() const
{
if (m_screen) {
return m_screen->geometry().height() - m_windowMargin*2;
}
return 1;
}
void UkuiNotification::TabletPopupView::updateHeight(int height)
{
if (height < 1) {
height = 1;
}
int h = height > windowMaxHeight() ? windowMaxHeight() : height;
if (h == TabletPopupView::height()) {
return;
}
setHeight(h);
}
bool UkuiNotification::TabletPopupView::enableAnimation() const
{
return m_enableAnimation;
}
#include "tablet-popup-view.moc"
ukui-sidebar/src/windows/right-hand-gesture-view.cpp 0000664 0001750 0001750 00000014002 15167643374 021537 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Author: hxf
*
*/
#include "right-hand-gesture-view.h"
#include
#include "sidebar-window-helper.h"
#include "hand-gesture-helper.h"
#include "global-settings.h"
#include "settings.h"
namespace Sidebar {
RightHandGestureView::RightHandGestureView(QWindow *parent) : SharedEngineView(parent)
{
setColor("transparent");
setResizeMode(SharedEngineView::SizeRootObjectToView);
setFlags(Qt::WindowDoesNotAcceptFocus | Qt::FramelessWindowHint);
m_windowProxy = new UkuiQuick::WindowProxy(this);
m_windowProxy->setWindowType(UkuiQuick::Settings::instance()->platformName() == "wayland" ?
UkuiQuick::WindowType::Switcher : UkuiQuick::WindowType::SystemWindow);
updateGeometry();
connect(SidebarWindowHelper::instance(), &SidebarWindowHelper::geometryChanged, this, &RightHandGestureView::updateGeometry);
connect(GlobalSettings::globalInstance(), &GlobalSettings::valueChanged, this, [this] (const QString &key) {
if (key == TABLET_MODE && m_isPressed) {
m_isPressed = false;
}
});
}
void RightHandGestureView::init()
{
setSource(QUrl("qrc:/qml/Right2LeftSwipe.qml"));
show();
}
void RightHandGestureView::updateGeometry()
{
QRect geometry = windowGeometry();
if (geometry.isEmpty()) return;
setGeometry(geometry);
m_windowProxy->setPosition(geometry.topLeft());
}
bool RightHandGestureView::event(QEvent *event)
{
switch (event->type()) {
case QEvent::TouchBegin: {
auto *touchEvent = static_cast(event);
if (targetWindow(touchEvent) == this) {
m_isPressed = true;
return true;
}
break;
}
case QEvent::TouchUpdate: {
auto *touchEvent = static_cast(event);
if (targetWindow(touchEvent) == this && m_isPressed) {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
int touchX = touchEvent->touchPoints().first().pos().x();
#else
const int touchX = touchEvent->points().first().position().x();
#endif
callControlCenter(touchX);
return true;
}
break;
}
case QEvent::TouchEnd: {
auto *touchEvent = static_cast(event);
if (targetWindow(touchEvent) == this) {
m_isPressed = false;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
int touchX = touchEvent->touchPoints().first().pos().x();
int touchY = touchEvent->touchPoints().first().pos().y();
#else
const int touchX = touchEvent->points().first().position().x();
const int touchY = touchEvent->points().first().position().y();
#endif
callControlCenterEnd(touchX, touchY);
return true;
}
break;
}
case QEvent::MouseButtonPress: {
auto *mouseEvent = static_cast(event);
if (mouseEvent->button() == Qt::LeftButton) {
m_isPressed = true;
return true;
}
break;
}
case QEvent::MouseButtonRelease: {
auto *mouseEvent = static_cast(event);
if (mouseEvent->button() == Qt::LeftButton) {
m_isPressed = false;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
callControlCenterEnd(mouseEvent->x(), mouseEvent->y());
#else
callControlCenterEnd(mouseEvent->position().x(), mouseEvent->position().y());
#endif
return true;
}
break;
}
case QEvent::MouseMove: {
if (m_isPressed) {
callControlCenter(dynamic_cast(event)->position().x());
return true;
}
break;
}
case QEvent::Expose: {
break;
}
case QEvent::Move: {
updateGeometry();
return true;
}
default:
break;
}
return QQuickWindow::event(event);
}
void RightHandGestureView::callControlCenter(int x)
{
int right;
if (SidebarWindowHelper::instance()->getLayoutDirection() == Qt::LayoutDirection::RightToLeft) {
if (x < 12) {
return;
}
right = x - 12;
} else {
if (x > -12) {
return;
}
right = windowGeometry().x() + x + 12;
}
HandGestureHelper::getInstance()->callControlCenter(right);
}
void RightHandGestureView::callControlCenterEnd(int x, int y)
{
int posX = (SidebarWindowHelper::instance()->getLayoutDirection() == Qt::LayoutDirection::RightToLeft)
? x - 12
: windowGeometry().x() + x + 12;
int posY = windowGeometry().y() + y + 12;
HandGestureHelper::getInstance()->right2LeftRelease(posX, posY);
}
QWindow* RightHandGestureView::targetWindow(QTouchEvent* touchEvent)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
return touchEvent->window();
#else
if (const QWidget *targetWidget = qobject_cast(touchEvent->target())) {
return targetWidget->windowHandle();
}
return nullptr;
#endif
}
QRect RightHandGestureView::windowGeometry()
{
return SidebarWindowHelper::instance()->getWindowGeometry(SidebarWindowType::RightHandGesture);
}
} // Sidebar
ukui-sidebar/src/windows/popup-notification-window.cpp 0000664 0001750 0001750 00000027213 15167643374 022232 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "global-settings.h"
#include "popup-notification-window.h"
#include "notification-group-model.h"
#include "notification-model.h"
#include "screen-monitor.h"
#include "popup-notification-model.h"
using namespace UkuiNotification;
PopupNotificationWindow::PopupNotificationWindow(QWindow *parent) : SharedEngineView(parent)
{
initWindow();
initNotificationModel();
}
void PopupNotificationWindow::initWindow()
{
setResizeMode(SharedEngineView::SizeViewToRootObject);
setFlags(Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
setColor("transparent");
m_screenLockState = Sidebar::ScreenMonitor::getInstance()->getScreenLockState();
m_windowProxy = new UkuiQuick::WindowProxy(this);
// m_windowProxy->setWindowType(m_screenLockState ? UkuiQuick::WindowType::ScreenLockNotification : UkuiQuick::WindowType::Notification);
m_windowProxy->setWindowType(UkuiQuick::WindowType::ScreenLockNotification);
Q_EMIT screenLockStatehChanged();
// 监听窗口尺寸变化,屏幕变化
onPrimaryScreenChanged(Sidebar::ScreenMonitor::getInstance()->getPrimaryScreen());
connect(Sidebar::ScreenMonitor::getInstance(), &Sidebar::ScreenMonitor::primaryScreenChanged, this, [this] {
onPrimaryScreenChanged(Sidebar::ScreenMonitor::getInstance()->getPrimaryScreen());
});
connect(Sidebar::ScreenMonitor::getInstance(), &Sidebar::ScreenMonitor::panelPropertyChanged, this, &PopupNotificationWindow::updateGeometry);
connect(Sidebar::ScreenMonitor::getInstance(), &Sidebar::ScreenMonitor::layoutDirectionChanged, this, &PopupNotificationWindow::updateGeometry);
connect(Sidebar::ScreenMonitor::getInstance(), &Sidebar::ScreenMonitor::screenLockStateChanged, this, [this] (bool state) {
if (m_screenLockState != state) {
// m_windowProxy->setWindowType(state ? UkuiQuick::WindowType::ScreenLockNotification : UkuiQuick::WindowType::Notification);
m_screenLockState = state;
Q_EMIT screenLockStatehChanged();
}
});
connect(Sidebar::GlobalSettings::globalInstance(), &Sidebar::GlobalSettings::valueChanged, this, [this] (const QString &key) {
if (key == UKUI_PANEL_TYPE_KEY || key == UKUI_SETTINGS_ISLAND_POSITION_KEY ||
key == UKUI_DATA_ISLAND_POSITION_KEY || key == UKUI_TOPBAR_SIZE_KEY ) {
updateGeometry();
}
});
}
void PopupNotificationWindow::initNotificationModel()
{
auto popupFilterModel = new PopupNotificationModel(this);
popupFilterModel->setSourceModel(NotificationModel::instance());
auto groupModel = new NotificationGroupModel(this);
groupModel->setSourceModel(popupFilterModel);
rootContext()->setContextProperty("groupModel", groupModel);
rootContext()->setContextProperty("sourceModel", NotificationModel::instance());
rootContext()->setContextProperty("popupNotificationWindow", this);
connect(groupModel, &QAbstractItemModel::rowsInserted, groupModel, [this, groupModel] {
setVisible(groupModel->rowCount(QModelIndex()) > 0);
});
connect(groupModel, &QAbstractItemModel::rowsRemoved, groupModel, [this, groupModel] {
setVisible(groupModel->rowCount(QModelIndex()) > 0);
});
}
void PopupNotificationWindow::loadQML()
{
engine()->addImportPath("qrc:/qml");
setSource(QUrl("qrc:/qml/PopupView.qml"));
if (rootObject()) {
m_viewWidth = rootObject()->width();
connect(rootObject(), &QQuickItem::widthChanged, this, &PopupNotificationWindow::onRootWidthChanged);
}
}
void PopupNotificationWindow::updateGeometry()
{
if (m_viewWidth <= 0) {
return;
}
QRect screenRect = m_screen->geometry();
if (screenRect.isEmpty()) return;
Sidebar::ScreenMonitor *screenMonitor = Sidebar::ScreenMonitor::getInstance();
bool isMirrored = screenMonitor->getLayoutDirection() == Qt::LayoutDirection::RightToLeft;
int panelSize = screenMonitor->getPanelSize();
int panelPosition = screenMonitor->getPanelPosition();
int panelType = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_PANEL_TYPE_KEY).toInt();
int dataIslandPosition = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_DATA_ISLAND_POSITION_KEY).toInt();
int settingsIslandPosition = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_SETTINGS_ISLAND_POSITION_KEY).toInt();
int topbarSize = Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_TOPBAR_SIZE_KEY).toInt();
int margin = 0;
int maxWindowHeight;
if (panelType == 1) {
if (dataIslandPosition == 1 || settingsIslandPosition == 1) {
m_notificationPoint = QPoint(isMirrored ?
margin : screenRect.width() - m_viewWidth - margin,
margin + topbarSize);
maxWindowHeight = screenRect.height() - panelSize - -topbarSize - margin * 2;
} else {
m_notificationPoint = QPoint(isMirrored ?
margin : screenRect.width() - m_viewWidth - margin,
margin);
maxWindowHeight = screenRect.height() - panelSize - margin * 2;
}
} else {
switch(panelPosition) {
default:
case 0: {
m_notificationPoint = QPoint(isMirrored ?
margin : screenRect.width() - m_viewWidth - margin,
margin);
maxWindowHeight = screenRect.height() - panelSize - margin * 2;
break;
}
case 1: {
m_notificationPoint = QPoint(isMirrored ?
margin : screenRect.width() - m_viewWidth - margin,
margin + panelSize);
maxWindowHeight = screenRect.height() - panelSize - margin * 2;
break;
}
case 2: {
m_notificationPoint = QPoint(isMirrored ?
margin + panelSize : screenRect.width() - m_viewWidth - margin,
margin);
maxWindowHeight = screenRect.height() - margin * 2;
break;
}
case 3: {
m_notificationPoint = QPoint(isMirrored ?
margin : screenRect.width() - m_viewWidth - margin - panelSize,
margin);
maxWindowHeight = screenRect.height() - margin * 2;
break;
}
}
}
if (maxWindowHeight <= 0) return;
setMaximumHeight(maxWindowHeight);
// 多屏状态下,坐标位置确定
m_notificationPoint.setX(m_notificationPoint.x() + screenRect.x());
m_notificationPoint.setY(m_notificationPoint.y() + screenRect.y());
if (m_needDisplace) {
if (isMirrored) {
m_notificationPoint.setX(m_notificationPoint.x() + m_sidebarWidth);
} else {
m_notificationPoint.setX(m_notificationPoint.x() - m_sidebarWidth);
}
}
m_windowProxy->setPosition(m_notificationPoint);
}
void PopupNotificationWindow::updataWindowRegion(QVariantMap windowRect, int contentY)
{
QVariantList groupsRect = windowRect.value("regions").toList();
QRegion windowRegion;
int nextGroupsY = 0;
for (int i = 0; i < groupsRect.length(); i ++) {
int count = groupsRect.at(i).toMap().value("count").toInt();
int height = groupsRect.at(i).toMap().value("height").toInt();
int width = groupsRect.at(i).toMap().value("width").toInt();
int radius = groupsRect.at(i).toMap().value("radius").toInt();
int spacing = 8;
int groupsRightBottom = 0;
QRegion childRegion;
QPainterPath path;
path.addRoundedRect(0, 0, width, height, radius, radius);
QRegion groupsRegion = QRegion(path.toFillPolygon().toPolygon());
if (count == 1) {
childRegion = groupsRegion;
groupsRightBottom = height;
} else if (count == 2) {
path.addRoundedRect((0.05 * width) / 2, spacing, width * 0.95, height, radius, radius);
QRegion folderRegion = QRegion(path.toFillPolygon().toPolygon());
childRegion = groupsRegion.united(folderRegion);
groupsRightBottom = height + spacing;
} else if (count > 2) {
path.addRoundedRect((0.05 * width) / 2, spacing, width * 0.95, height, radius, radius);
QRegion folderRegion = QRegion(path.toFillPolygon().toPolygon());
path.addRoundedRect((0.0975 * width) / 2, spacing * 2, width * 0.9025, height, radius, radius);
QRegion secondFolderRegion = QRegion(path.toFillPolygon().toPolygon());
childRegion = groupsRegion.united(folderRegion).united(secondFolderRegion);
groupsRightBottom = height + spacing * 2;
}
if (i > 0) {
childRegion.translate(0, nextGroupsY);
}
nextGroupsY = nextGroupsY + groupsRightBottom + spacing;
windowRegion = windowRegion.united(childRegion);
}
m_windowRegion = windowRegion.translated(0, -contentY);
enableWindowBlur(m_enable);
}
void PopupNotificationWindow::updataGroupsPosition(int relativeY)
{
m_windowRegion.translate(QPoint(0, -relativeY));
}
void PopupNotificationWindow::enableWindowBlur(bool enable)
{
m_enable = enable;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
KWindowEffects::enableBlurBehindWithStrength(this, m_enable, m_windowRegion, 800);
#else
KWindowEffects::enableBlurBehind(this, m_enable, m_windowRegion);
#endif
}
void PopupNotificationWindow::updatePopupWindowGeometry(bool needDisplace, int sidebarWidth)
{
if (m_needDisplace == needDisplace && m_sidebarWidth == sidebarWidth) {
return;
}
m_needDisplace = needDisplace;
m_sidebarWidth = sidebarWidth;
updateGeometry();
}
bool PopupNotificationWindow::event(QEvent *event)
{
return SharedEngineView::event(event);
}
void PopupNotificationWindow::onPrimaryScreenChanged(QScreen *newScreen)
{
if (!newScreen) {
return;
}
if (m_screen) {
m_screen->disconnect(this);
}
m_screen = newScreen;
setScreen(m_screen);
updateGeometry();
connect(m_screen, &QScreen::geometryChanged, this, &PopupNotificationWindow::updateGeometry);
}
void PopupNotificationWindow::onRootWidthChanged()
{
if (rootObject()->width() == m_viewWidth) {
return;
}
m_viewWidth = rootObject()->width();
updateGeometry();
}
int PopupNotificationWindow::viewWidth() const
{
return m_viewWidth;
}
int PopupNotificationWindow::itemWidth() const
{
return m_itemWidth;
}
bool PopupNotificationWindow::screenLockState() const
{
return m_screenLockState;
}
ukui-sidebar/src/notification/ 0000775 0001750 0001750 00000000000 15167643374 015361 5 ustar feng feng ukui-sidebar/src/notification/popup-notification-model.cpp 0000664 0001750 0001750 00000004102 15167606206 023000 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "popup-notification-model.h"
#include "notification-model.h"
#include "global-settings.h"
#include "screen-monitor.h"
using namespace UkuiNotification;
PopupNotificationModel::PopupNotificationModel(QObject *parent) : QSortFilterProxyModel(parent)
{
m_isTabletMode = Sidebar::GlobalSettings::globalInstance()->getValue(TABLET_MODE).toBool();
connect(Sidebar::GlobalSettings::globalInstance(), &Sidebar::GlobalSettings::valueChanged, this, [this] (const QString &key) {
if (key == TABLET_MODE) {
m_isTabletMode = Sidebar::GlobalSettings::globalInstance()->getValue(key).toBool();
invalidateFilter();
}
});
connect(Sidebar::ScreenMonitor::getInstance(), &Sidebar::ScreenMonitor::screenLockStateChanged, this, [this] (bool state) {
if (m_screenLockState != state) {
m_screenLockState = state;
invalidateFilter();
}
});
}
bool PopupNotificationModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
if (m_isTabletMode) {
return false;
}
const QModelIndex modelIndex = sourceModel()->index(sourceRow, 0, sourceParent);
if (m_screenLockState) {
return !modelIndex.data(NotificationItem::IsStored).toBool() && modelIndex.data(NotificationItem::ShowOnLockScreen).toBool();
}
return !modelIndex.data(NotificationItem::IsStored).toBool();
}
ukui-sidebar/src/notification/notification-utils.cpp 0000664 0001750 0001750 00000004252 15167606206 021705 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "notification-utils.h"
#include
using namespace UkuiNotification;
NotificationAction::NotificationAction(bool e, bool d, int index, Mode mode, QString icon, QString name, QString state)
: m_enable(e), m_default(d), m_index(index), m_mode(mode), m_icon(std::move(icon)), m_name(std::move(name)), m_state(std::move(state))
{
}
bool NotificationAction::isEnable() const
{
return m_enable;
}
bool NotificationAction::isDefault() const
{
return m_default;
}
void NotificationAction::setEnable(bool e)
{
m_enable = e;
}
void NotificationAction::setDefault(bool d)
{
m_default = d;
}
int NotificationAction::index() const
{
return m_index;
}
NotificationAction::Mode NotificationAction::mode() const
{
return m_mode;
}
QString NotificationAction::icon() const
{
return m_icon;
}
QString NotificationAction::name() const
{
return m_name;
}
QString NotificationAction::state() const
{
return m_state;
}
void NotificationAction::setIndex(int index)
{
m_index = index;
}
void NotificationAction::setMode(NotificationAction::Mode mode)
{
m_mode = mode;
}
void NotificationAction::setIcon(const QString &icon)
{
m_icon = icon;
}
void NotificationAction::setName(const QString &name)
{
m_name = name;
}
void NotificationAction::setState(const QString &state)
{
m_state = state;
}
QString NotificationAction::action() const
{
return m_action;
}
void NotificationAction::setAction(const QString &action)
{
m_action = action;
}
ukui-sidebar/src/notification/group-cache-proxy-model.h 0000664 0001750 0001750 00000005170 15167606206 022200 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_GROUP_CACHE_PROXY_MODEL_H
#define UKUI_SIDEBAR_GROUP_CACHE_PROXY_MODEL_H
#include
#include
#include
namespace UkuiNotification {
class GroupCacheProxyModel : public QAbstractProxyModel
{
Q_OBJECT
public:
explicit GroupCacheProxyModel(QObject *parent = nullptr);
void setSourceModel(QAbstractItemModel *sourceModel) override;
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
QModelIndex parent(const QModelIndex &child) const override;
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
QVariant data(const QModelIndex &proxyIndex, int role) const override;
Q_INVOKABLE void setRootIndex(QModelIndex rootIndex);
Q_INVOKABLE QModelIndex getRootIndex(int rootIndex);
// Q_INVOKABLE void removeItem(int index);
Q_INVOKABLE void removeItem(uint id);
Q_SIGNALS:
// void removeItem(int row);
void itemRemoved(int row);
private Q_SLOTS:
void onRowInserted(const QModelIndex &parent, int first, int last);
void onRowRemoved(const QModelIndex &parent, int first, int last);
void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles);
private:
class CacheItem {
public:
CacheItem(uint i, QModelIndex index) : id(i), sourceIndex(index) {};
CacheItem(uint i, QPersistentModelIndex index) : id(i), sourceIndex(std::move(index)) {};
uint id;
QPersistentModelIndex sourceIndex;
};
private:
bool m_isValid = false;
QPersistentModelIndex m_rootModelIndex;
QVector m_items;
// QVector m_items;
};
}
#endif //UKUI_SIDEBAR_GROUP_CACHE_PROXY_MODEL_H
ukui-sidebar/src/notification/notification-model.h 0000664 0001750 0001750 00000012646 15167643374 021327 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_NOTIFICATION_MODEL_H
#define UKUI_SIDEBAR_NOTIFICATION_MODEL_H
#include
#include
#include
#include "notification-utils.h"
namespace UkuiNotification {
class NotificationModel;
class NotificationModelPrivate;
class SingleApplicationSettings;
class NotificationItem
{
Q_GADGET
friend class NotificationModel;
friend class NotificationModelPrivate;
public:
enum Flag {
TransientPopup = 0x01, // 默认flag,自动消失弹窗
ResidentPopup = 0x02, // 常驻弹窗
Stored = 0x04, // 已被存储
Expired = 0x08 // 已过期
};
Q_ENUM(Flag)
// Q_DECLARE_FLAGS(Flags, Flag)
enum Property {
Id = 0,
Display,
AppName,
AppIconName,
Icon,
Summary,
Body,
Category,
Image,
CreateTime,
Actions,
ActionState,
HasDefaultAction,
EnableActionIcons,
SoundFile,
SuppressSound,
Resident,
Transient,
Urgency,
Timout,
NoFold,
PopupTimeout,
/* 新属性 */
ToBeStored,
IsStored,
IsExpired,
GroupIndex, // 23
GroupName,
GroupCount,
GroupIsExpand,
ShowOnLockScreen,
ShowContentOnLockScreen,
ProcessedBody,
/* 删除相关属性 */
DelayRemove
};
Q_ENUM(Property)
// Q_DECLARE_FLAGS(Propertys, Property)
static QHash roles();
NotificationItem() = default;
explicit NotificationItem(const PopupNotification& notification);
uint id() const;
private:
void updateActions();
void setData(const PopupNotification ¬ification);
NotificationCloseReason::CloseReason closeReason {NotificationCloseReason::Expired};
qint32 flag {TransientPopup};
QList actions;
PopupNotification data;
bool isShowOnLockScreen {false};
bool isShowContentOnLockScreen {false};
bool isToBeStored {false};
bool isDelayRemove {false};
};
class NotificationModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QString linkActiveColor READ linkActiveColor WRITE setLinkActiveColor NOTIFY linkActiveColorChanged)
public:
static NotificationModel *instance();
Q_DISABLE_COPY_MOVE(NotificationModel)
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
QHash roleNames() const override;
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
Q_INVOKABLE void closeNotification(uint id);
Q_INVOKABLE void execAction(uint id, QString action = "");
Q_INVOKABLE void clearAll();
Q_INVOKABLE void removeNotification(uint id);
Q_INVOKABLE bool setNotificationData(uint id, const QVariant& value, int role);
QString linkActiveColor();
void setLinkActiveColor(QString linkActiveColor);
int getUnreadMessageCount();
Q_SIGNALS:
void linkActiveColorChanged();
public Q_SLOTS:
void storePopupNotification(bool isShow);
private Q_SLOTS:
void onNotificationReceived(const UkuiNotification::PopupNotification ¬ification);
void onNotificationClosed(uint id, UkuiNotification::NotificationCloseReason::CloseReason closeReason);
void removeNotifications();
private:
explicit NotificationModel(QObject *parent = nullptr);
void init();
// 查找消息在数组中的索引
int findNotificationIndex(uint id) const;
// 收起消息
void storeNotification(uint id);
void initNewNotification(NotificationItem &item, SingleApplicationSettings *appSetting);
// 更新消息action状态
void notificationExpired(uint id);
void playSound(const QString& soundName);
void playSoundFile(const QString& soundFile);
// 通知数据更新
void updateNotification(int row, const PopupNotification ¬ification, const SingleApplicationSettings *appSetting);
void updateNotificationTimer(uint id, int timeout, bool isExpired);
void checkNotificationItemChanged(NotificationItem &item, const PopupNotification ¬ification, QVector &changeProperties);
void addUnreadNotification(uint id);
void removeUnreadNotification(uint id);
QString updateNotificationBody(QString text) const;
private:
NotificationModelPrivate *d { nullptr };
bool m_sidebarVisible {false};
QVector m_unreadNotifications;
QString m_linkActiveColor;
Q_SIGNALS:
void unreadMessageCountChanged();
};
} // Notification
//Q_DECLARE_METATYPE(UkuiNotification::NotificationItem::Property)
#endif //UKUI_SIDEBAR_NOTIFICATION_MODEL_H
ukui-sidebar/src/notification/notification-manager.h 0000664 0001750 0001750 00000003476 15167606206 021633 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: iaom
*
*/
#ifndef NOTIFICATIONMANAGER_H
#define NOTIFICATIONMANAGER_H
#include
#include
#include
#include
#include "notification-helper.h"
namespace Notify {
class NotificationManager : public QObject
{
Q_OBJECT
public:
explicit NotificationManager(QObject *parent = nullptr);
public:
Q_INVOKABLE QStringList allAppNames();
Q_INVOKABLE QList getMessages(QString &appName);
public Q_SLOTS:
void newMessageRecived(Message &message);
bool action(const QString &ID);
void openSystemSetting();
void deleteMessage(const QString &ID,const QString &appName);
void deleteAllMessage();
void deleteAppMessage(const QString &appName);
Q_SIGNALS:
void newMessage(const Message &message);
void iHaveUnreadMessage();
void syncDeleteMessage(const QString &ID,const QString &appName);
void syncDeleteAllMessage();
void syncDeleteAppMessage(const QString &appName);
private:
QMultiMap m_nameID; //appName -> IDs
QMap m_messages;
};
}
#endif // NOTIFICATIONMANAGER_H
ukui-sidebar/src/notification/notification-group-model.h 0000664 0001750 0001750 00000005372 15167606206 022450 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_NOTIFICATION_GROUP_MODEL_H
#define UKUI_SIDEBAR_NOTIFICATION_GROUP_MODEL_H
#include
namespace UkuiNotification {
class NotificationGroupModel : public QAbstractProxyModel
{
Q_OBJECT
public:
explicit NotificationGroupModel(QObject *parent = nullptr);
void setSourceModel(QAbstractItemModel *sourceModel) override;
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
QModelIndex parent(const QModelIndex &child) const override;
bool hasChildren(const QModelIndex &parent) const override;
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &proxyIndex, int role) const override;
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override;
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Q_INVOKABLE void clearGroup(const QModelIndex &groupIndex);
Q_INVOKABLE QString stripRichText(const QString &str) const;
private Q_SLOTS:
void onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles);
void onRowInserted(const QModelIndex &parent, int first, int last);
void onRowRemoved(const QModelIndex &parent, int first, int last);
private:
void rebuildGroups();
void adjustSourceIndex(int base, int offset);
void addNewItemToModel(int groupIndex, int sourceIndex);
void removeItemFromModel(int groupIndex, int sourceIndex);
// 返回group的index
int findAppGroupIndex(int sourceIndex) const;
int findAppGroupIndex(const QModelIndex &sourceIndex) const;
bool compareApp(const QModelIndex &a, const QModelIndex &b) const;
int findParentIndex(const QModelIndex &child) const;
int findGroupIndexByRow(int row);
private:
QVector*> m_groups;
QVector m_groupStatus;
};
} // UkuiNotification
#endif //UKUI_SIDEBAR_NOTIFICATION_GROUP_MODEL_H
ukui-sidebar/src/notification/urgency-notification-model.cpp 0000664 0001750 0001750 00000003331 15167606206 023314 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "urgency-notification-model.h"
#include
using namespace UkuiNotification;
UrgencyNotificationModel::UrgencyNotificationModel(QObject *parent)
:QSortFilterProxyModel(parent)
{
}
void UrgencyNotificationModel::closeNotification(uint id)
{
NotificationModel::instance()->closeNotification(id);
}
void UrgencyNotificationModel::execAction(uint id, QString action)
{
NotificationModel::instance()->execAction(id, action);
}
bool UrgencyNotificationModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
QModelIndex sourceIndex = sourceModel()->index(sourceRow, 0, sourceParent);
if (sourceIndex.data(NotificationItem::Urgency).toInt() == PopupNotification::Urgency::CriticalUrgency) {
return true;
}
return false;
}
bool UrgencyNotificationModel::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const
{
return sourceLeft.data(NotificationItem::CreateTime).toDateTime() < sourceRight.data(NotificationItem::CreateTime).toDateTime();
}
ukui-sidebar/src/notification/popup-notification-model.h 0000664 0001750 0001750 00000002422 15167606206 022450 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_POPUP_NOTIFICATION_MODEL_H
#define UKUI_SIDEBAR_POPUP_NOTIFICATION_MODEL_H
#include
namespace UkuiNotification {
class PopupNotificationModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit PopupNotificationModel(QObject *parent = nullptr);
~PopupNotificationModel() override = default;
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
private:
bool m_isTabletMode {false};
bool m_screenLockState {false};
};
}
#endif //UKUI_SIDEBAR_POPUP_NOTIFICATION_MODEL_H
ukui-sidebar/src/notification/urgency-notification-model.h 0000664 0001750 0001750 00000002555 15167606206 022770 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef URGENCYNOTIFICATIONMODEL_H
#define URGENCYNOTIFICATIONMODEL_H
#include
#include "notification-model.h"
class UrgencyNotificationModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit UrgencyNotificationModel(QObject *parent = nullptr);
~UrgencyNotificationModel() = default;
Q_INVOKABLE void closeNotification(uint id);
Q_INVOKABLE void execAction(uint id, QString action = "");
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
bool lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const override;
};
#endif // URGENCYNOTIFICATIONMODEL_H
ukui-sidebar/src/notification/notification-model.cpp 0000664 0001750 0001750 00000071474 15167643374 021666 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "notification-model.h"
#include
#include
#include
//声音播放音效dbus
#define UKUI_SOUNDTHEME_NAME "org.ukui.sound.theme.player"
#define UKUI_SOUNDTHEME_PATH "/org/ukui/sound/theme/player"
#define UKUI_SOUNDTHEME_INTERFACE "org.ukui.sound.theme.player"
#define PLAY_SOUND_METHOD "playAlertSound"
std::once_flag once_flag;
namespace UkuiNotification {
QHash NotificationItem::roles()
{
static QHash roles;
std::call_once(once_flag, [] {
roles.insert(Id, "id");
roles.insert(Display, "display");
roles.insert(AppName, "appName");
roles.insert(AppIconName, "appIconName");
roles.insert(Icon, "icon");
roles.insert(Summary, "summary");
roles.insert(Body, "body");
roles.insert(Category, "category");
roles.insert(Image, "image");
roles.insert(CreateTime, "createTime");
roles.insert(Actions, "actions");
roles.insert(ActionState, "actionState");
roles.insert(HasDefaultAction, "hasDefaultAction");
roles.insert(EnableActionIcons, "enableActionIcons");
roles.insert(SoundFile, "soundFile");
roles.insert(SuppressSound, "suppressSound");
roles.insert(Resident, "resident");
roles.insert(Transient, "transient");
roles.insert(Urgency, "urgency");
roles.insert(Timout, "timout");
roles.insert(NoFold, "noFold");
roles.insert(PopupTimeout, "popupTimeout");
roles.insert(IsStored, "isStored");
roles.insert(ToBeStored, "toBeStored");
roles.insert(IsExpired, "isExpired");
roles.insert(GroupName, "groupName");
roles.insert(GroupCount, "groupCount");
roles.insert(GroupIndex, "groupIndex");
roles.insert(GroupIsExpand, "groupIsExpand");
roles.insert(ShowOnLockScreen, "showOnLockScreen");
roles.insert(ShowContentOnLockScreen, "showContentOnLockScreen");
roles.insert(ProcessedBody, "processedBody");
roles.insert(DelayRemove, "delayRemove");
});
return roles;
}
NotificationItem::NotificationItem(const PopupNotification& notification)
{
setData(notification);
}
uint NotificationItem::id() const
{
return data.id();
}
void NotificationItem::setData(const PopupNotification ¬ification)
{
data = notification;
updateActions();
}
void NotificationItem::updateActions()
{
actions.clear();
ActionList actionList(data.actions());
QStringList actionState(data.actionState());
for (int i = 0; i < actionList.size(); ++i) {
NotificationAction action;
action.setEnable(true);
action.setDefault(data.hasDefaultAction() && actionList[i].first == "default");
action.setIndex(i);
action.setIcon(data.enableActionIcons() ? actionList[i].second : "");
action.setName(actionList[i].second);
action.setAction(actionList[i].first);
action.setState(i < actionState.size() ? actionState[i] : "");
actions.append(action);
}
}
// ===== Private ======//
class NotificationModelPrivate
{
public:
virtual ~NotificationModelPrivate();
NotificationGlobalSettings *globalSettings {nullptr};
// 消息客户端,收取消息
NotificationClient *client {nullptr};
// 全部消息记录
// QVector notifications;
QVector notifications;
// 计时器,控制每条弹窗消息定时收起
QHash notificationTimers;
// 即将删除的消息Id列表
QSet pendingRemovalIds;
// 计时器,在计时器结束后,删除消息
QTimer *pendingRemovalTimer {nullptr};
public:
void deleteTimer(const uint &id);
void prepareToDeleteNotification(const uint &id);
};
NotificationModelPrivate::~NotificationModelPrivate()
{
qDeleteAll(notificationTimers);
notificationTimers.clear();
}
void NotificationModelPrivate::deleteTimer(const uint &id)
{
delete notificationTimers.take(id);
}
void NotificationModelPrivate::prepareToDeleteNotification(const uint &id)
{
// 删除定时器
deleteTimer(id);
// 重启计时器,删除通知
pendingRemovalTimer->stop();
pendingRemovalIds.insert(id);
pendingRemovalTimer->start();
}
// ===== M ====== //
NotificationModel *NotificationModel::instance()
{
static NotificationModel instance;
return &instance;
}
NotificationModel::NotificationModel(QObject *parent) : QAbstractListModel(parent), d(new NotificationModelPrivate)
{
qRegisterMetaType("NotificationAction");
init();
}
void NotificationModel::init()
{
// 初始化timer
d->pendingRemovalTimer = new QTimer(this);
d->pendingRemovalTimer->setSingleShot(true);
d->pendingRemovalTimer->setInterval(50);
connect(d->pendingRemovalTimer, &QTimer::timeout, this, &NotificationModel::removeNotifications);
// 通知全局设置
d->globalSettings = new NotificationGlobalSettings(this);
d->client = new NotificationClient(this);
connect(d->client, &NotificationClient::newNotification, this, &NotificationModel::onNotificationReceived);
connect(d->client, &NotificationClient::notificationClosed, this, &NotificationModel::onNotificationClosed);
if (!d->client->registerClient()) {
qWarning() << "register client failed.";
}
}
int NotificationModel::findNotificationIndex(uint id) const
{
auto it = std::find_if(d->notifications.constBegin(), d->notifications.constEnd(), [&id] (const NotificationItem &n) {
return n.id() == id;
});
if (it == d->notifications.constEnd()) {
return -1;
}
return std::distance(d->notifications.constBegin(), it);
}
void NotificationModel::initNewNotification(NotificationItem &item, SingleApplicationSettings *appSetting)
{
// switch (appSetting->popupStyle()) {
// case SettingsProperty::TransientPopup: {
// if (item.data.popupTimeout() < 0) {
// item.flag = NotificationItem::ResidentPopup;
// break;
// }
//
// if (item.data.popupTimeout() > 0) {
// item.flag = NotificationItem::TransientPopup;
// break;
// }
//
// item.flag = NotificationItem::Stored;
// break;
// }
// case SettingsProperty::ResidentPopup:
// item.flag = NotificationItem::ResidentPopup;
// break;
// case SettingsProperty::NoPopup:
// default:
// item.flag = NotificationItem::Stored;
// }
if (item.data.popupTimeout() < 0) {
item.flag = NotificationItem::ResidentPopup;
} else if (item.data.popupTimeout() > 0) {
item.flag = m_sidebarVisible ? NotificationItem::Stored : NotificationItem::TransientPopup;
} else {
item.flag = NotificationItem::Stored;
}
item.isShowOnLockScreen = appSetting->showNotificationOnLockScreen();
item.isShowContentOnLockScreen = appSetting->showContentOnLockScreen();
if (appSetting->allowSound() && !item.data.suppressSound()) {
// TODO: 一段时间内只响一次
// 响铃 ding ~
if (item.data.soundFile().isEmpty()) {
playSound(item.data.soundName().isEmpty() ? "notification-general" : item.data.soundName());
} else {
playSound("notification-general");
// FIXME: 实现声音文件播放
// playSoundFile(item.data.soundFile());
}
}
}
void NotificationModel::onNotificationReceived(const PopupNotification ¬ification)
{
if (!d->globalSettings->receiveNotificationsFromApps() && !ApplicationsSettings::self()->isInAllowList(notification.desktopEntry())) {
return;
}
SingleApplicationSettings *appSetting = ApplicationsSettings::self()->creatSettings(notification);
if (!appSetting->allowNotify()) {
return;
}
int index = findNotificationIndex(notification.id());
if (index >= 0) {
// 已经存在消息,更新消息
updateNotification(index, notification, appSetting);
return;
}
if (d->notifications.size() >= 500) {
beginRemoveRows(QModelIndex(), 0, 0);
d->deleteTimer(d->notifications.at(0).id());
d->notifications.removeAt(0);
endRemoveRows();
// int count = d->notifications.size() - 500;
// for (int i = count - 1; i >= 0; --i) {
// beginRemoveRows(QModelIndex(), i, i);
// d->notifications.removeAt(i);
// endRemoveRows();
// }
}
// TODO 查询应用设置,检查系统设置,响铃
/*
* bool allowNotify() const; y
* bool allowSound() const ; y
* bool showContentOnLockScreen() const ; n
* bool showNotificationOnLockScreen() const; n
* SettingsProperty::Property popupStyle() const; y
*/
NotificationItem item(notification);
// 勿扰模式
if (d->globalSettings->isDND()) {
if (d->globalSettings->notifyAlarmWhileDND() && item.data.desktopEntry().contains("ukui-clock")) {
initNewNotification(item, appSetting);
} else {
item.flag = NotificationItem::Stored;
addUnreadNotification(item.id());
}
} else {
initNewNotification(item, appSetting);
}
int timeout = item.data.timeout();
if (item.flag & NotificationItem::TransientPopup) {
// 弹窗
bool isExpired = true;
if (timeout <= 0 || (timeout > item.data.popupTimeout())) {
isExpired = false;
timeout = item.data.popupTimeout();
}
updateNotificationTimer(item.id(), timeout, isExpired);
} else {
// 非弹窗
if (timeout > 0 && !item.data.resident()) {
updateNotificationTimer(item.id(), timeout, true);
}
}
// 插入数据
beginInsertRows(QModelIndex(), d->notifications.size(), d->notifications.size());
d->notifications.append(std::move(item));
endInsertRows();
}
void NotificationModel::playSound(const QString& soundName)
{
QDBusMessage message = QDBusMessage::createMethodCall(UKUI_SOUNDTHEME_NAME, UKUI_SOUNDTHEME_PATH, UKUI_SOUNDTHEME_INTERFACE, PLAY_SOUND_METHOD);
message << soundName;
auto watcher = new QDBusPendingCallWatcher(QDBusConnection::sessionBus().asyncCall(message), this);
connect(watcher, &QDBusPendingCallWatcher::finished, this, [] (QDBusPendingCallWatcher *self) {
if (self) {
QDBusPendingReply reply = *self;
if (reply.isError()) {
qWarning() << "playSound error:" << reply.error().message();
}
self->deleteLater();
}
});
}
void NotificationModel::playSoundFile(const QString &soundFile)
{
// TODO: 播放自定义声音文件
}
void
NotificationModel::onNotificationClosed(uint id, UkuiNotification::NotificationCloseReason::CloseReason closeReason)
{
int row = findNotificationIndex(id);
if (row < 0) {
return;
}
if (!m_sidebarVisible) {
d->prepareToDeleteNotification(id);
} else {
NotificationItem &item = d->notifications[row];
item.isDelayRemove = true;
Q_EMIT dataChanged(index(row), index(row), {NotificationItem::DelayRemove});
}
// 插入数据
// beginRemoveRows(QModelIndex(), index, index);
// d->notifications.removeAt(index);
// endRemoveRows();
}
void NotificationModel::updateNotification(int row, const PopupNotification ¬ification, const SingleApplicationSettings *appSetting)
{
QVector roles;
NotificationItem &item = d->notifications[row];
if (d->pendingRemovalIds.contains(item.id())) {
d->pendingRemovalIds.remove(item.id());
}
item.isShowOnLockScreen = appSetting->showNotificationOnLockScreen();
item.isShowContentOnLockScreen = appSetting->showContentOnLockScreen();
checkNotificationItemChanged(item, notification, roles);
item.setData(notification);
Q_EMIT dataChanged(index(row), index(row), roles);
}
/**
* 初始化某条消息的timer,
* 如果已经存在timer,那就重新启动timer,将消息收起的时间延长
* timer计时结束后,将允许收起的消息收起
* @param id 消息id
* @param timeout 超时时间,单位:毫秒
* @param isExpired 在定时结束后,消息变为过期状态
*/
void NotificationModel::updateNotificationTimer(uint id, int timeout, bool isExpired)
{
QTimer *timer = d->notificationTimers.value(id, nullptr);
if (!timer) {
timer = new QTimer();
timer->setSingleShot(true);
timer->setProperty("id", id);
// timer的两种状态:
// 1.作为弹窗计时器 (计时结束后收起弹窗)
// 2.作为消息生命周期计时器 (计时结束后删除消息)
connect(timer, &QTimer::timeout, this, [this, timer] {
uint id = timer->property("id").toUInt();
bool isExpired = timer->property("isExpired").toBool();
// 删除消息
if (isExpired) {
//更新actions状态
notificationExpired(id);
} else {
storeNotification(id);
}
});
d->notificationTimers.insert(id, timer);
}
timer->stop();
timer->setProperty("isExpired", isExpired);
timer->setInterval(timeout);
timer->start();
}
void NotificationModel::addUnreadNotification(uint id)
{
if (!m_unreadNotifications.contains(id)) {
m_unreadNotifications.append(id);
}
Q_EMIT unreadMessageCountChanged();
}
void NotificationModel::removeUnreadNotification(uint id)
{
if (m_unreadNotifications.contains(id)) {
m_unreadNotifications.removeAll(id);
}
Q_EMIT unreadMessageCountChanged();
}
void NotificationModel::checkNotificationItemChanged(NotificationItem &item, const PopupNotification ¬ification, QVector &roles)
{
if (item.data.display() != notification.display()){
roles.append(NotificationItem::Display);
}
if (item.data.applicationName() != notification.applicationName()){
roles.append(NotificationItem::AppName);
}
if (item.data.applicationIconName() != notification.applicationIconName()){
roles.append(NotificationItem::AppIconName);
}
if (item.data.icon() != notification.icon()){
roles.append(NotificationItem::Icon);
}
if (item.data.summary() != notification.summary()){
roles.append(NotificationItem::Summary);
}
if (item.data.body() != notification.body()){
roles.append(NotificationItem::Body);
}
if (item.data.category() != notification.category()){
roles.append(NotificationItem::Category);
}
if (item.data.image() != notification.image()){
roles.append(NotificationItem::Image);
}
if (item.data.createdTime() != notification.createdTime()){
roles.append(NotificationItem::CreateTime);
}
if (item.data.actions() != notification.actions()){
roles.append(NotificationItem::Actions);
}
if (item.data.actionState() != notification.actionState()){
roles.append(NotificationItem::ActionState);
}
if (item.data.hasDefaultAction() != notification.hasDefaultAction()){
roles.append(NotificationItem::HasDefaultAction);
}
if (item.data.enableActionIcons() != notification.enableActionIcons()){
roles.append(NotificationItem::EnableActionIcons);
}
if (item.data.soundFile() != notification.soundFile()){
roles.append(NotificationItem::SoundFile);
}
if (item.data.suppressSound() != notification.suppressSound()){
roles.append(NotificationItem::SuppressSound);
}
if (item.data.resident() != notification.resident()){
roles.append(NotificationItem::Resident);
}
if (item.data.transient() != notification.transient()){
roles.append(NotificationItem::Transient);
}
if (item.data.urgency() != notification.urgency()){
roles.append(NotificationItem::Urgency);
}
if (item.data.timeout() != notification.timeout()){
roles.append(NotificationItem::Timout);
}
if (item.data.noFold() != notification.noFold()){
roles.append(NotificationItem::NoFold);
}
if (item.data.popupTimeout() != notification.popupTimeout()){
roles.append(NotificationItem::PopupTimeout);
}
}
/**
* 定时器结束后,调用该函数
* @param id
*/
void NotificationModel::storeNotification(uint id)
{
int idx = findNotificationIndex(id);
if (idx < 0) {
d->deleteTimer(id);
return;
}
NotificationItem &item = d->notifications[idx];
int timeout = item.data.timeout();
if (timeout > 0) {
if (timeout > item.data.popupTimeout()) {
timeout = timeout - item.data.popupTimeout();
}
updateNotificationTimer(id, timeout, true);
} else {
d->deleteTimer(id);
}
if (!(item.flag & NotificationItem::Stored) && index(idx).isValid()) {
item.isToBeStored = true;
addUnreadNotification(item.id());
Q_EMIT dataChanged(index(idx), index(idx), {NotificationItem::ToBeStored});
}
}
void NotificationModel::notificationExpired(uint id)
{
// d->prepareToDeleteNotification(id);
int idx = findNotificationIndex(id);
if (idx < 0) {
d->deleteTimer(id);
return;
}
NotificationItem &item = d->notifications[idx];
if (item.flag & NotificationItem::TransientPopup) {
item.isToBeStored = true;
addUnreadNotification(item.id());
}
item.flag |= NotificationItem::Expired;
for (auto &action : item.actions) {
action.setEnable(false);
}
d->deleteTimer(id);
Q_EMIT dataChanged(index(idx), index(idx), {NotificationItem::Actions, NotificationItem::IsExpired, NotificationItem::ToBeStored});
}
void NotificationModel::removeNotifications()
{
if (d->pendingRemovalIds.isEmpty()) {
return;
}
QVector rows;
rows.reserve(d->pendingRemovalIds.size());
for (uint id : d->pendingRemovalIds) {
int row = findNotificationIndex(id);
d->notifications[row].isDelayRemove = false;
if (row < 0) {
continue;
}
rows.append(row);
}
if (rows.isEmpty()) {
d->pendingRemovalIds.clear();
return;
}
std::sort(rows.begin(), rows.end());
// 准备删除row数据
QVector> rangeList;
QPair range {rows[0], rows[0]};
for (int row : rows) {
if (row > (range.second + 1)) {
rangeList.append(range);
range.first = row;
}
range.second = row;
}
if (rangeList.isEmpty() || (rangeList.last() != range)) {
rangeList.append(range);
}
int removedRows = 0;
for (int i = rangeList.count() - 1; i >= 0; --i) {
range = rangeList[i];
beginRemoveRows(QModelIndex(), range.first, range.second);
for (int j = range.second; j >= range.first; --j) {
// close notification
NotificationItem item = d->notifications.takeAt(j);
removeUnreadNotification(item.id());
d->client->closeNotification(item.id(), item.closeReason);
++removedRows;
}
endRemoveRows();
}
d->pendingRemovalIds.clear();
}
// ====== !!! Model oh ~ oh ~ oh ~ oh ~ oh ~ ======
int NotificationModel::rowCount(const QModelIndex &parent) const
{
return d->notifications.count();
}
QVariant NotificationModel::data(const QModelIndex &index, int role) const
{
if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)) {
return {};
}
const NotificationItem &item = d->notifications[index.row()];
switch (role) {
case NotificationItem::Id:
return item.id();
case NotificationItem::Display:
return item.data.display();
case NotificationItem::AppName:
return item.data.applicationName();
case NotificationItem::AppIconName: {
if (item.data.icon().isEmpty()) {
if (item.data.applicationIconName().isEmpty()) {
return "application-x-desktop";
}
return item.data.applicationIconName();
}
return item.data.icon();
}
case NotificationItem::Icon:
return item.data.icon();
case NotificationItem::Summary:
return item.data.summary();
case NotificationItem::Body: {
return item.data.body();
}
case NotificationItem::Category:
return item.data.category();
case NotificationItem::Image: {
if (!item.data.image().isNull()) {
return item.data.image();
}
return {};
}
case NotificationItem::CreateTime:
return item.data.createdTime();
case NotificationItem::Actions: {
// for qt 5.12
QVariantList list;
for (const auto &ac : item.actions) {
list.append(QVariant::fromValue(ac));
}
return list;
// return QVariant::fromValue(item.actions);
}
case NotificationItem::EnableActionIcons:
return item.data.enableActionIcons();
case NotificationItem::SoundFile:
return item.data.soundFile();
case NotificationItem::SuppressSound:
return item.data.suppressSound();
case NotificationItem::Resident:
return item.data.resident();
case NotificationItem::Transient:
return item.data.transient();
case NotificationItem::Urgency:
return item.data.urgency();
case NotificationItem::Timout:
return item.data.timeout();
case NotificationItem::NoFold:
return item.data.noFold();
case NotificationItem::PopupTimeout:
return item.data.popupTimeout();
case NotificationItem::ToBeStored:
return item.isToBeStored;
case NotificationItem::IsStored:
return item.flag & NotificationItem::Stored;
case NotificationItem::IsExpired:
return item.flag & NotificationItem::Expired;
case NotificationItem::HasDefaultAction:
return item.data.hasDefaultAction();
case NotificationItem::ShowOnLockScreen:
return item.isShowOnLockScreen;
case NotificationItem::ShowContentOnLockScreen:
return item.isShowContentOnLockScreen;
case NotificationItem::ProcessedBody:
return updateNotificationBody(item.data.body());
case NotificationItem::DelayRemove:
return item.isDelayRemove;
default:
break;
}
return {};
}
QHash NotificationModel::roleNames() const
{
return NotificationItem::roles();
}
bool NotificationModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if (!index.isValid() || index.row() < 0 || index.row() >= d->notifications.size()) {
return false;
}
NotificationItem &item = d->notifications[index.row()];
if (role == NotificationItem::IsStored && value.toBool()) {
if (!(item.flag & NotificationItem::Stored)) {
item.flag = NotificationItem::Stored;
item.isToBeStored = false;
Q_EMIT dataChanged(index, index, {NotificationItem::IsStored, NotificationItem::ToBeStored});
return true;
}
} else if (role == NotificationItem::DelayRemove) {
item.isDelayRemove = value.toBool();
if (!item.isDelayRemove) {
closeNotification(index.data(NotificationItem::Id).toUInt());
}
Q_EMIT dataChanged(index, index, {NotificationItem::DelayRemove});
return true;
}
return QAbstractListModel::setData(index, value, role);
}
void NotificationModel::closeNotification(uint id)
{
int index = findNotificationIndex(id);
if (index < 0) {
return;
}
d->notifications[index].closeReason = NotificationCloseReason::DismissedByUser;
d->prepareToDeleteNotification(id);
}
void NotificationModel::execAction(uint id, QString action)
{
int index = findNotificationIndex(id);
if (index < 0) {
return;
}
NotificationItem &item = d->notifications[index];
if (item.flag & NotificationItem::Expired) {
item.closeReason = NotificationCloseReason::DismissedByUser;
d->prepareToDeleteNotification(id);
return;
}
if (action.isEmpty()) {
if (item.data.hasDefaultAction()) {
action = "default";
} else {
// item.closeReason = NotificationCloseReason::Revoked;
// d->prepareToDeleteNotification(id);
return;
}
}
d->client->invokeAction(id, action);
if (!item.data.resident()) {
item.closeReason = NotificationCloseReason::Revoked;
d->prepareToDeleteNotification(id);
}
}
void NotificationModel::clearAll()
{
beginRemoveRows(QModelIndex(), 0, d->notifications.size() - 1);
int i = d->notifications.size() - 1;
for (; i >= 0; --i) {
d->deleteTimer(d->notifications.at(i).id());
d->notifications.removeAt(i);
}
endRemoveRows();
}
void NotificationModel::removeNotification(uint id)
{
d->prepareToDeleteNotification(id);
}
bool NotificationModel::setNotificationData(uint id, const QVariant& value, int role)
{
// GetModelIndex
int row = findNotificationIndex(id);
QModelIndex modelIndex;
if (row < 0) {
return false;
}
modelIndex = index(row, 0);
if (!modelIndex.isValid() || modelIndex.parent().isValid()) {
return false;
}
// SetData
return setData(modelIndex, value, role);
}
QString NotificationModel::linkActiveColor()
{
return m_linkActiveColor;
}
void NotificationModel::setLinkActiveColor(QString linkActiveColor)
{
if (linkActiveColor == m_linkActiveColor) return;
m_linkActiveColor = linkActiveColor;
for (int i = 0; i < d->notifications.count(); i++) {
Q_EMIT dataChanged(index(i), index(i), {NotificationItem::ProcessedBody});
}
}
QString NotificationModel::updateNotificationBody(QString text) const
{
if (Qt::mightBeRichText(text)) {
QTextDocument doc;
doc.setHtml(text);
for (QTextBlock block = doc.begin(); block != doc.end(); block = block.next()) {
for (QTextBlock::iterator item = block.begin(); item != block.end(); item++) {
QTextFragment fragment = item.fragment();
if (fragment.isValid()) {
QTextCharFormat format = fragment.charFormat();
if (!format.anchorHref().isEmpty()) {
int index = text.lastIndexOf(fragment.text());
if (index != -1) {
QString leftText = text.mid(0,index);
QString rightText = text.mid(index + fragment.text().length());
QString newText = leftText + (QString("").arg(m_linkActiveColor)) + fragment.text()
+ QString("") + rightText;
return newText;
}
}
}
}
}
}
return text;
}
int NotificationModel::getUnreadMessageCount()
{
return m_unreadNotifications.length();
}
void NotificationModel::storePopupNotification(bool isShow)
{
if (m_sidebarVisible == isShow) return;
if (isShow) {
for (int i = 0; i < d->notifications.length(); i++) {
NotificationItem &item = d->notifications[i];
if (item.flag == NotificationItem::TransientPopup) {
item.flag = NotificationItem::Stored;
Q_EMIT dataChanged(index(i), index(i), {NotificationItem::Stored});
}
}
m_unreadNotifications.clear();
Q_EMIT unreadMessageCountChanged();
}
m_sidebarVisible = isShow;
}
} // Notification
ukui-sidebar/src/notification/notification-utils.h 0000664 0001750 0001750 00000004735 15167606206 021360 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_NOTIFICATION_UTILS_H
#define UKUI_SIDEBAR_NOTIFICATION_UTILS_H
#include
namespace UkuiNotification {
/**
bool hasDefaultAction() const;
QString defaultActionLabel();
ActionList actions() const;
QStringList actionState() const;
*/
class NotificationAction
{
Q_GADGET
Q_PROPERTY(bool isEnable READ isEnable)
Q_PROPERTY(bool isDefault READ isDefault)
Q_PROPERTY(int index READ index)
Q_PROPERTY(Mode mode READ mode)
Q_PROPERTY(QString icon READ icon)
Q_PROPERTY(QString name READ name)
Q_PROPERTY(QString action READ action)
Q_PROPERTY(QString state READ state)
public:
enum Mode {
Icon = 0,
Text,
IconAndText
};
Q_ENUM(Mode)
enum State {
Enable = 0,
Disable,
};
Q_ENUM(State)
NotificationAction() = default;
NotificationAction(bool e, bool d, int index, Mode mode, QString icon, QString name, QString state);
bool isEnable() const;
void setEnable(bool e);
bool isDefault() const;
void setDefault(bool d);
int index() const;
void setIndex(int index);
NotificationAction::Mode mode() const;
void setMode(Mode mode);
QString icon() const;
void setIcon(const QString &icon);
QString name() const;
void setName(const QString &name);
QString action() const;
void setAction(const QString &action);
QString state() const;
void setState(const QString &state);
private:
bool m_enable {true};
bool m_default {true};
int m_index {0};
Mode m_mode {Text};
QString m_icon;
QString m_name;
QString m_action;
// TODO use enum?
QString m_state;
};
} // UkuiNotification
Q_DECLARE_METATYPE(UkuiNotification::NotificationAction)
#endif //UKUI_SIDEBAR_NOTIFICATION_UTILS_H
ukui-sidebar/src/notification/notification-group-model.cpp 0000664 0001750 0001750 00000031124 15167606206 022775 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "notification-group-model.h"
#include "notification-model.h"
#include
#include
#include
using namespace UkuiNotification;
NotificationGroupModel::NotificationGroupModel(QObject *parent) : QAbstractProxyModel(parent)
{
qRegisterMetaType();
}
void NotificationGroupModel::setSourceModel(QAbstractItemModel *sourceModel)
{
if (sourceModel == QAbstractProxyModel::sourceModel()) {
return;
}
beginResetModel();
if (QAbstractProxyModel::sourceModel()) {
QAbstractProxyModel::sourceModel()->disconnect(this);
}
qDeleteAll(m_groups);
QAbstractProxyModel::setSourceModel(sourceModel);
if (QAbstractProxyModel::sourceModel()) {
rebuildGroups();
connect(sourceModel, &QAbstractItemModel::dataChanged, this, &NotificationGroupModel::onDataChanged);
connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &NotificationGroupModel::onRowInserted);
connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &NotificationGroupModel::onRowRemoved);
connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, [=] (const QModelIndex &parent, int first, int last) {
if (parent.isValid()) {
return ;
}
adjustSourceIndex(first, -(last - first + 1));
});
connect(sourceModel, &QAbstractItemModel::modelReset, this, [this] {
beginResetModel();
qDeleteAll(m_groups);
rebuildGroups();
endResetModel();
});
}
endResetModel();
}
void NotificationGroupModel::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
const QVector &roles)
{
if (topLeft.parent() != bottomRight.parent()) {
return;
}
if (topLeft == bottomRight) {
if (roles.contains(NotificationItem::NoFold) || roles.contains(NotificationItem::AppName)) {
int row = topLeft.row();
int groupIndex = findGroupIndexByRow(row);
removeItemFromModel(groupIndex, row);
addNewItemToModel(findAppGroupIndex(row), row);
return;
}
QModelIndex top = mapFromSource(topLeft);
if (!top.isValid()) {
return;
}
Q_EMIT dataChanged(top, top, roles);
}
QModelIndex top = mapFromSource(topLeft);
if (!top.isValid()) {
return;
}
QModelIndex bottom = mapFromSource(bottomRight);
if (!bottom.isValid()) {
return;
}
if (top.parent() == bottom.parent()) {
Q_EMIT dataChanged(top, bottom, roles);
} else {
Q_EMIT dataChanged(top.parent(), top.parent(), roles);
Q_EMIT dataChanged(bottom.parent(), bottom.parent(), roles);
}
}
/**
* 调整内部存储索引指向
* @param base
* @param offset
*/
void NotificationGroupModel::adjustSourceIndex(int base, int offset)
{
for (QVector *group : m_groups) {
QMutableVectorIterator it(*group);
while (it.hasNext()) {
const int &value = it.next();
if (value >= base) {
it.setValue(value + offset);
}
}
}
}
void NotificationGroupModel::onRowInserted(const QModelIndex &parent, int first, int last)
{
if (parent.isValid()) {
return;
}
if (first < (sourceModel()->rowCount() -1)) {
// relocation
adjustSourceIndex(first, last - first + 1);
}
for (int i = first; i <= last; ++i) {
addNewItemToModel(findAppGroupIndex(i), i);
}
}
void NotificationGroupModel::onRowRemoved(const QModelIndex &parent, int first, int last)
{
if (parent.isValid()) {
return ;
}
for (int sourceIndex = first; sourceIndex <= last; ++sourceIndex) {
QModelIndex removedIndex = sourceModel()->index(sourceIndex, 0, parent);
int groupIndex = findAppGroupIndex(removedIndex);
if (groupIndex < 0) {
continue;
}
removeItemFromModel(groupIndex, sourceIndex);
}
}
void NotificationGroupModel::rebuildGroups()
{
m_groupStatus.clear();
int count = sourceModel()->rowCount();
for (int i = 0; i < count; ++i) {
addNewItemToModel(findAppGroupIndex(i), i);
}
}
void NotificationGroupModel::addNewItemToModel(int groupIndex, int sourceIndex)
{
QVector *group;
if (groupIndex < 0) {
group = new QVector(1, sourceIndex);
// 插入group
beginInsertRows(QModelIndex(), 0, 0);
m_groups.prepend(group);
m_groupStatus.prepend(false);
endInsertRows();
// // TODO: update group count
// beginInsertRows(index(m_groups.size() - 1, 0, QModelIndex()), 0, 0);
// group->append(sourceIndex);
// endInsertRows();
} else {
group = m_groups.at(groupIndex);
if (groupIndex > 0) {
beginMoveRows(QModelIndex(), groupIndex, groupIndex, QModelIndex(), 0);
m_groups.move(groupIndex, 0);
m_groupStatus.move(groupIndex, 0);
endMoveRows();
}
QModelIndex groupModelIndex = index(0, 0, QModelIndex());
beginInsertRows(groupModelIndex, 0, 0);
group->prepend(sourceIndex);
endInsertRows();
Q_EMIT dataChanged(groupModelIndex, groupModelIndex);
}
Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(m_groups.size() - 1, 0, QModelIndex()), {NotificationItem::GroupIndex});
}
void NotificationGroupModel::removeItemFromModel(int groupIndex, int sourceIndex)
{
if (groupIndex < 0) return;
QModelIndex groupModelIndex = index(groupIndex, 0, QModelIndex());
QVector* group = m_groups[groupIndex];
if (group->size() > 1) {
int appIndex = group->indexOf(sourceIndex);
beginRemoveRows(groupModelIndex, appIndex, appIndex);
group->removeAt(appIndex);
endRemoveRows();
Q_EMIT dataChanged(groupModelIndex, groupModelIndex);
} else {
beginRemoveRows(QModelIndex(), groupIndex, groupIndex);
delete m_groups.takeAt(groupIndex);
m_groupStatus.removeAt(groupIndex);
endRemoveRows();
Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(m_groups.size() - 1, 0, QModelIndex()), {NotificationItem::GroupIndex});
}
}
int NotificationGroupModel::findAppGroupIndex(int sourceIndex) const
{
if (sourceModel()) {
return findAppGroupIndex(sourceModel()->index(sourceIndex, 0));
}
return -1;
}
int NotificationGroupModel::findAppGroupIndex(const QModelIndex &sourceIndex) const
{
for (int i = 0; i < m_groups.size(); ++i) {
QModelIndex group = sourceModel()->index(m_groups.at(i)->at(0), 0);
if (compareApp(group, sourceIndex)) {
return i;
}
}
return -1;
}
bool NotificationGroupModel::compareApp(const QModelIndex &a, const QModelIndex &b) const
{
bool allowFold = !a.data(NotificationItem::NoFold).toBool() && !b.data(NotificationItem::NoFold).toBool();
return allowFold ? a.data(NotificationItem::AppName).toString() == b.data(NotificationItem::AppName).toString()
: a.data(NotificationItem::Id).toUInt() == b.data(NotificationItem::Id).toUInt();
}
QModelIndex NotificationGroupModel::index(int row, int column, const QModelIndex &parent) const
{
if (row < 0 || column != 0) {
return {};
}
if (parent.isValid()) {
return createIndex(row, column, m_groups.value(parent.row()));
}
return createIndex(row, column);
}
int NotificationGroupModel::findParentIndex(const QModelIndex &child) const
{
QVector *group = static_cast *>(child.internalPointer());
if (group) {
return m_groups.indexOf(group);
}
return -1;
}
int NotificationGroupModel::findGroupIndexByRow(int row)
{
for (int i = 0; i < m_groups.size(); i++ ){
for (int j = 0; j < m_groups[i]->size(); j++ ){
if (m_groups[i]->at(j) == row){
return i;
}
}
}
return -1;
}
QModelIndex NotificationGroupModel::parent(const QModelIndex &child) const
{
if (!child.isValid()) {
return {};
}
int r = findParentIndex(child);
if (r < 0) {
return {};
}
return createIndex(r, 0);
}
bool NotificationGroupModel::hasChildren(const QModelIndex &parent) const
{
if (!sourceModel()) {
return false;
}
// root
if (!parent.isValid()) {
return !m_groups.isEmpty();
}
// child
if (parent.parent().isValid()) {
return false;
}
return true;
}
QModelIndex NotificationGroupModel::mapToSource(const QModelIndex &proxyIndex) const
{
// root
if (!sourceModel() || !proxyIndex.isValid()) {
return {};
}
// child
if (proxyIndex.parent().isValid()) {
int r = m_groups.at(proxyIndex.parent().row())->at(proxyIndex.row());
return sourceModel()->index(r, 0);
}
// group
return {};
}
QModelIndex NotificationGroupModel::mapFromSource(const QModelIndex &sourceIndex) const
{
int i = findAppGroupIndex(sourceIndex);
if (i < 0) {
return {};
}
int r = m_groups.at(i)->indexOf(sourceIndex.row());
if (r < 0) {
return {};
}
return index(r, 0, index(i, 0, QModelIndex()));
}
int NotificationGroupModel::rowCount(const QModelIndex &parent) const
{
if (!sourceModel()) {
return 0;
}
// root
if (!parent.isValid()) {
return m_groups.size();
}
// child
if (parent.parent().isValid()) {
return 0;
}
// group
int r = parent.row();
if (r < 0 || r >= m_groups.size()) {
return 0;
}
return m_groups.at(r)->size();
}
int NotificationGroupModel::columnCount(const QModelIndex &parent) const
{
return 1;
}
QVariant NotificationGroupModel::data(const QModelIndex &proxyIndex, int role) const
{
if (!proxyIndex.isValid()) {
return {};
}
if (proxyIndex.parent().isValid()) {
return QAbstractProxyModel::data(proxyIndex, role);
}
int groupIndex = proxyIndex.row();
switch (role) {
case NotificationItem::GroupIndex:
return groupIndex;
case NotificationItem::GroupName:
return sourceModel()->index(m_groups.at(groupIndex)->at(0), 0, QModelIndex()).data(NotificationItem::AppName);
case NotificationItem::GroupCount:
return m_groups.at(groupIndex)->size();
case NotificationItem::GroupIsExpand:
return m_groupStatus.at(groupIndex);
default:
break;
}
return {};
}
bool NotificationGroupModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role == NotificationItem::GroupIsExpand) {
if (!index.isValid() || index.parent().isValid()) {
return false;
}
m_groupStatus[index.data(NotificationItem::GroupIndex).toInt()] = value.toBool();
Q_EMIT dataChanged(index, index, {NotificationItem::GroupIsExpand});
return true;
}
return QAbstractProxyModel::setData(index, value, role);
}
void NotificationGroupModel::clearGroup(const QModelIndex &groupIndex)
{
if (!checkIndex(groupIndex, QAbstractItemModel::CheckIndexOption::IndexIsValid)) {
return;
}
int r = groupIndex.row();
beginRemoveRows(QModelIndex(), r, r);
QVector *group = m_groups.takeAt(r);
for (const auto &sourceRow : *group) {
NotificationModel::instance()->removeNotification(sourceModel()->index(sourceRow, 0, QModelIndex()).data(NotificationItem::Id).toUInt());
}
delete group;
endRemoveRows();
Q_EMIT dataChanged(index(0, 0, QModelIndex()), index(m_groups.size() - 1, 0, QModelIndex()), {NotificationItem::GroupIndex});
}
QString NotificationGroupModel::stripRichText(const QString &str) const
{
if (Qt::mightBeRichText(str)) {
QTextDocument doc;
doc.setHtml(str);
return doc.toPlainText();
}
return str;
}
ukui-sidebar/src/notification/notification-manager.cpp 0000664 0001750 0001750 00000005314 15167606206 022157 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Authors: iaom
*
*/
#include "notification-manager.h"
#include "app-manager.h"
#include
#include
#include
#include
using namespace Notify;
NotificationManager::NotificationManager(QObject *parent) : QObject(parent)
{
connect(NotificationHelper::instance(), &NotificationHelper::newMessage, this, &NotificationManager::newMessageRecived);
}
QStringList NotificationManager::allAppNames()
{
return m_nameID.keys();
}
QList NotificationManager::getMessages(QString &appName)
{
QList messages;
for(QString id : m_nameID.values(appName)) {
messages.append(m_messages.value(id));
}
return messages;
}
void NotificationManager::newMessageRecived(Message &message)
{
m_messages.insert(message.getID(), message);
m_nameID.insert(message.getAppName(), message.getID());
Q_EMIT newMessage(message);
Q_EMIT iHaveUnreadMessage();
}
bool NotificationManager::action(const QString &ID)
{
if(m_messages.contains(ID)) {
return m_messages.value(ID).executeDefaultAction();
}
return true;
}
void NotificationManager::deleteMessage(const QString &ID,const QString &appName)
{
m_nameID.remove(m_messages.value(ID).getAppName(), ID);
m_messages.remove(ID);
Q_EMIT syncDeleteMessage(ID,appName);
}
void NotificationManager::deleteAllMessage()
{
m_messages.clear();
m_nameID.clear();
Q_EMIT syncDeleteAllMessage();
}
void NotificationManager::deleteAppMessage(const QString &appName)
{
// QMap::iterator find_index = m_nameID.find(appName);
for (const QString &messageID : m_nameID.values(appName)) {
m_messages.remove(messageID);
}
m_nameID.remove(appName);
Q_EMIT syncDeleteAppMessage(appName);
}
void NotificationManager::openSystemSetting()
{
QStringList args;
args<<"-m"<<"Notice";
Sidebar::AppManager::getInstance(this)->launchAppWithArguments("/usr/share/applications/ukui-control-center.desktop", args, "ukui-control-center");
}
ukui-sidebar/src/notification/group-cache-proxy-model.cpp 0000664 0001750 0001750 00000014036 15167606206 022534 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "group-cache-proxy-model.h"
#include "notification-model.h"
#include
using namespace UkuiNotification;
GroupCacheProxyModel::GroupCacheProxyModel(QObject *parent) : QAbstractProxyModel(parent)
{
}
void GroupCacheProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
if (sourceModel == QAbstractProxyModel::sourceModel()) {
return;
}
beginResetModel();
if (QAbstractProxyModel::sourceModel()) {
QAbstractProxyModel::sourceModel()->disconnect(this);
}
QAbstractProxyModel::setSourceModel(sourceModel);
if (sourceModel) {
connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &GroupCacheProxyModel::onRowInserted);
// connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, [=] (const QModelIndex &parent, int first, int last) {
// qDebug() << "=rowsRemoved=" << first << last;
// });
connect(sourceModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &GroupCacheProxyModel::onRowRemoved);
connect(sourceModel, &QAbstractItemModel::dataChanged,this, &GroupCacheProxyModel::onDataChanged);
}
endResetModel();
}
QModelIndex GroupCacheProxyModel::index(int row, int column, const QModelIndex &parent) const
{
if (parent.isValid() || column > 0) {
return {};
}
return createIndex(row, column, nullptr);
}
QModelIndex GroupCacheProxyModel::parent(const QModelIndex &child) const
{
return {};
}
int GroupCacheProxyModel::rowCount(const QModelIndex &parent) const
{
if (sourceModel() && m_rootModelIndex.isValid()) {
return m_items.size();
}
return 0;
}
int GroupCacheProxyModel::columnCount(const QModelIndex &parent) const
{
return 1;
}
QModelIndex GroupCacheProxyModel::mapToSource(const QModelIndex &proxyIndex) const
{
if (m_rootModelIndex.isValid()) {
int r = proxyIndex.row();
if (r >= 0 && r < m_items.size()) {
QModelIndex modelIndex = m_items.at(r).sourceIndex;
return modelIndex;
}
}
return {};
}
QModelIndex GroupCacheProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
{
if (!sourceIndex.isValid() || !sourceIndex.parent().isValid()) {
return {};
}
if (sourceModel()->hasChildren(sourceIndex)) {
return {};
}
for (int i = 0; i < m_items.size(); ++i) {
if (m_items.at(i).sourceIndex == sourceIndex) {
return createIndex(i, sourceIndex.column(), nullptr);
}
}
return {};
}
QVariant GroupCacheProxyModel::data(const QModelIndex &proxyIndex, int role) const
{
if (!checkIndex(proxyIndex, CheckIndexOption::IndexIsValid)) {
return {};
}
return QAbstractProxyModel::data(mapToSource(proxyIndex), role);
}
void GroupCacheProxyModel::onRowInserted(const QModelIndex &parent, int first, int last)
{
if (!parent.isValid() || (parent != m_rootModelIndex)) {
return;
}
beginInsertRows(QModelIndex(), 0, (last - first));
for (int i = last; i >= last; --i) {
QModelIndex si = sourceModel()->index(i, 0, parent);
m_items.prepend(CacheItem(si.data(NotificationItem::Id).toUInt(), si));
}
endInsertRows();
}
void GroupCacheProxyModel::onRowRemoved(const QModelIndex &parent, int first, int last)
{
if (!parent.isValid() || parent != m_rootModelIndex) {
return;
}
int row = first;
QVector indexList;
for (int i = 0; i < m_items.size() && row <= last; ++i) {
auto item = m_items.at(i);
if (item.sourceIndex.row() == row) {
indexList.append(i);
++row;
}
}
for (const auto &index : indexList) {
Q_EMIT itemRemoved(index);
}
}
void GroupCacheProxyModel::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight,
const QVector &roles)
{
if ((topLeft.parent() != m_rootModelIndex) || !topLeft.isValid() || !topLeft.parent().isValid()) {
return;
}
Q_EMIT dataChanged(mapFromSource(topLeft), mapFromSource(bottomRight), roles);
}
void GroupCacheProxyModel::setRootIndex(QModelIndex rootIndex)
{
if (m_rootModelIndex == rootIndex) {
return;
}
beginResetModel();
m_rootModelIndex = rootIndex;
m_items.clear();
if (sourceModel()) {
for (int i = 0; i < sourceModel()->rowCount(m_rootModelIndex); ++i) {
auto si = sourceModel()->index(i, 0, m_rootModelIndex);
m_items.append(CacheItem(si.data(NotificationItem::Id).toUInt(), si));
}
}
endResetModel();
}
QModelIndex GroupCacheProxyModel::getRootIndex(int rootIndex)
{
if (sourceModel()) {
return sourceModel()->index(rootIndex, 0, QModelIndex());
}
return {};
}
//void GroupCacheProxyModel::removeItem(int index)
//{
// if (index >= 0 && index < m_items.size()) {
// auto item = m_items.at(index);
// qDebug() << "=removeItem=" << index << m_items.size() << item.sourceIndex.isValid();
// beginRemoveRows(QModelIndex(), index, 0);
// m_items.removeAt(index);
// endRemoveRows();
// }
//}
void GroupCacheProxyModel::removeItem(uint id)
{
int i = m_items.size() - 1;
for (; i >= 0; --i) {
if (m_items.at(i).id == id) {
beginRemoveRows(QModelIndex(), i, i);
m_items.removeAt(i);
endRemoveRows();
return;
}
}
}
ukui-sidebar/src/main.cpp 0000664 0001750 0001750 00000010334 15167643374 014324 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include
#include
#include
#include "qtsingleapplication.h"
#include "sidebar-main.h"
#include "log-utils.h"
QString parseArgs(const QStringList& args)
{
if (args.length() < 2) {
return {};
}
QCommandLineOption state({"S", "state"}, QObject::tr("Show the current state of the sidebar."));
QCommandLineOption show({"s", "show"}, QObject::tr("There are two options, 'notify' and 'control'."), "option");
QCommandLineOption quit({"q", "quit"}, QObject::tr("Quit sidebar."));
QCommandLineParser parser;
parser.addOption(state);
parser.addOption(show);
parser.addOption(quit);
bool pd = parser.parse(args);
if (pd) {
if (parser.isSet(state)) {
//state
return QStringLiteral("state");
} else if (parser.isSet(show)) {
//show
return QString("show %1").arg(parser.value(show));
} else if (parser.isSet(quit)) {
return QStringLiteral("quit");
}
} else {
qDebug() << "Parser Error:" << parser.errorText();
}
QCommandLineOption help = parser.addHelpOption();
QCommandLineOption version = parser.addVersionOption();
if (parser.isSet(version)) {
parser.showVersion();
} else {
if (!parser.unknownOptionNames().isEmpty()) {
qDebug() << "Unknown options:" << parser.unknownOptionNames();
}
parser.showHelp();
}
}
int main(int argc, char *argv[])
{
#ifndef UKUI_SIDEBAR_LOG_FILE_DISABLE
LogUtils::initLogFile("ukui-sidebar");
qInstallMessageHandler(LogUtils::messageOutput);
#endif
// qputenv("QT_SCALE_FACTOR", "1.0");
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) && QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// QGuiApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
#endif
QGuiApplication::setApplicationName(QObject::tr("ukui-sidebar"));
QGuiApplication::setApplicationVersion(VERSION);
QString sessionType(qgetenv("XDG_SESSION_TYPE"));
QString displayEnv = (sessionType == QStringLiteral("wayland")) ? QStringLiteral("WAYLAND_DISPLAY") : QStringLiteral("DISPLAY");
QString display(qgetenv(displayEnv.toUtf8().data()));
QString appid = QString("ukui-sidebar-qml-%1").arg(display);
qDebug() << "ukui-sidebar launch with:" << sessionType << "display:" << display << "appid:" << appid;
if(sessionType == QStringLiteral("wayland")) {
qputenv("QT_WAYLAND_DISABLE_FIXED_POSITIONS", "true");
//qputenv("QT_WAYLAND_SHELL_INTEGRATION", "ukui-shell");
}
QtSingleApplication app(appid, argc, argv);
QTranslator translator;
if (translator.load(QString(TRANSLATION_FILE_DIR) + "/ukui-sidebar_" + QLocale::system().name())) {
QtSingleApplication::installTranslator(&translator);
} else {
qWarning() << "Load translations file" << QLocale::system().name() << "failed!";
}
QString message = parseArgs(QtSingleApplication::arguments());
if (app.isRunning()) {
//已经有实例在运行
app.sendMessage(message);
return 0;
}
SidebarMain sidebar;
sidebar.parseMessage(message);
QObject::connect(&app, &QtSingleApplication::messageReceived, &sidebar, &SidebarMain::parseMessage);
return QtSingleApplication::exec();
}
ukui-sidebar/src/utils/ 0000775 0001750 0001750 00000000000 15167643374 014033 5 ustar feng feng ukui-sidebar/src/utils/event-track.h 0000664 0001750 0001750 00000002375 15167606206 016427 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef UKUI_SIDEBAR_EVENT_TRACK_H
#define UKUI_SIDEBAR_EVENT_TRACK_H
#include
#include
namespace Sidebar {
class EventTrack : public QObject
{
Q_OBJECT
public:
static EventTrack *qmlAttachedProperties(QObject *object);
static EventTrack *instance();
explicit EventTrack(QObject *parent = nullptr);
Q_INVOKABLE void sendSlideEvent(const QString& code, const QString& page, const QVariantMap &map = {});
};
} // Sidebar
QML_DECLARE_TYPEINFO(Sidebar::EventTrack, QML_HAS_ATTACHED_PROPERTIES)
#endif //UKUI_SIDEBAR_EVENT_TRACK_H
ukui-sidebar/src/utils/date-time-utils.cpp 0000664 0001750 0001750 00000015027 15167606206 017544 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "date-time-utils.h"
#include "libkydate.h"
#include
#include
#include
using namespace Sidebar;
#define HOUR_SYSTEM_CONTROL "org.ukui.control-center.panel.plugins"
#define DATA_FORMAT "date" //日期格式:yyyy/MM/dd、yyyy-MM-dd
#define TIME_FORMAT "hoursystem" //时间格式:12小时制、24小时制
#define KYSDK_TIMERSERVER "com.kylin.kysdk.TimeServer"
#define KYSDK_TIMERPATH "/com/kylin/kysdk/Timer"
#define KYSDK_TIMERINTERFACE "com.kylin.kysdk.TimeInterface"
DateTimeUtils::DateTimeUtils(QObject *parent) :
QObject(parent),
m_dataFormat("cn"),
m_hourSystem("24")
{
initGsettings();
//使用系统提供的sdk刷新时间显示
QDBusConnection::systemBus().connect(KYSDK_TIMERSERVER,
KYSDK_TIMERPATH,
KYSDK_TIMERINTERFACE,
"TimeChangeSignal",
this,
SLOT(timeSignalSlot()));
bool success = false;
success = QDBusConnection::systemBus().connect(KYSDK_TIMERSERVER,
KYSDK_TIMERPATH,
KYSDK_TIMERINTERFACE,
"TimeSignal",
this,
SLOT(timeSignalSlot()));
if(!success) {
m_timer = new QTimer(this);
m_timer->setInterval(1000);
connect(m_timer, &QTimer::timeout, this, &DateTimeUtils::timeSignalSlot);
m_timer->start();
}
QDBusConnection::sessionBus().connect("com.kylin.kysdk.DateServer",
"/com/kylin/kysdk/Date",
"com.kylin.kysdk.DateInterface",
"ShortDateSignal",
this, SLOT(setShortDateFormat(QString)));
setShortDateFormat();
}
DateTimeUtils::~DateTimeUtils()
{
if(m_timeGsettings) {
delete m_timeGsettings;
m_timeGsettings = nullptr;
}
}
QString DateTimeUtils::currentTime()
{
if(m_hourSystem == "24") {
return QDateTime::currentDateTime().toString("HH:mm");
} else {
return QDateTime::currentDateTime().toString("AP hh:mm");
}
}
QString DateTimeUtils::currentDate()
{
if(m_dataFormat == "cn") {
return QDateTime::currentDateTime().toString("MM/dd");
} else {
return QDateTime::currentDateTime().toString("MM-dd");
}
}
QString DateTimeUtils::currentWeekDay()
{
return QDateTime::currentDateTime().toString("ddd");
}
void DateTimeUtils::timeSignalSlot()
{
Q_EMIT timeUpdate(currentTime());
Q_EMIT dateUpdate(currentDate());
Q_EMIT weekDayUpdate(currentWeekDay());
Q_EMIT timeRefresh();
}
void DateTimeUtils::setShortDateFormat(QString shortDateFormat)
{
if (shortDateFormat == "") {
char* date = kdk_system_get_shortformat();
shortDateFormat = date;
free(date);
}
if (shortDateFormat == "") {
shortDateFormat = "yyyy/MM/dd";
}
if (shortDateFormat == m_shortDateFormat) return;
m_shortDateFormat = shortDateFormat;
Q_EMIT timeRefresh();
}
QString DateTimeUtils::computeTimeOut(QDateTime timeStamp)
{
QDateTime currentDateTime(QDateTime::currentDateTime());
int dateDiff = currentDateTime.date().toJulianDay() - timeStamp.date().toJulianDay();
// 一分钟之内
if (timeStamp <= currentDateTime && currentDateTime < timeStamp.addSecs(60)) {
return QString(tr("Now"));
// 一天之内
} else if (dateDiff == 0 && timeStamp <= currentDateTime ) {
if (m_hourSystem == "24") {
return timeStamp.toString("HH:mm");
} else {
return timeStamp.toString("AP h:mm");
}
// 一天
} else if (dateDiff == 1) {
if (m_hourSystem == "24") {
return QString(tr("Yesterday ")).append(timeStamp.toString("HH:mm"));
} else {
return QString(tr("Yesterday ")).append(timeStamp.toString("AP h:mm"));
}
// 大于一天且在一周之内
} else if (1 < dateDiff && 7 > dateDiff) {
if(m_hourSystem == "24") {
return timeStamp.toString("ddd HH:mm");
} else {
return timeStamp.toString("ddd AP h:mm");
}
// 超过一周
} else if (dateDiff >= 7) {
return timeStamp.toString(m_shortDateFormat);
// 时间设置为过去
} else if (currentDateTime < timeStamp) {
return timeStamp.toString(m_shortDateFormat);
// 其他情况
} else {
if (m_hourSystem == "24") {
return timeStamp.toString(m_shortDateFormat + " HH:mm");
} else {
return timeStamp.toString(m_shortDateFormat + " AP h:mm");
}
}
}
void DateTimeUtils::initGsettings()
{
const QByteArray id(HOUR_SYSTEM_CONTROL);
if (QGSettings::isSchemaInstalled(id)) {
m_timeGsettings = new QGSettings(id);
connect(m_timeGsettings, &QGSettings::changed, this, [=] (const QString &key) {
if (key == DATA_FORMAT) {
m_dataFormat = m_timeGsettings->get(DATA_FORMAT).toString();
Q_EMIT dateUpdate(currentDate());
} else if(key == TIME_FORMAT) {
m_hourSystem = m_timeGsettings->get(TIME_FORMAT).toString();
Q_EMIT timeUpdate(currentTime());
}
});
QStringList ketList = m_timeGsettings->keys();
if(ketList.contains(DATA_FORMAT))
m_dataFormat = m_timeGsettings->get(DATA_FORMAT).toString();
if(ketList.contains(TIME_FORMAT))
m_hourSystem = m_timeGsettings->get(TIME_FORMAT).toString();
}
}
ukui-sidebar/src/utils/date-time-utils.h 0000664 0001750 0001750 00000003406 15167606206 017207 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef DATETIMEUTILS_H
#define DATETIMEUTILS_H
#include
#include
#include
#include
namespace Sidebar {
class DateTimeUtils : public QObject
{
Q_OBJECT
public:
explicit DateTimeUtils(QObject *parent = nullptr);
~DateTimeUtils();
Q_INVOKABLE QString currentTime();
Q_INVOKABLE QString currentDate();
Q_INVOKABLE QString currentWeekDay();
/**
* 计算源时间与现在时刻的时间差值
* @brief computeTimeOut
* @param srcDate
* @return
*/
Q_INVOKABLE QString computeTimeOut(QDateTime timeStamp);
Q_SIGNALS:
void timeUpdate(const QString&);
void dateUpdate(const QString&);
void weekDayUpdate(const QString&);
void timeRefresh();
private Q_SLOTS:
void timeSignalSlot();
void setShortDateFormat(QString shortDateFormat = "");
private:
void initGsettings();
QString m_dataFormat;
QString m_hourSystem;
QString m_shortDateFormat;
QGSettings *m_timeGsettings = nullptr;
QTimer *m_timer = nullptr;
signals:
};
}
#endif // DATETIMEUTILS_H
ukui-sidebar/src/utils/weather-helper.h 0000664 0001750 0001750 00000002414 15167606206 017112 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef WEATHERHELPER_H
#define WEATHERHELPER_H
#include
#include
namespace Sidebar {
class WeatherHelper : public QObject
{
Q_OBJECT
public:
explicit WeatherHelper(QObject *parent = nullptr);
Q_INVOKABLE QString getWeather();
Q_INVOKABLE QString getIcon();
public Q_SLOTS:
void openWeather();
Q_SIGNALS:
void weatherInfoChanged(QString weather, QString icon);
private:
bool extractWeatherInfo(QString weatherInfo);
QGSettings *m_gsettings = nullptr;
QString m_weather;
QString m_icon;
};
}
#endif // WEATHERHELPER_H
ukui-sidebar/src/utils/weather-helper.cpp 0000664 0001750 0001750 00000004755 15167606206 017457 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "weather-helper.h"
#include "app-manager.h"
#include
#include
#include
#define KYLIN_WEATHER_SETTING "org.kylin-weather.settings"
#define WEATHER_KEY "weather"
using namespace Sidebar;
WeatherHelper::WeatherHelper(QObject *parent) : QObject(parent)
{
const QByteArray id(KYLIN_WEATHER_SETTING);
if(QGSettings::isSchemaInstalled(id)) {
m_gsettings = new QGSettings(id);
if(m_gsettings->keys().contains(WEATHER_KEY, Qt::CaseInsensitive)) {
extractWeatherInfo(m_gsettings->get(WEATHER_KEY).toString());
} else {
qWarning() << "WeatherHelper:" << "can't find key :" << WEATHER_KEY;
}
connect(m_gsettings, &QGSettings::changed, this, [ & ](const QString & key) {
if(key == WEATHER_KEY) {
if(extractWeatherInfo(m_gsettings->get(WEATHER_KEY).toString())) {
Q_EMIT weatherInfoChanged(m_weather, m_icon);
}
}
});
} else {
qWarning() << "WeatherHelper:" << "can't find gsettings :" << KYLIN_WEATHER_SETTING;
}
}
QString WeatherHelper::getWeather()
{
return m_weather;
}
QString WeatherHelper::getIcon()
{
return m_icon;
}
void WeatherHelper::openWeather()
{
Sidebar::AppManager::getInstance(this)->launchApp("/usr/share/applications/kylin-weather.desktop", "kylin-weather");
}
bool WeatherHelper::extractWeatherInfo(QString weatherInfo)
{
QStringList weatherInfoList = weatherInfo.split(",");
if(weatherInfoList.size() < 7) {
qWarning() << "WeatherHelper:" << "Get Weather info error!";
return false;
}
m_weather = weatherInfoList.at(2) + weatherInfoList.at(3) + weatherInfoList.at(5);
m_icon = weatherInfoList.at(8);
return true;
}
ukui-sidebar/src/utils/event-track.cpp 0000664 0001750 0001750 00000004527 15167643374 016772 0 ustar feng feng /*
* Copyright (C) 2023, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include "event-track.h"
#include
namespace Sidebar {
KCustomProperty* appendCustomProp(KTrackData *data, const QVariantMap &map)
{
if (!data || map.isEmpty()) {
return nullptr;
}
int i = 0;
auto properties = new KCustomProperty[map.size()];
QMapIterator it(map);
while (it.hasNext()) {
it.next();
std::string string = it.key().toStdString();
properties[i].key = strdup(string.c_str());
string = it.value().toString().toStdString();
properties[i].value = strdup(string.c_str());
++i;
}
return properties;
}
void freeKCustomProperty(KCustomProperty *customProperty, int size)
{
for (int i = 0; i < size; ++i) {
delete customProperty[i].key;
delete customProperty[i].value;
}
delete [] customProperty;
}
EventTrack::EventTrack(QObject *parent) : QObject(parent)
{
}
void EventTrack::sendSlideEvent(const QString& code, const QString& page, const QVariantMap &map)
{
KTrackData* data = kdk_dia_data_init(KEVENTSOURCE_DESKTOP, KEVENT_CUSTOM);
KCustomProperty* properties = appendCustomProp(data, map);
if (properties) {
kdk_dia_append_custom_property(data, properties, map.size());
}
kdk_dia_upload_default(data, code.toUtf8().data(), page.toUtf8().data());
kdk_dia_data_free(data);
freeKCustomProperty(properties, map.size());
}
EventTrack *EventTrack::qmlAttachedProperties(QObject *object)
{
Q_UNUSED(object)
return EventTrack::instance();
}
EventTrack *EventTrack::instance()
{
static EventTrack eventTrack;
return &eventTrack;
}
} // Sidebar
ukui-sidebar/src/main/ 0000775 0001750 0001750 00000000000 15167643374 013617 5 ustar feng feng ukui-sidebar/src/main/hand-gesture-helper.h 0000664 0001750 0001750 00000002636 15167606206 017633 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#ifndef HANDGESTUREHELPER_H
#define HANDGESTUREHELPER_H
#include
namespace Sidebar {
class HandGestureHelper : public QObject
{
Q_OBJECT
public:
static HandGestureHelper* getInstance();
virtual ~HandGestureHelper();
public Q_SLOTS:
void callNotificationCenter(int posY);
void callControlCenter(int posX);
void top2BottomRelease(int posX, int posY);
void right2LeftRelease(int posX, int posY);
Q_SIGNALS:
void notificationCenterCalled(int posY);
void controlCenterCalled(int posX);
void top2BottomReleased(int posX, int posY);
void right2LeftReleased(int posX, int posY);
private:
explicit HandGestureHelper(QObject *parent = nullptr);
};
}
#endif // HANDGESTUREHELPER_H
ukui-sidebar/src/main/global-settings.cpp 0000664 0001750 0001750 00000025473 15167606206 017425 0 ustar feng feng /*
* Copyright (C) 2022, KylinSoft Co., Ltd.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
#include
#include
#include
#include
#include
#include "global-settings.h"
#define UKUI_PANEL_SETTING "org.ukui.panel.settings"
using namespace Sidebar;
static std::once_flag onceFlag;
static GlobalSettings *g_globalSettings = nullptr;
static GSettings * m_settings = nullptr;
static GSettingsSchema * m_schema = nullptr;
static const char *m_panelLengthKey = "panellength";
GlobalSettings *GlobalSettings::globalInstance(QObject *parent)
{
std::call_once(onceFlag, [ & ] {
g_globalSettings = new GlobalSettings(parent);
});
return g_globalSettings;
}
GlobalSettings::GlobalSettings(QObject *parent) : QObject(parent)
{
// 1.加载主题 gsetting
initStyleSettings();
initControlCenterSettings();
// 2.加载平板模式设置
initStatusManagerDbus();
initPanelMonitor();
// 3.缩放相关
// initUSDCenterSettings();
initUSDSetting();
initPanelGSettings();
}
GlobalSettings::~GlobalSettings()
{
if (m_settings) {
g_object_unref(m_settings);
}
if (m_schema) {
g_settings_schema_unref(m_schema);
}
g_globalSettings = nullptr;
}
const QVariant GlobalSettings::getValue(const QString &key)
{
if (m_cache.contains(key)) {
return m_cache.value(key);
}
return {};
}
const QStringList GlobalSettings::getKeys()
{
return m_cache.keys();
}
int GlobalSettings::getPanelLength(QString screenName)
{
if (!m_settings || !m_schema) return -1;
if (!isKeysContain(m_panelLengthKey)) return -1;
QMap map = getPanelLengthMap();
if (!map.contains(screenName)) {
return -1;
}
return map.value(screenName).toInt();
}
void GlobalSettings::initStyleSettings()
{
insertValue(UKUI_STYLE_NAME_KEY, DEFAULT_STYLE);
insertValue(UKUI_STYLE_WINDOW_RADIUS_KEY, 12);
const QByteArray id(UKUI_STYLE_SETTING);
if (QGSettings::isSchemaInstalled(id)) {
auto *settings = new QGSettings(id, QByteArray(), this);
connect(settings, &QGSettings::changed, this, [=](const QString &key) {
if (key == UKUI_STYLE_NAME_KEY || key == UKUI_STYLE_THEME_COLOR_KEY || key == UKUI_STYLE_WINDOW_RADIUS_KEY) {
insertValue(key, settings->get(key));
Q_EMIT valueChanged(key);
}
});
QStringList keys = settings->keys();
if (keys.contains(UKUI_STYLE_NAME_KEY)) {
insertValue(UKUI_STYLE_NAME_KEY, settings->get(UKUI_STYLE_NAME_KEY));
}
if (keys.contains(UKUI_STYLE_WINDOW_RADIUS_KEY)) {
insertValue(UKUI_STYLE_WINDOW_RADIUS_KEY, settings->get(UKUI_STYLE_WINDOW_RADIUS_KEY));
}
}
}
void GlobalSettings::insertValue(const QString &key, const QVariant &value)
{
m_cache.insert(key,value);
}
void GlobalSettings::initStatusManagerDbus()
{
m_cache.insert(TABLET_MODE, false);
//dbus
m_statusManagerDBus = new QDBusInterface(DBUS_STATUS_MANAGER_IF, "/" , DBUS_STATUS_MANAGER_IF, QDBusConnection::sessionBus(), this);
if (m_statusManagerDBus && m_statusManagerDBus->isValid()) {
//平板模式切换
connect(m_statusManagerDBus, SIGNAL(mode_change_signal(bool)), this, SLOT(updateTabletStatus(bool)));
QDBusReply message = m_statusManagerDBus->call("get_current_tabletmode");
if (message.isValid()) {
m_cache.insert(TABLET_MODE, message.value());
}
}
}
void GlobalSettings::updateTabletStatus(bool isTabletMode)
{
m_cache.insert(TABLET_MODE, isTabletMode);
Q_EMIT valueChanged(TABLET_MODE);
}
void GlobalSettings::initControlCenterSettings()
{
insertValue(CONTROL_CENTER_EFFECT, false);
insertValue(CONTROL_CENTER_TRANSPARENCY_KEY, 1.0);
const QByteArray id(CONTROL_CENTER_SETTING);
if (QGSettings::isSchemaInstalled(id)) {
auto *settings = new QGSettings(id, QByteArray(), this);
connect(settings, &QGSettings::changed, this, [=](const QString &key) {
if (key == CONTROL_CENTER_TRANSPARENCY_KEY || key == CONTROL_CENTER_EFFECT) {
insertValue(key, settings->get(key));
Q_EMIT valueChanged(key);
}
});
QStringList keys = settings->keys();
if (keys.contains(CONTROL_CENTER_TRANSPARENCY_KEY)) {
insertValue(CONTROL_CENTER_TRANSPARENCY_KEY, settings->get(CONTROL_CENTER_TRANSPARENCY_KEY));
}
if (keys.contains(CONTROL_CENTER_EFFECT)) {
insertValue(CONTROL_CENTER_EFFECT, settings->get(CONTROL_CENTER_EFFECT));
}
}
}
void GlobalSettings::initUSDSetting()
{
m_cache.insert(IS_LITE_MODE, false);
const QString service = QStringLiteral("org.ukui.SettingsDaemon");
const QString path = QStringLiteral("/GlobalSignal");
const QString interface = QStringLiteral("org.ukui.SettingsDaemon.GlobalSignal");
QDBusInterface dBusInterface(service, path, interface);
if (dBusInterface.isValid()) {
QDBusReply reply = dBusInterface.call(QStringLiteral("getUKUILiteAnimation"));
if (reply.isValid()) {
QMap m;
m.insert("animation", reply.value());
updateIsLiteMode(m);
}
}
QDBusConnection::sessionBus().connect(service, path, interface, "UKUILiteChanged", this, SLOT(updateIsLiteMode));
}
void GlobalSettings::initPanelMonitor()
{
m_cache.insert(UKUI_PANEL_POSITION_KEY, 0);
m_cache.insert(UKUI_PANEL_SIZE_KEY, 48);
const QByteArray id(UKUI_PANEL_SETTING);
if (QGSettings::isSchemaInstalled(id)) {
auto panelGSetting = new QGSettings(id, QByteArray(), this);
QStringList keys = panelGSetting->keys();
if (keys.contains(UKUI_PANEL_POSITION_KEY)) {
m_cache.insert(UKUI_PANEL_POSITION_KEY, panelGSetting->get(UKUI_PANEL_POSITION_KEY));
}
if (keys.contains(UKUI_PANEL_SIZE_KEY)) {
m_cache.insert(UKUI_PANEL_SIZE_KEY, panelGSetting->get(UKUI_PANEL_SIZE_KEY));
}
if (keys.contains(UKUI_PANEL_TYPE_KEY)) {
m_cache.insert(UKUI_PANEL_TYPE_KEY, panelGSetting->get(UKUI_PANEL_TYPE_KEY));
}
if (keys.contains(UKUI_SETTINGS_ISLAND_POSITION_KEY)) {
m_cache.insert(UKUI_SETTINGS_ISLAND_POSITION_KEY, panelGSetting->get(UKUI_SETTINGS_ISLAND_POSITION_KEY));
}
if (keys.contains(UKUI_DATA_ISLAND_POSITION_KEY)) {
m_cache.insert(UKUI_DATA_ISLAND_POSITION_KEY, panelGSetting->get(UKUI_DATA_ISLAND_POSITION_KEY));
}
if (keys.contains(UKUI_TOPBAR_SIZE_KEY)) {
m_cache.insert(UKUI_TOPBAR_SIZE_KEY, panelGSetting->get(UKUI_TOPBAR_SIZE_KEY));
}
connect(panelGSetting, &QGSettings::changed, this, [this, panelGSetting] (const QString &key) {
if (key == UKUI_PANEL_POSITION_KEY || key == UKUI_PANEL_SIZE_KEY ||
key == UKUI_PANEL_TYPE_KEY || key == UKUI_SETTINGS_ISLAND_POSITION_KEY ||
key == UKUI_DATA_ISLAND_POSITION_KEY || key == UKUI_TOPBAR_SIZE_KEY) {
insertValue(key, panelGSetting->get(key));
Q_EMIT valueChanged(key);
}
if (key == UKUI_PANEL_LENGTH_KEY) {
Q_EMIT valueChanged(key);
}
});
}
}
void GlobalSettings::initPanelGSettings()
{
GSettingsSchemaSource *source;
source = g_settings_schema_source_get_default();
m_schema = g_settings_schema_source_lookup(source, "org.ukui.panel.settings", true);
if (!m_schema) {
m_settings = nullptr;
return;
}
m_settings = g_settings_new_with_path("org.ukui.panel.settings", "/org/ukui/panel/settings/");
}
bool GlobalSettings::isKeysContain(const char *key)
{
if (!m_settings || !m_schema) return false;
gchar **keys = g_settings_schema_list_keys(m_schema);
if (g_strv_contains(keys, key)) {
g_strfreev(keys);
return true;
} else {
g_strfreev(keys);
return false;
}
}
QMap GlobalSettings::getPanelLengthMap()
{
GVariant *gvalue = g_settings_get_value(m_settings, m_panelLengthKey);
GVariantIter iter;
QMap map;
const gchar *key;
size_t str_len;
GVariant *val = NULL;
g_variant_iter_init (&iter, gvalue);
QVariant qvar;
while (g_variant_iter_next (&iter, "{&sv}", &key, &val)) {
if (g_variant_is_of_type(val, G_VARIANT_TYPE_UINT32)) {
qvar = QVariant::fromValue(static_cast(g_variant_get_uint32(val)));
map.insert(key, qvar);
}
}
g_variant_unref(gvalue);
return map;
}
void GlobalSettings::updateIsLiteMode(QMap