ukui-sidebar/0000775000175000017500000000000015167643374012104 5ustar fengfengukui-sidebar/src/0000775000175000017500000000000015167643374012673 5ustar fengfengukui-sidebar/src/sidebar-dbus-service.h0000664000175000017500000000252315167606206017041 0ustar fengfeng/* * 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/0000775000175000017500000000000015167643374014365 5ustar fengfengukui-sidebar/src/windows/urgency-notification-window.h0000664000175000017500000000260615167606206022200 0ustar fengfeng/* * 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.h0000664000175000017500000000265715167606206017576 0ustar fengfeng/* * 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.cpp0000664000175000017500000000733115167643374020623 0ustar fengfeng/* * 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.h0000664000175000017500000000217515167606206017022 0ustar fengfeng/* * 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.h0000664000175000017500000000367215167606206020532 0ustar fengfeng/* * 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.h0000664000175000017500000000413315167606206020114 0ustar fengfeng/* * 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.cpp0000664000175000017500000001061515167606206022532 0ustar fengfeng/* * 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.h0000664000175000017500000000271615167606206021206 0ustar fengfeng/* * 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.cpp0000664000175000017500000000744215167643374021273 0ustar fengfeng/* * 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.cpp0000664000175000017500000003011215167643374017447 0ustar fengfeng/* * 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.h0000664000175000017500000000476215167606206021674 0ustar fengfeng/* * 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.h0000664000175000017500000000547615167643374020115 0ustar fengfeng/* * 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.h0000664000175000017500000000757615167643374017136 0ustar fengfeng/* * 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.cpp0000664000175000017500000001325215167606206020122 0ustar fengfeng/* * 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.cpp0000664000175000017500000001440015167606206021054 0ustar fengfeng/* * 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.h0000664000175000017500000000331715167643374020270 0ustar fengfeng/* * 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.h0000664000175000017500000000321515167643374020732 0ustar fengfeng/* * 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.cpp0000664000175000017500000003503115167643374020436 0ustar fengfeng/* * 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.cpp0000664000175000017500000002171315167643374020461 0ustar fengfeng/* * 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.cpp0000664000175000017500000001400215167643374021537 0ustar fengfeng/* * 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.cpp0000664000175000017500000002721315167643374022232 0ustar fengfeng/* * 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/0000775000175000017500000000000015167643374015361 5ustar fengfengukui-sidebar/src/notification/popup-notification-model.cpp0000664000175000017500000000410215167606206023000 0ustar fengfeng/* * 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.cpp0000664000175000017500000000425215167606206021705 0ustar fengfeng/* * 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.h0000664000175000017500000000517015167606206022200 0ustar fengfeng/* * 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.h0000664000175000017500000001264615167643374021327 0ustar fengfeng/* * 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.h0000664000175000017500000000347615167606206021633 0ustar fengfeng/* * 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.h0000664000175000017500000000537215167606206022450 0ustar fengfeng/* * 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.cpp0000664000175000017500000000333115167606206023314 0ustar fengfeng/* * 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.h0000664000175000017500000000242215167606206022450 0ustar fengfeng/* * 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.h0000664000175000017500000000255515167606206022770 0ustar fengfeng/* * 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.cpp0000664000175000017500000007147415167643374021666 0ustar fengfeng/* * 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.h0000664000175000017500000000473515167606206021360 0ustar fengfeng/* * 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.cpp0000664000175000017500000003112415167606206022775 0ustar fengfeng/* * 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.cpp0000664000175000017500000000531415167606206022157 0ustar fengfeng/* * 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.cpp0000664000175000017500000001403615167606206022534 0ustar fengfeng/* * 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.cpp0000664000175000017500000001033415167643374014324 0ustar fengfeng/* * 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/0000775000175000017500000000000015167643374014033 5ustar fengfengukui-sidebar/src/utils/event-track.h0000664000175000017500000000237515167606206016427 0ustar fengfeng/* * 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.cpp0000664000175000017500000001502715167606206017544 0ustar fengfeng/* * 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.h0000664000175000017500000000340615167606206017207 0ustar fengfeng/* * 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.h0000664000175000017500000000241415167606206017112 0ustar fengfeng/* * 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.cpp0000664000175000017500000000475515167606206017457 0ustar fengfeng/* * 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.cpp0000664000175000017500000000452715167643374016772 0ustar fengfeng/* * 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/0000775000175000017500000000000015167643374013617 5ustar fengfengukui-sidebar/src/main/hand-gesture-helper.h0000664000175000017500000000263615167606206017633 0ustar fengfeng/* * 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.cpp0000664000175000017500000002547315167606206017425 0ustar fengfeng/* * 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 map) { if (map.contains("animation")) { insertValue(IS_LITE_MODE, map.value("animation").toString() == QStringLiteral("lite")); Q_EMIT valueChanged(IS_LITE_MODE); } } void GlobalSettings::initUSDCenterSettings() { insertValue(USD_SCALING_FACTOR_KEY, 1.0); const QByteArray id(USD_SETTING); if (QGSettings::isSchemaInstalled(id)) { auto *settings = new QGSettings(id, QByteArray(), this); connect(settings, &QGSettings::changed, this, [=](const QString &key) { if (key == USD_SCALING_FACTOR_KEY) { insertValue(key, settings->get(key)); Q_EMIT valueChanged(key); } }); QStringList keys = settings->keys(); if (keys.contains(USD_SCALING_FACTOR_KEY)) { insertValue(USD_SCALING_FACTOR_KEY, settings->get(USD_SCALING_FACTOR_KEY)); } } } SettingMonitor::SettingMonitor(QObject *parent) : QObject(parent) { connect(GlobalSettings::globalInstance(), &GlobalSettings::valueChanged, this, &SettingMonitor::valueChangedSlot); } QStringList SettingMonitor::keys() { return m_keys; } void SettingMonitor::setKeys(QStringList &keys) { if (keys == m_keys) { return; } m_keys.clear(); m_keys.append(keys); Q_EMIT keysChanged(); } void SettingMonitor::valueChangedSlot(const QString &key) { if (m_keys.contains(key)) { Q_EMIT valueChanged(key); } } QVariant SettingMonitor::getValue(const QString &key) { return GlobalSettings::globalInstance()->getValue(key); } ukui-sidebar/src/main/app-manager.cpp0000664000175000017500000000636015167606206016511 0ustar fengfeng/* * 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 "app-manager.h" #include #include #include #include #include #define KYLIN_APP_MANAGER_NAME "com.kylin.ProcessManager" #define KYLIN_APP_MANAGER_PATH "/com/kylin/ProcessManager/AppLauncher" #define KYLIN_APP_MANAGER_INTERFACE "com.kylin.ProcessManager.AppLauncher" namespace Sidebar { static AppManager *globalInstance = nullptr; AppManager *AppManager::getInstance(QObject *parent) { if (!globalInstance) { globalInstance = new AppManager(parent); } return globalInstance; } void AppManager::launchApp(const QString &desktopFile, const QString &applicationName) { QDBusMessage message = QDBusMessage::createMethodCall(KYLIN_APP_MANAGER_NAME, KYLIN_APP_MANAGER_PATH, KYLIN_APP_MANAGER_INTERFACE, "LaunchApp"); message << desktopFile; auto watcher = new QDBusPendingCallWatcher(QDBusConnection::sessionBus().asyncCall(message), this); connect(watcher, &QDBusPendingCallWatcher::finished, this, [applicationName] (QDBusPendingCallWatcher *self) { if (self) { if (self->isError()) { qWarning() << self->error().message(); QProcess::startDetached(applicationName, QStringList(), ""); } self->deleteLater(); } }); } void AppManager::launchAppWithArguments(const QString &desktopFile, const QStringList &args, const QString &applicationName) { QDBusMessage message = QDBusMessage::createMethodCall(KYLIN_APP_MANAGER_NAME, KYLIN_APP_MANAGER_PATH, KYLIN_APP_MANAGER_INTERFACE, "LaunchAppWithArguments"); message << desktopFile << args; auto watcher = new QDBusPendingCallWatcher(QDBusConnection::sessionBus().asyncCall(message), this); connect(watcher, &QDBusPendingCallWatcher::finished, this, [applicationName, args] (QDBusPendingCallWatcher *self) { if (self) { if (self->isError()) { qWarning() << self->error().message(); QProcess::startDetached(applicationName, args, ""); } self->deleteLater(); } }); } AppManager::AppManager(QObject *parent) : QObject(parent) { } AppManager::~AppManager() = default; } // Sidebar ukui-sidebar/src/main/color-helper.h0000664000175000017500000000516115167606206016357 0ustar fengfeng/* * 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-8-15. // #ifndef UKUI_SIDEBAR_COLOR_HELPER_H #define UKUI_SIDEBAR_COLOR_HELPER_H #include "value-type.h" #include #include #include namespace Sidebar { class ColorHelper : public QObject { Q_OBJECT public: static ColorHelper *getInstance(); ~ColorHelper() override = default; // 当前界面是否为深色主题 Q_INVOKABLE bool isDarkStyle(); /** * 根据提供的颜色枚举值,返回对应的颜色 * 用于适配主题,统一颜色显示 * @param colorRole * @return */ Q_INVOKABLE QColor pluginColor(UkuiShortcut::Color::ColorRole colorRole); Q_INVOKABLE QColor pluginColorWithCustomTransparency(UkuiShortcut::Color::ColorRole colorRole, qreal alphaF); Q_INVOKABLE QColor pluginColorHover(UkuiShortcut::Color::ColorRole colorRole); Q_INVOKABLE QColor pluginColorPressed(UkuiShortcut::Color::ColorRole colorRole); /** * 带有主题透明度的插件颜色 * @param colorRole * @return */ Q_INVOKABLE QColor pluginColorWithTransparency(UkuiShortcut::Color::ColorRole colorRole); /** * 判断一个颜色是否为高亮色 * 比如:如果一个图标的背景颜色为高亮色,那么这个图标需要进行反色显示,否则会看不清图标内容 * !!! 只能判断插件显示的颜色是否高亮色 * @param colorRole 颜色枚举值 * @return */ Q_INVOKABLE bool isHighLightColor(UkuiShortcut::Color::ColorRole colorRole); Q_INVOKABLE QColor separator() const; // 侧边栏蒙版颜色 Q_INVOKABLE QColor mask() const; private: explicit ColorHelper(QObject *parent = nullptr); private Q_SLOTS: void styleChangedSlot(const QString &key = ""); Q_SIGNALS: void styleColorChanged(); private: bool m_isDarkStyle = false; qreal m_transparency = 1.0; }; } // UkuiShortcut #endif //UKUI_SIDEBAR_COLOR_HELPER_H ukui-sidebar/src/main/app-manager.h0000664000175000017500000000261515167606206016155 0ustar fengfeng/* * 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-10-11. // #ifndef UKUI_SIDEBAR_APP_MANAGER_H #define UKUI_SIDEBAR_APP_MANAGER_H #include class QDBusInterface; namespace Sidebar { class AppManager : public QObject { Q_OBJECT public: static AppManager *getInstance(QObject *parent = nullptr); ~AppManager() override; Q_INVOKABLE void launchApp(const QString &desktopFile, const QString &applicationName); Q_INVOKABLE void launchAppWithArguments(const QString &desktopFile, const QStringList &args, const QString &applicationName); private: explicit AppManager(QObject *parent); private: QDBusInterface *m_appManagerDbusInterface = nullptr; }; } // Sidebar #endif //UKUI_SIDEBAR_APP_MANAGER_H ukui-sidebar/src/main/account-information.h0000664000175000017500000000765415167643374017763 0ustar fengfeng/* * 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 ACCOUNTINFORMATION_H #define ACCOUNTINFORMATION_H #include #include #include #include namespace UkuiShortcut { typedef struct UserInfo { bool current; bool isLogged; bool autologin; bool noPwdLogin; int accountType; int passwdType; qint64 uid; QString objPath; QString username; QString realName; QString iconFile; QString passwd; } UserInformation; class PowerButton : public QObject { Q_OBJECT Q_PROPERTY(bool isEnable READ isEnable NOTIFY isEnableChanged) Q_PROPERTY(QString icon READ icon NOTIFY iconChanged) Q_PROPERTY(QString tooltip READ tooltip NOTIFY tooltipChanged) Q_PROPERTY(QString percentage READ percentage NOTIFY percentageChanged) public: explicit PowerButton(QObject *parent = nullptr); ~PowerButton() override; bool isEnable(); QString icon(); QString tooltip(); QString percentage(); Q_SIGNALS: void isEnableChanged(); void iconChanged(); void tooltipChanged(); void percentageChanged(); private: void initPowerBatteryIface(); void getBatteryInfo(); private Q_SLOTS: void onServiceUnregistered(); void onConnectorReady(QDBusInterface* interface); void onBatteryIconChanged(QString iconName); void onPercentageChanged(double percentage); void onBatteryShowIcon(bool isEnable); private: bool m_isEnable = false; QString m_icon = ""; QString m_tooltip = ""; QString m_percentage = ""; bool m_iconNeedRefresh = false; bool m_percentageNeedRefresh = false; bool m_isEnableNeedRefresh = false; QDBusInterface *m_powerBatteryIface = nullptr; QDBusServiceWatcher *m_powerServiceWatcher = nullptr; }; class AccountInformation : public QObject { Q_OBJECT Q_PROPERTY(QString username READ getUsername NOTIFY userInfoChanged) Q_PROPERTY(QString realName READ getRealName NOTIFY userInfoChanged) Q_PROPERTY(QString iconFile READ getIconFile NOTIFY userInfoChanged) Q_PROPERTY(QString accountType READ getAccountType NOTIFY userInfoChanged) public: explicit AccountInformation(QObject *parent = nullptr); ~AccountInformation() override; Q_INVOKABLE QString getUsername(); Q_INVOKABLE QString getRealName(); Q_INVOKABLE QString getIconFile(); Q_INVOKABLE QString getAccountType(); Q_INVOKABLE void openUserCenter(); Q_INVOKABLE void openPeonyUser(); Q_INVOKABLE void openControlCenter(); Q_INVOKABLE void openPowerButton(); private: void initMemberVariable(); void registeredAccountsDbus(); void initUserInfo(); QStringList getUserObjectPath(); UserInformation GetUserInformation(const QString &objectPath); private Q_SLOTS: void currentAccountUpdateSlot(const QString &property, const QMap &propertyMap, const QStringList &propertyList); Q_SIGNALS: void userInfoChanged(); private: QDBusInterface *m_systemUserIFace = nullptr; //用于监听当前登录用户的信息变化信号 QDBusInterface *m_currentUserIFace = nullptr; UserInformation m_currentUserInfo; QString m_administrator; QString m_standardUser; }; } #endif // ACCOUNTINFORMATION_H ukui-sidebar/src/main/screen-monitor.h0000664000175000017500000000555315167606206016735 0ustar fengfeng/* * 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-8-4. // #ifndef UKUI_SIDEBAR_SCREEN_MONITOR_H #define UKUI_SIDEBAR_SCREEN_MONITOR_H #define UKUI_PANEL_SETTING "org.ukui.panel.settings" #define UKUI_PANEL_POSITION_KEY "panelposition" #define UKUI_PANEL_SIZE_KEY "panelsize" #include #include #include #include namespace Sidebar { /** * 用于监听主屏幕的变化 * 获取主屏幕坐标,尺寸等 */ class ScreenMonitor : public QObject { Q_OBJECT Q_PROPERTY(QScreen* primaryScreen READ getPrimaryScreen NOTIFY primaryScreenChanged) Q_PROPERTY(QRect geometry READ getGeometry NOTIFY geometryChanged) public: static ScreenMonitor* getInstance(); Q_INVOKABLE int getPanelPosition(); Q_INVOKABLE int getPanelSize(); bool getScreenLockState(); public Q_SLOTS: qreal screenRatio(); QScreen *getPrimaryScreen(); QRect getGeometry(); Qt::LayoutDirection getLayoutDirection(); void primaryScreenChangedSlot(QScreen *screen); void screenRemovedSlot(QScreen *screen); void screenAddedSlot(QScreen *screen); void panelPropertyChangedSlot(const QString& key); void layoutDirectionChangedSlot(Qt::LayoutDirection direction); void screenLockSlot(); void screenUnLockSlot(); Q_SIGNALS: void primaryScreenChanged(); void geometryChanged(const QRect &geometry); // 任务栏的位置和大小变化 void panelPropertyChanged(); void layoutDirectionChanged(); void screenLockStateChanged(bool isLocked); void screenRemoved(QScreen *screen); private: explicit ScreenMonitor(QObject *parent = nullptr); void initPanelMonitor(); void initScreenSaver(); /** * 任务栏位置与屏幕:上: 1, 下: 0, 左: 2, 右: 3 * 如果为其他值,则说明任务栏不存在 */ typedef struct { int position; int size; } PanelProperty; private: PanelProperty m_panelProperty {4, 0}; QPointer m_primaryScreen = nullptr; QGSettings *m_panelSetting = nullptr; Qt::LayoutDirection m_direction = Qt::LayoutDirection::LeftToRight; bool m_screenLockState = false; }; } #endif //UKUI_SIDEBAR_SCREEN_MONITOR_H ukui-sidebar/src/main/hand-gesture-helper.cpp0000664000175000017500000000327415167606206020165 0ustar fengfeng/* * 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 "hand-gesture-helper.h" #include #include #include "screen-monitor.h" using namespace Sidebar; static std::once_flag flag; static HandGestureHelper *global_intance = nullptr; HandGestureHelper *HandGestureHelper::getInstance() { std::call_once(flag, [ & ] { global_intance = new HandGestureHelper(); }); return global_intance; } HandGestureHelper::~HandGestureHelper() { } void HandGestureHelper::callNotificationCenter(int posY) { // qDebug() << "callNotificationCenter---" << posY; Q_EMIT notificationCenterCalled(posY); } void HandGestureHelper::callControlCenter(int posX) { // qDebug() << "callControlCenter---" << posX; Q_EMIT controlCenterCalled(posX); } void HandGestureHelper::top2BottomRelease(int posX, int posY) { Q_EMIT top2BottomReleased(posX, posY); } void HandGestureHelper::right2LeftRelease(int posX, int posY) { Q_EMIT right2LeftReleased(posX, posY); } HandGestureHelper::HandGestureHelper(QObject *parent) : QObject(parent) { } ukui-sidebar/src/main/global-settings.h0000664000175000017500000000766615167606206017076 0ustar fengfeng/* * 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_GLOBAL_SETTINGS_H #define UKUI_SIDEBAR_GLOBAL_SETTINGS_H #include #include #include #include #include #define USD_SETTING "org.ukui.SettingsDaemon.plugins.xsettings" #define USD_SCALING_FACTOR_KEY "scalingFactor" #define CONTROL_CENTER_SETTING "org.ukui.control-center.personalise" #define CONTROL_CENTER_TRANSPARENCY_KEY "transparency" #define CONTROL_CENTER_EFFECT "effect" // style schema #define UKUI_STYLE_SETTING "org.ukui.style" // style keys #define UKUI_STYLE_FONT_KEY "systemFont" #define UKUI_STYLE_FONT_SIZE_KEY "systemFontSize" #define UKUI_STYLE_NAME_KEY "styleName" #define UKUI_STYLE_THEME_COLOR_KEY "themeColor" #define UKUI_STYLE_WINDOW_RADIUS_KEY "windowRadius" // style value #define DEFAULT_STYLE "ukui-default" #define BLACK_STYLE "ukui-black" #define WHITE_STYLE "ukui-white" #define DARK_STYLE "ukui-dark" #define LIGHT_STYLE "ukui-light" //dbus #define DBUS_STATUS_MANAGER_IF "com.kylin.statusmanager.interface" #define TABLET_MODE "tablet-mode" #define IS_LITE_MODE "isLiteMode" // panel #define UKUI_PANEL_POSITION_KEY "panelposition" #define UKUI_PANEL_SIZE_KEY "panelsize" #define UKUI_PANEL_TYPE_KEY "paneltype" #define UKUI_SETTINGS_ISLAND_POSITION_KEY "settingsislandposition" #define UKUI_DATA_ISLAND_POSITION_KEY "dataislandposition" #define UKUI_TOPBAR_SIZE_KEY "topbarsize" #define UKUI_PANEL_LENGTH_KEY "panellength" namespace Sidebar { class GlobalSettings : public QObject { Q_OBJECT public: static GlobalSettings *globalInstance(QObject *parent = nullptr); ~GlobalSettings() override; const QVariant getValue(const QString &key); const QStringList getKeys(); int getPanelLength(QString screenName); Q_SIGNALS: void valueChanged(const QString &key); private Q_SLOTS: void updateTabletStatus(bool isTabletMode); void updateIsLiteMode(QMap map); private: explicit GlobalSettings(QObject *parent = nullptr); inline void insertValue(const QString &key, const QVariant &value); void initStyleSettings(); void initControlCenterSettings(); void initUSDSetting(); void initUSDCenterSettings(); void initStatusManagerDbus(); void initPanelMonitor(); void initPanelGSettings(); bool isKeysContain(const char* key); QMap getPanelLengthMap(); private: QDBusInterface *m_statusManagerDBus = nullptr; QMap m_cache; }; class SettingMonitor : public QObject { Q_OBJECT Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged) public: explicit SettingMonitor(QObject *parent = nullptr); QStringList keys(); void setKeys(QStringList &keys); Q_INVOKABLE QVariant getValue(const QString &key); private Q_SLOTS: void valueChangedSlot(const QString &key); Q_SIGNALS: void keysChanged(); void valueChanged(const QString &key); private: QStringList m_keys; }; } // UkuiShortcut #endif //UKUI_SIDEBAR_GLOBAL_SETTINGS_H ukui-sidebar/src/main/screen-monitor.cpp0000664000175000017500000001426215167643374017274 0ustar fengfeng/* * 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-8-4. // #include "screen-monitor.h" #include #include #include #include #include #include #define SCREENSAVER_SERVICE_NAME "org.ukui.ScreenSaver" #define SCREENSAVER_SERVICE_PATH "/" #define SCREENSAVER_SERVICE_INTERFACE "org.ukui.ScreenSaver" using namespace Sidebar; static std::once_flag flag; static ScreenMonitor *global_intance = nullptr; ScreenMonitor *ScreenMonitor::getInstance() { std::call_once(flag, [ & ] { global_intance = new ScreenMonitor(); }); return global_intance; } int ScreenMonitor::getPanelPosition() { return m_panelProperty.position; } int ScreenMonitor::getPanelSize() { return m_panelProperty.size; } bool ScreenMonitor::getScreenLockState() { return m_screenLockState; } ScreenMonitor::ScreenMonitor(QObject *parent) : QObject(parent) { qRegisterMetaType("QScreen*"); initPanelMonitor(); primaryScreenChangedSlot(QApplication::primaryScreen()); m_direction = QApplication::layoutDirection(); initScreenSaver(); connect(qApp, &QApplication::screenAdded, this, &ScreenMonitor::screenAddedSlot); connect(qApp, &QApplication::screenRemoved, this, &ScreenMonitor::screenRemovedSlot); connect(qApp, &QApplication::primaryScreenChanged, this, &ScreenMonitor::primaryScreenChangedSlot); connect(qApp, &QApplication::layoutDirectionChanged, this, &ScreenMonitor::layoutDirectionChangedSlot); } void ScreenMonitor::initPanelMonitor() { const QByteArray id(UKUI_PANEL_SETTING); if (QGSettings::isSchemaInstalled(id)) { m_panelSetting = new QGSettings(id, QByteArray(), this); QStringList keys = m_panelSetting->keys(); if (keys.contains(UKUI_PANEL_POSITION_KEY)) { m_panelProperty.position = m_panelSetting->get(UKUI_PANEL_POSITION_KEY).toInt(); } if (keys.contains(UKUI_PANEL_SIZE_KEY)) { m_panelProperty.size = m_panelSetting->get(UKUI_PANEL_SIZE_KEY).toInt(); } connect(m_panelSetting, &QGSettings::changed, this, &ScreenMonitor::panelPropertyChangedSlot); } } void ScreenMonitor::initScreenSaver() { QDBusInterface interface(SCREENSAVER_SERVICE_NAME, SCREENSAVER_SERVICE_PATH, SCREENSAVER_SERVICE_INTERFACE, QDBusConnection::sessionBus()); if (interface.isValid()) { QDBusReply reply = interface.call("GetLockState"); if (reply.isValid()) { m_screenLockState = reply.value(); } } Q_EMIT screenLockStateChanged(m_screenLockState); QDBusConnection::sessionBus().connect(SCREENSAVER_SERVICE_NAME, SCREENSAVER_SERVICE_PATH, SCREENSAVER_SERVICE_INTERFACE, "lock",this,SLOT(screenLockSlot())); QDBusConnection::sessionBus().connect(SCREENSAVER_SERVICE_NAME, SCREENSAVER_SERVICE_PATH, SCREENSAVER_SERVICE_INTERFACE, "unlock",this,SLOT(screenUnLockSlot())); } void ScreenMonitor::primaryScreenChangedSlot(QScreen *screen) { if (!screen) { return; } if (m_primaryScreen) { m_primaryScreen->disconnect(this); } m_primaryScreen = screen; connect(m_primaryScreen, &QScreen::geometryChanged, this, &ScreenMonitor::geometryChanged); Q_EMIT primaryScreenChanged(); Q_EMIT geometryChanged(m_primaryScreen->geometry()); } void ScreenMonitor::screenRemovedSlot(QScreen *screen) { qDebug() << "ScreenMonitor::onScreenRemoved" << screen; Q_EMIT screenRemoved(screen); // if (screen == m_primaryScreen) { // m_primaryScreen = QApplication::primaryScreen(); // } } void ScreenMonitor::screenAddedSlot(QScreen *screen) { Q_UNUSED(screen) qDebug() << "ScreenMonitor::onScreenAdded" << screen; } void ScreenMonitor::panelPropertyChangedSlot(const QString& key) { if (key == UKUI_PANEL_POSITION_KEY || key == UKUI_PANEL_SIZE_KEY) { if (key == UKUI_PANEL_POSITION_KEY) { m_panelProperty.position = m_panelSetting->get(UKUI_PANEL_POSITION_KEY).toInt(); } else { m_panelProperty.size = m_panelSetting->get(UKUI_PANEL_SIZE_KEY).toInt(); } Q_EMIT panelPropertyChanged(); } } void ScreenMonitor::layoutDirectionChangedSlot(Qt::LayoutDirection direction) { if (m_direction == direction) return; m_direction = direction; Q_EMIT layoutDirectionChanged(); } void ScreenMonitor::screenLockSlot() { Q_EMIT screenLockStateChanged(true); } void ScreenMonitor::screenUnLockSlot() { Q_EMIT screenLockStateChanged(false); } QScreen *ScreenMonitor::getPrimaryScreen() { return m_primaryScreen; } QRect ScreenMonitor::getGeometry() { if (m_primaryScreen) { return m_primaryScreen->geometry(); } return {}; } Qt::LayoutDirection ScreenMonitor::getLayoutDirection() { return m_direction; } qreal ScreenMonitor::screenRatio() { qreal ratio = 1; if (!m_primaryScreen) { return ratio; } qreal height = 825 + (m_primaryScreen->devicePixelRatio() > 1 ? 8*m_primaryScreen->devicePixelRatio() : 8); if (m_primaryScreen->geometry().height() < height) { ratio = qreal(m_primaryScreen->geometry().height()) / height; if (ratio < 0.5) { ratio = 0.5; } } return ratio; } ukui-sidebar/src/main/account-information.cpp0000664000175000017500000003153415167643374020310 0ustar fengfeng/* * 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 "account-information.h" #include "app-manager.h" #include "dbus-connector.h" #include #include #include #define DEFAULT_USER_ICON_FILE ":/icon/default-community-image.png" #define KYLIN_POWER_NORMAL_PATH_MAJOR ":/icon/pad_mainpower.svg" #define ADMINISTRATORS 1 #define STANDARD_USER 0 #define POWER_BUS_NAME "org.ukui.upower" #define POWER_BUS_PATH "/upower/BatteryInfo" #define POWER_BUS_INTERFACE "org.ukui.upower.battery" using namespace UkuiShortcut; using namespace UkuiQuick; AccountInformation::AccountInformation(QObject *parent) : QObject(parent) { initMemberVariable(); registeredAccountsDbus(); initUserInfo(); } AccountInformation::~AccountInformation() = default; void AccountInformation::initMemberVariable() { m_administrator = QObject::tr("Administrator"); m_standardUser = QObject::tr("Standard user"); } void AccountInformation::registeredAccountsDbus() { m_systemUserIFace = new QDBusInterface("org.freedesktop.Accounts", "/org/freedesktop/Accounts", "org.freedesktop.Accounts", QDBusConnection::systemBus(), this); } void AccountInformation::initUserInfo() { QStringList objectPaths = getUserObjectPath(); UserInformation user; for (const QString& objectPath : objectPaths){ user = GetUserInformation(objectPath); if(user.current && user.isLogged) { m_currentUserInfo = user; m_currentUserIFace = new QDBusInterface("org.freedesktop.Accounts", objectPath, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus(), this); m_currentUserIFace->connection().connect("org.freedesktop.Accounts", objectPath, "org.freedesktop.DBus.Properties", "PropertiesChanged", this, SLOT(currentAccountUpdateSlot(QString, QMap, QStringList))); break; } } } QStringList AccountInformation::getUserObjectPath() { QStringList users; QDBusReply > reply = m_systemUserIFace->call("ListCachedUsers"); if (reply.isValid()) { for (const QDBusObjectPath& op : reply.value()) { users << op.path(); } } return users; } UserInformation AccountInformation::GetUserInformation(const QString& objectPath) { UserInformation user; //默认值 user.current = false; user.isLogged = false; user.autologin = false; QDBusInterface userInterface("org.freedesktop.Accounts", objectPath, "org.freedesktop.DBus.Properties", QDBusConnection::systemBus()); QDBusReply > reply = userInterface.call("GetAll", "org.freedesktop.Accounts.User"); if (reply.isValid()) { QMap propertyMap; propertyMap = reply.value(); user.username = propertyMap.find("UserName").value().toString(); user.realName = propertyMap.find("RealName").value().toString(); user.accountType = propertyMap.find("AccountType").value().toInt(); user.iconFile = propertyMap.find("IconFile").value().toString(); user.passwdType = propertyMap.find("PasswordMode").value().toInt(); user.uid = propertyMap.find("Uid").value().toInt(); user.autologin = false; user.objPath = objectPath; if (user.username == QString(qgetenv("USER"))) { user.current = true; user.isLogged = true; } } else { qDebug() << "GetUserInformation: reply failed"; } return user; } void AccountInformation::currentAccountUpdateSlot(const QString& property, const QMap& propertyMap, const QStringList& propertyList) { Q_UNUSED(property) Q_UNUSED(propertyList) QStringList keys = propertyMap.keys(); if (keys.contains("IconFile")) { m_currentUserInfo.iconFile = propertyMap.value("IconFile").toString(); } if (keys.contains("UserName")) { m_currentUserInfo.username = propertyMap.value("UserName").toString(); } if (keys.contains("RealName")) { m_currentUserInfo.realName = propertyMap.value("RealName").toString(); } if (keys.contains("AccountType")) { m_currentUserInfo.accountType = propertyMap.value("AccountType").toInt(); } Q_EMIT userInfoChanged(); } QString AccountInformation::getUsername() { return m_currentUserInfo.username; } QString AccountInformation::getRealName() { return m_currentUserInfo.realName; } QString AccountInformation::getIconFile() { if (m_currentUserInfo.iconFile.isEmpty()) { return {DEFAULT_USER_ICON_FILE}; } return m_currentUserInfo.iconFile; } QString AccountInformation::getAccountType() { if (m_currentUserInfo.accountType == ADMINISTRATORS) { return m_administrator; } if (m_currentUserInfo.accountType == STANDARD_USER) { return m_standardUser; } return ""; } void AccountInformation::openUserCenter() { QStringList args; args.append("-m"); args.append("Userinfo"); Sidebar::AppManager::getInstance(this)->launchAppWithArguments("/usr/share/applications/ukui-control-center.desktop", args, "ukui-control-center"); } void AccountInformation::openPeonyUser() { Sidebar::AppManager::getInstance(this)->launchAppWithArguments("/usr/share/applications/peony.desktop", QStringList(), "peony ~/"); } void AccountInformation::openControlCenter() { QStringList args; args.append("-m"); args.append("Boot"); Sidebar::AppManager::getInstance(this)->launchAppWithArguments("/usr/share/applications/ukui-control-center.desktop", args, "ukui-control-center"); } void AccountInformation::openPowerButton() { Sidebar::AppManager::getInstance(this)->launchApp("/usr/share/applications/ukui-session-tools.desktop", "ukui-session-tools"); } PowerButton::PowerButton(QObject *parent) : QObject(parent) { initPowerBatteryIface(); } PowerButton::~PowerButton() { if (m_powerBatteryIface) { delete m_powerBatteryIface; m_powerBatteryIface = nullptr; } if (!m_powerServiceWatcher) { delete m_powerServiceWatcher; m_powerServiceWatcher = nullptr; } } bool PowerButton::isEnable() { return m_isEnable; } QString PowerButton::icon() { return m_icon; } QString PowerButton::tooltip() { return m_tooltip; } QString PowerButton::percentage() { return m_percentage; } void PowerButton::initPowerBatteryIface() { DbusConnector* dbusConnector = new DbusConnector(POWER_BUS_NAME, POWER_BUS_PATH, POWER_BUS_INTERFACE, QDBusConnection::sessionBus()); connect(dbusConnector, &DbusConnector::ready, this, &PowerButton::onConnectorReady); dbusConnector->start(); } void PowerButton::getBatteryInfo() { if (!m_powerBatteryIface) return; m_iconNeedRefresh = true; auto iconWatcher = new QDBusPendingCallWatcher(m_powerBatteryIface->asyncCall(QStringLiteral("IconName")), this); connect(iconWatcher, &QDBusPendingCallWatcher::finished, this, [this] (QDBusPendingCallWatcher *self) { QDBusPendingReply reply = *self; if (self) { if (reply.isError()) { qDebug() << "PowerBatteryIface call IconName error" << reply.error().message(); } else { if (m_iconNeedRefresh) { onBatteryIconChanged(reply.value()); } } self->deleteLater(); } }); m_percentageNeedRefresh = true; auto percentageWatcher = new QDBusPendingCallWatcher(m_powerBatteryIface->asyncCall(QStringLiteral("Percentage")), this); connect(percentageWatcher, &QDBusPendingCallWatcher::finished, this, [this] (QDBusPendingCallWatcher *self) { QDBusPendingReply reply = *self; if (self) { if (reply.isError()) { qDebug() << "PowerBatteryIface call Percentage error" << reply.error().message(); } else { if (m_percentageNeedRefresh) { onPercentageChanged(reply.value()); } } self->deleteLater(); } }); m_isEnableNeedRefresh = true; auto enableWatcher = new QDBusPendingCallWatcher(m_powerBatteryIface->asyncCall(QStringLiteral("ShowIcon")), this); connect(enableWatcher, &QDBusPendingCallWatcher::finished, this, [this] (QDBusPendingCallWatcher *self) { QDBusPendingReply reply = *self; if (self) { if (reply.isError()) { qDebug() << "PowerBatteryIface call ShowIcon error" << reply.error().message(); } else { if (m_isEnableNeedRefresh) { onBatteryShowIcon(reply.value()); } } self->deleteLater(); } }); } void PowerButton::onServiceUnregistered() { if (m_powerBatteryIface) { delete m_powerBatteryIface; m_powerBatteryIface = nullptr; } m_isEnable = false; Q_EMIT isEnableChanged(); initPowerBatteryIface(); } void PowerButton::onConnectorReady(QDBusInterface *interface) { if (!interface || !interface->isValid()) { qWarning() << "Init powerBatteryIface error"; return; } m_powerBatteryIface = interface; m_isEnable = true; Q_EMIT isEnableChanged(); getBatteryInfo(); if(!QDBusConnection::sessionBus().connect(POWER_BUS_NAME, POWER_BUS_PATH, POWER_BUS_INTERFACE, QStringLiteral("BatteryIcon"), this, SLOT(onBatteryIconChanged(QString)))) { qWarning() << "PowerBatteryIface connect signal BatteryIcon failed!"; } if(!QDBusConnection::sessionBus().connect(POWER_BUS_NAME, POWER_BUS_PATH, POWER_BUS_INTERFACE, QStringLiteral("PercentageChanged"), this, SLOT(onPercentageChanged(double)))) { qWarning() << "PowerBatteryIface connect signal PercentageChanged failed!"; } if(!QDBusConnection::sessionBus().connect(POWER_BUS_NAME, POWER_BUS_PATH, POWER_BUS_INTERFACE, QStringLiteral("BatteryShowIcon"), this, SLOT(onBatteryShowIcon(bool)))) { qWarning() << "PowerBatteryIface connect signal BatteryShowIcon failed!"; } if (!m_powerServiceWatcher) { m_powerServiceWatcher = new QDBusServiceWatcher(POWER_BUS_NAME, QDBusConnection::sessionBus(), QDBusServiceWatcher::WatchForUnregistration,this); if (m_powerServiceWatcher) { connect(m_powerServiceWatcher, &QDBusServiceWatcher::serviceUnregistered, this, &PowerButton::onServiceUnregistered); } else { qDebug()<<"PowerServiceWatcher init error"; } } } void PowerButton::onBatteryIconChanged(QString iconName) { m_iconNeedRefresh = false; if (iconName == m_icon) return; m_icon = iconName; Q_EMIT iconChanged(); } void PowerButton::onPercentageChanged(double percentage) { m_percentageNeedRefresh = false; QString per = QString::number(percentage, 'f', 0); if (per == m_percentage) return; m_percentage = per; m_tooltip = per; Q_EMIT percentageChanged(); Q_EMIT tooltipChanged(); } void PowerButton::onBatteryShowIcon(bool isEnable) { m_isEnableNeedRefresh = false; if (isEnable == m_isEnable) return; m_isEnable = isEnable; Q_EMIT isEnableChanged(); } ukui-sidebar/src/main/color-helper.cpp0000664000175000017500000001356615167606206016722 0ustar fengfeng/* * 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-8-15. // #include "color-helper.h" #include "global-settings.h" #include #include using namespace Sidebar; static ColorHelper *globalInstance = nullptr; ColorHelper *ColorHelper::getInstance() { if (!globalInstance) { globalInstance = new ColorHelper(nullptr); } return globalInstance; } ColorHelper::ColorHelper(QObject *parent) : QObject(parent) { styleChangedSlot(UKUI_STYLE_NAME_KEY); connect(Sidebar::GlobalSettings::globalInstance(), &Sidebar::GlobalSettings::valueChanged, this, &ColorHelper::styleChangedSlot, Qt::QueuedConnection); connect(qApp, &QApplication::paletteChanged, this, [=] { Q_EMIT styleColorChanged(); }); } void ColorHelper::styleChangedSlot(const QString &key) { if (key == UKUI_STYLE_NAME_KEY || key == UKUI_STYLE_THEME_COLOR_KEY || key == CONTROL_CENTER_TRANSPARENCY_KEY) { // 此处由于主题框架黑名单规则,在ukui-default主题下,侧边栏的调色板为暗色,所以对于侧边栏来说,default也属于暗色主题 m_isDarkStyle = (Sidebar::GlobalSettings::globalInstance()->getValue(UKUI_STYLE_NAME_KEY).toString() != LIGHT_STYLE); m_transparency = Sidebar::GlobalSettings::globalInstance()->getValue(CONTROL_CENTER_TRANSPARENCY_KEY).toReal(); Q_EMIT styleColorChanged(); } } QColor ColorHelper::pluginColor(UkuiShortcut::Color::ColorRole colorRole) { QPalette palette = QApplication::palette(); QColor color; switch (colorRole) { default: case UkuiShortcut::Color::BaseColor: { // color = palette.color(QPalette::Button); // 设计师:按钮的基础色为brightText+0.1的alpha color = palette.color(QPalette::BrightText); color.setAlphaF(0.1); break; } case UkuiShortcut::Color::HighLight: { color = palette.color(QPalette::Highlight); break; } case UkuiShortcut::Color::Success: { color = palette.color(QPalette::Highlight); break; } case UkuiShortcut::Color::Warning: { color = QColor("#E6A23C"); break; } case UkuiShortcut::Color::Info: { color = palette.color(QPalette::Dark); break; } case UkuiShortcut::Color::Danger: { color = QColor("#FE4F4F"); break; } case UkuiShortcut::Color::Disable: { color = palette.color(QPalette::Disabled, QPalette::Window); break; } } return color; } QColor ColorHelper::pluginColorHover(UkuiShortcut::Color::ColorRole colorRole) { QColor color = pluginColor(colorRole); if (colorRole == UkuiShortcut::Color::BaseColor) { color.setAlphaF(0.2); } else { // 转换为hsv模型后,调整v分量 qreal value = color.valueF() - (m_isDarkStyle ? -0.05 : 0.05); value = value > 1 ? 1 : (value < 0) ? 0 : value; QColor hsvColor(QColor::Hsv); hsvColor.setHsvF(color.hsvHueF(), color.hsvSaturationF(), value); color = hsvColor.toRgb(); } return color; } QColor ColorHelper::pluginColorPressed(UkuiShortcut::Color::ColorRole colorRole) { QColor color = pluginColor(colorRole); if (colorRole == UkuiShortcut::Color::BaseColor) { color.setAlphaF(0.3); } else { qreal value = color.valueF() - (m_isDarkStyle ? -0.2 : 0.2); value = value > 1 ? 1 : (value < 0) ? 0 : value; QColor hsvColor(QColor::Hsv); hsvColor.setHsvF(color.hsvHueF(), color.hsvSaturationF(), value); color = hsvColor.toRgb(); } return color; } QColor ColorHelper::pluginColorWithCustomTransparency(UkuiShortcut::Color::ColorRole colorRole, qreal alphaF) { QColor color = pluginColor(colorRole); color.setAlphaF(alphaF); return color; } QColor ColorHelper::pluginColorWithTransparency(UkuiShortcut::Color::ColorRole colorRole) { QColor color = pluginColor(colorRole); color.setAlphaF(qMax(m_transparency, 0.75)); return color; } bool ColorHelper::isHighLightColor(UkuiShortcut::Color::ColorRole colorRole) { // 如果是暗色主题,那么图标需要进行反色 if (m_isDarkStyle) { return true; } bool isHighLight; switch (colorRole) { default: case UkuiShortcut::Color::ColorRole::BaseColor: case UkuiShortcut::Color::ColorRole::Info: case UkuiShortcut::Color::ColorRole::Disable: { isHighLight = false; break; } case UkuiShortcut::Color::ColorRole::HighLight: case UkuiShortcut::Color::ColorRole::Success: case UkuiShortcut::Color::ColorRole::Danger: { isHighLight = true; break; } } return isHighLight; } QColor ColorHelper::separator() const { QColor color = m_isDarkStyle ? QColor(255, 255, 255) : QColor(38, 38, 38); color.setAlphaF(0.08); return color; } QColor ColorHelper::mask() const { // 区分明暗主题 QColor color = m_isDarkStyle ? QColor("#ffffff") : QColor("#262626"); color.setAlphaF(0.25); return color; } bool ColorHelper::isDarkStyle() { return m_isDarkStyle; } ukui-sidebar/src/layout/0000775000175000017500000000000015167643374014210 5ustar fengfengukui-sidebar/src/layout/ukui-column.cpp0000664000175000017500000010307115167643374017166 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. * Copyright (C) 2025, KylinSoft Co., Ltd. * ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ** iaom ** qiqi49 ****************************************************************************/ #include "ukui-column.h" #include #include #include static const QQuickItemPrivate::ChangeTypes watchedChanges = QQuickItemPrivate::Geometry | QQuickItemPrivate::SiblingOrder | QQuickItemPrivate::Visibility | QQuickItemPrivate::Destroyed; UkuiScale::UkuiScale(QObject *parent) : QQuickTransform(parent) { } UkuiScale::~UkuiScale() { } QVector3D UkuiScale::origin() const { return m_origin; } void UkuiScale::setOrigin(const QVector3D &point) { if (m_origin == point) return; m_origin = point; update(); emit originChanged(); } qreal UkuiScale::xScale() const { return m_xScale; } void UkuiScale::setXScale(qreal scale) { if (m_xScale == scale) return; m_xScale = scale; update(); emit xScaleChanged(); emit scaleChanged(); } qreal UkuiScale::yScale() const { return m_yScale; } void UkuiScale::setYScale(qreal scale) { if (m_yScale == scale) return; m_yScale = scale; update(); emit yScaleChanged(); emit scaleChanged(); } qreal UkuiScale::zScale() const { return m_zScale; } void UkuiScale::setZScale(qreal scale) { if (m_zScale == scale) return; m_zScale = scale; update(); emit zScaleChanged(); emit scaleChanged(); } void UkuiScale::applyTo(QMatrix4x4 *matrix) const { matrix->translate(m_origin); matrix->scale(m_xScale, m_yScale, m_zScale); matrix->translate(-m_origin); } void UkuiBasePositionerPrivate::watchChanges(QQuickItem *other) { QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other); otherPrivate->addItemChangeListener(this, watchedChanges); } void UkuiBasePositionerPrivate::unwatchChanges(QQuickItem* other) { QQuickItemPrivate *otherPrivate = QQuickItemPrivate::get(other); otherPrivate->removeItemChangeListener(this, watchedChanges); } UkuiBasePositioner::PositionedItem::PositionedItem(QQuickItem *i) : item(i) , transitionableItem(nullptr) , index(-1) , isNew(false) , isVisible(true) , topPadding(0) , leftPadding(0) , rightPadding(0) , bottomPadding(0) { } UkuiBasePositioner::PositionedItem::~PositionedItem() { delete transitionableItem; } qreal UkuiBasePositioner::PositionedItem::itemX() const { return transitionableItem ? transitionableItem->itemX() : item->x(); } qreal UkuiBasePositioner::PositionedItem::itemY() const { return transitionableItem ? transitionableItem->itemY() : item->y(); } void UkuiBasePositioner::PositionedItem::moveTo(const QPointF &pos) { if (transitionableItem) { transitionableItem->moveTo(pos); } else item->setPosition(pos); } void UkuiBasePositioner::PositionedItem::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget) { if (!transitioner) return; if (!transitionableItem) transitionableItem = new QQuickItemViewTransitionableItem(item); transitioner->transitionNextReposition(transitionableItem, type, asTarget); } bool UkuiBasePositioner::PositionedItem::prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds) { return transitionableItem ? transitionableItem->prepareTransition(transitioner, index, viewBounds) : false; } void UkuiBasePositioner::PositionedItem::startTransition(QQuickItemViewTransitioner *transitioner) { if (transitionableItem) transitionableItem->startTransition(transitioner, index); } void UkuiBasePositioner::PositionedItem::updatePadding(qreal lp, qreal tp, qreal rp, qreal bp) { leftPadding = lp; topPadding = tp; rightPadding = rp; bottomPadding = bp; } void UkuiBasePositioner::PositionedItem::setScaleTransition(qreal start, qreal end) { hasScaleTransition = true; startScale = start; endScale = end; } void UkuiBasePositioner::PositionedItem::applyCustomTransitions() { if (!item) { return; } if (hasScaleTransition) { QPropertyAnimation *anim = new QPropertyAnimation(item, "scale"); anim->setDuration(300); anim->setEasingCurve(QEasingCurve::OutBack); anim->setStartValue(startScale); anim->setEndValue(endScale); anim->start(QAbstractAnimation::DeleteWhenStopped); } hasScaleTransition = false; startScale = 0.0; endScale = 0.0; } void UkuiBasePositioner::PositionedItem::setYScale(qreal scale) { if (!item || yScale == scale) { return; } yScale = scale; clearTransformFromItem(); UkuiScale* scaleTransform = nullptr; if (!scaleTransform && yScale != 1.0) { scaleTransform = new UkuiScale(item); scaleTransform->setOrigin(QVector3D(0, 0, 0)); scaleTransform->setXScale(1.0); scaleTransform->setYScale(yScale); addTransformToItem(scaleTransform); } } void UkuiBasePositioner::PositionedItem::addTransformToItem(QQuickTransform* transform) { if (!item || !transform) { return; }; QQmlListProperty prop = item->transform(); prop.append(&prop, transform); } void UkuiBasePositioner::PositionedItem::clearTransformFromItem() { if (!item) { return; }; QQmlListProperty prop = item->transform(); prop.clear(&prop); } UkuiBasePositioner::UkuiBasePositioner(PositionerType at, QQuickItem *parent) : QQuickImplicitSizeItem(*(new UkuiBasePositionerPrivate), parent) { Q_D(UkuiBasePositioner); d->init(at); } UkuiBasePositioner::UkuiBasePositioner(UkuiBasePositionerPrivate &dd, PositionerType at, QQuickItem *parent) : QQuickImplicitSizeItem(dd, parent) { Q_D(UkuiBasePositioner); d->init(at); } UkuiBasePositioner::~UkuiBasePositioner() { Q_D(UkuiBasePositioner); delete d->transitioner; for (int i = 0; i < positionedItems.count(); ++i) d->unwatchChanges(positionedItems.at(i).item); for (int i = 0; i < unpositionedItems.count(); ++i) d->unwatchChanges(unpositionedItems.at(i).item); clearPositionedItems(&positionedItems); clearPositionedItems(&unpositionedItems); } void UkuiBasePositioner::updatePolish() { Q_D(UkuiBasePositioner); if (d->positioningDirty) prePositioning(); } qreal UkuiBasePositioner::spacing() const { Q_D(const UkuiBasePositioner); return d->spacing; } void UkuiBasePositioner::setSpacing(qreal s) { Q_D(UkuiBasePositioner); if (s == d->spacing) return; d->spacing = s; d->setPositioningDirty(); emit spacingChanged(); } QQuickTransition *UkuiBasePositioner::populate() const { Q_D(const UkuiBasePositioner); return d->transitioner ? d->transitioner->populateTransition : nullptr; } void UkuiBasePositioner::setPopulate(QQuickTransition *transition) { Q_D(UkuiBasePositioner); if (!d->transitioner) d->transitioner = new QQuickItemViewTransitioner; if (d->transitioner->populateTransition != transition) { d->transitioner->populateTransition = transition; emit populateChanged(); } } QQuickTransition *UkuiBasePositioner::move() const { Q_D(const UkuiBasePositioner); return d->transitioner ? d->transitioner->displacedTransition : nullptr; } void UkuiBasePositioner::setMove(QQuickTransition *mt) { Q_D(UkuiBasePositioner); if (!d->transitioner) d->transitioner = new QQuickItemViewTransitioner; if (mt == d->transitioner->displacedTransition) return; d->transitioner->displacedTransition = mt; emit moveChanged(); } QQuickTransition *UkuiBasePositioner::add() const { Q_D(const UkuiBasePositioner); return d->transitioner ? d->transitioner->addTransition : nullptr; } void UkuiBasePositioner::setAdd(QQuickTransition *add) { Q_D(UkuiBasePositioner); if (!d->transitioner) d->transitioner = new QQuickItemViewTransitioner; if (add == d->transitioner->addTransition) return; d->transitioner->addTransition = add; emit addChanged(); } QQuickTransition* UkuiBasePositioner::removeTransition() const { Q_D(const UkuiBasePositioner); return d->transitioner ? d->transitioner->removeTransition : nullptr; } void UkuiBasePositioner::setRemoveTransition(QQuickTransition* transition) { Q_D(UkuiBasePositioner); if (!d->transitioner) { d->transitioner = new QQuickItemViewTransitioner; // d->transitioner->setChangeListener(this); // TODO } if (d->transitioner->removeTransition != transition) { d->transitioner->removeTransition = transition; emit removeTransitionChanged(); } } void UkuiBasePositioner::componentComplete() { Q_D(UkuiBasePositioner); QQuickItem::componentComplete(); if (d->transitioner) d->transitioner->setPopulateTransitionEnabled(true); positionedItems.reserve(childItems().count()); prePositioning(); if (d->transitioner) d->transitioner->setPopulateTransitionEnabled(false); } void UkuiBasePositioner::itemChange(ItemChange change, const ItemChangeData &value) { Q_D(UkuiBasePositioner); if (change == ItemChildAddedChange) { d->setPositioningDirty(); } else if (change == ItemChildRemovedChange) { QQuickItem *child = value.item; UkuiBasePositioner::PositionedItem posItem(child); int idx = positionedItems.indexOf(posItem); if (idx >= 0) { d->unwatchChanges(child); removePositionedItem(&positionedItems, idx); } else if ((idx = unpositionedItems.indexOf(posItem)) >= 0) { d->unwatchChanges(child); removePositionedItem(&unpositionedItems, idx); } d->setPositioningDirty(); } QQuickItem::itemChange(change, value); } void UkuiBasePositioner::forceLayout() { updatePolish(); } void UkuiBasePositioner::prePositioning() { Q_D(UkuiBasePositioner); // 1. 前置检查:确保组件已完成初始化且没有重入问题 if (!isComponentComplete()) return; if (d->doingPositioning) return; // 2. 状态标记:标记布局开始,清除脏标记 d->positioningDirty = false; d->doingPositioning = true; // ===== 记录动画起始状态 ===== for (int i = 0; i < positionedItems.count(); ++i) { PositionedItem& item = positionedItems[i]; if (item.item) { item.startScale = item.item->scale(); } } // 3. 获取子项列表(按创建/堆叠顺序) QList children = childItems(); // 4. 备份旧项数据:保存当前定位项和未定位项 QList oldItems; positionedItems.swap(oldItems); for (int ii = 0; ii < unpositionedItems.count(); ii++) oldItems.append(unpositionedItems[ii]); unpositionedItems.clear(); int addedIndex = -1; // 跟踪首个新增项的索引 // 5. 遍历所有子项,构建新的定位列表 for (int ii = 0; ii < children.count(); ++ii) { QQuickItem *child = children.at(ii); // 跳过透明项(不参与布局的项) if (QQuickItemPrivate::get(child)->isTransparentForPositioner()) continue; QQuickItemPrivate *childPrivate = QQuickItemPrivate::get(child); PositionedItem posItem(child); int wIdx = oldItems.indexOf(posItem); // 6. 处理新出现的项 if (wIdx < 0) { d->watchChanges(child); posItem.isNew = true; // 6.1 无效项处理(不可见或尺寸为0) if (!childPrivate->explicitVisible || !child->width() || !child->height()) { posItem.isVisible = false; posItem.index = -1; unpositionedItems.append(posItem); // 加入unpositionedItems未定位列表 } else { // 6.2 有效新项处理 posItem.index = positionedItems.count(); positionedItems.append(posItem); // 加入positionedItems定位列表 // 处理动画过渡 if (d->transitioner) { if (addedIndex < 0) addedIndex = posItem.index; PositionedItem *theItem = &positionedItems[positionedItems.count()-1]; if (d->transitioner->canTransition(QQuickItemViewTransitioner::PopulateTransition, true)) theItem->transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::PopulateTransition, true); else if (!d->transitioner->populateTransitionEnabled()) theItem->transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::AddTransition, true); } } } else { PositionedItem *item = &oldItems[wIdx]; // 7.1 无效项处理(尺寸为0) if (!child->width() || !child->height()) { item->isVisible = false; item->index = -1; unpositionedItems.append(*item); } else if (!item->isVisible) { // item changed from non-visible to visible, treat it as a "new" item item->isVisible = childPrivate->explicitVisible; item->isNew = false; item->index = positionedItems.count(); positionedItems.append(*item); // 处理添加动画 if (d->transitioner) { if (addedIndex < 0) addedIndex = item->index; positionedItems[positionedItems.count()-1].transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::AddTransition, true); } } else { // 7.3 常规存在的项 item->isNew = false; item->index = positionedItems.count(); positionedItems.append(*item); } } } if (d->transitioner) { for (int i = 0; i < positionedItems.count(); i++) { if (positionedItems[i].isNew) { positionedItems[i].transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::AddTransition, true); } else { positionedItems[i].transitionNextReposition(d->transitioner, QQuickItemViewTransitioner::MoveTransition, false); } } } // 9. 执行实际布局 QSizeF contentSize(0,0); reportConflictingAnchors(); if (!d->anchorConflict) { doPositioning(&contentSize); updateAttachedProperties(); } // 10. 处理过渡动画的启动 if (d->transitioner) { QRectF viewBounds(QPointF(), contentSize); // 准备过渡 for (int i=0; itransitioner, viewBounds); // 启动过渡 for (int i=0; itransitioner); d->transitioner->resetTargetLists(); } // ===== 应用自定义Scale动画 ===== for (int i = 0; i < positionedItems.count(); i++) { PositionedItem&pItem = positionedItems[i]; QQuickItem* item = pItem.item; // 缩放动画(折叠模式特有) if (qAbs(pItem.startScale - item->scale()) > 0.01) { pItem.setScaleTransition(pItem.startScale, item->scale()); } pItem.applyCustomTransitions(); } d->doingPositioning = false; setImplicitSize(contentSize.width(), contentSize.height()); // 设置隐式尺寸 emit positioningComplete(); // 发出布局完成信号 } void UkuiBasePositioner::positionItem(qreal x, qreal y, PositionedItem *target) { if ( target->itemX() != x || target->itemY() != y ) target->moveTo(QPointF(x, y)); } void UkuiBasePositioner::positionItemX(qreal x, PositionedItem *target) { Q_D(UkuiBasePositioner); if (target->itemX() != x && (d->type == Horizontal || d->type == Both)) { target->moveTo(QPointF(x, target->itemY())); } } void UkuiBasePositioner::positionItemY(qreal y, PositionedItem *target) { Q_D(UkuiBasePositioner); if (target->itemY() != y && (d->type == Vertical || d->type == Both)) { target->moveTo(QPointF(target->itemX(), y)); } } /* Since PositionedItem values are stored by value, their internal transitionableItem pointers must be cleaned up when a PositionedItem is removed from a QPODVector, otherwise the pointer is never deleted since QPODVector doesn't invoke the destructor. */ void UkuiBasePositioner::removePositionedItem(QList *items, int index) { Q_ASSERT(index >= 0 && index < items->count()); delete items->at(index).transitionableItem; items->removeAt(index); } void UkuiBasePositioner::clearPositionedItems(QList *items) { for (int i=0; icount(); i++) delete items->at(i).transitionableItem; items->clear(); } UkuiPositionerAttached *UkuiBasePositioner::qmlAttachedProperties(QObject *obj) { return new UkuiPositionerAttached(obj); } void UkuiBasePositioner::updateAttachedProperties(UkuiPositionerAttached *specificProperty, QQuickItem *specificPropertyOwner) const { // If this function is deemed too expensive or shows up in profiles, it could // be changed to run only when there are attached properties present. This // could be a flag in the positioner that is set by the attached property // constructor. UkuiPositionerAttached *prevLastProperty = nullptr; UkuiPositionerAttached *lastProperty = nullptr; for (int ii = 0; ii < positionedItems.count(); ++ii) { const PositionedItem &child = positionedItems.at(ii); if (!child.item) continue; UkuiPositionerAttached *property = nullptr; if (specificProperty) { if (specificPropertyOwner == child.item) { property = specificProperty; } } else { property = static_cast(qmlAttachedPropertiesObject(child.item, false)); } if (property) { property->setIndex(ii); property->setIsFirstItem(ii == 0); if (property->isLastItem()) { if (prevLastProperty) prevLastProperty->setIsLastItem(false); // there can be only one last property prevLastProperty = property; } } lastProperty = property; } if (prevLastProperty && prevLastProperty != lastProperty) prevLastProperty->setIsLastItem(false); if (lastProperty) lastProperty->setIsLastItem(true); // clear attached properties for unpositioned items for (int ii = 0; ii < unpositionedItems.count(); ++ii) { const PositionedItem &child = unpositionedItems.at(ii); if (!child.item) continue; UkuiPositionerAttached *property = nullptr; if (specificProperty) { if (specificPropertyOwner == child.item) { property = specificProperty; } } else { property = static_cast(qmlAttachedPropertiesObject(child.item, false)); } if (property) { property->setIndex(-1); property->setIsFirstItem(false); property->setIsLastItem(false); } } } qreal UkuiBasePositioner::padding() const { Q_D(const UkuiBasePositioner); return d->padding(); } void UkuiBasePositioner::setPadding(qreal padding) { Q_D(UkuiBasePositioner); if (qFuzzyCompare(d->padding(), padding)) return; d->extra.value().padding = padding; d->setPositioningDirty(); emit paddingChanged(); if (!d->extra.isAllocated() || !d->extra->explicitTopPadding) emit topPaddingChanged(); if (!d->extra.isAllocated() || !d->extra->explicitLeftPadding) emit leftPaddingChanged(); if (!d->extra.isAllocated() || !d->extra->explicitRightPadding) emit rightPaddingChanged(); if (!d->extra.isAllocated() || !d->extra->explicitBottomPadding) emit bottomPaddingChanged(); } void UkuiBasePositioner::resetPadding() { setPadding(0); } qreal UkuiBasePositioner::topPadding() const { Q_D(const UkuiBasePositioner); if (d->extra.isAllocated() && d->extra->explicitTopPadding) return d->extra->topPadding; return d->padding(); } void UkuiBasePositioner::setTopPadding(qreal padding) { Q_D(UkuiBasePositioner); d->setTopPadding(padding); } void UkuiBasePositioner::resetTopPadding() { Q_D(UkuiBasePositioner); d->setTopPadding(0, true); } qreal UkuiBasePositioner::leftPadding() const { Q_D(const UkuiBasePositioner); if (d->extra.isAllocated() && d->extra->explicitLeftPadding) return d->extra->leftPadding; return d->padding(); } void UkuiBasePositioner::setLeftPadding(qreal padding) { Q_D(UkuiBasePositioner); d->setLeftPadding(padding); } void UkuiBasePositioner::resetLeftPadding() { Q_D(UkuiBasePositioner); d->setLeftPadding(0, true); } qreal UkuiBasePositioner::rightPadding() const { Q_D(const UkuiBasePositioner); if (d->extra.isAllocated() && d->extra->explicitRightPadding) return d->extra->rightPadding; return d->padding(); } void UkuiBasePositioner::setRightPadding(qreal padding) { Q_D(UkuiBasePositioner); d->setRightPadding(padding); } void UkuiBasePositioner::resetRightPadding() { Q_D(UkuiBasePositioner); d->setRightPadding(0, true); } qreal UkuiBasePositioner::bottomPadding() const { Q_D(const UkuiBasePositioner); if (d->extra.isAllocated() && d->extra->explicitBottomPadding) return d->extra->bottomPadding; return d->padding(); } void UkuiBasePositioner::setBottomPadding(qreal padding) { Q_D(UkuiBasePositioner); d->setBottomPadding(padding); } void UkuiBasePositioner::resetBottomPadding() { Q_D(UkuiBasePositioner); d->setBottomPadding(0, true); } UkuiBasePositionerPrivate::ExtraData::ExtraData() : padding(0) , topPadding(0) , leftPadding(0) , rightPadding(0) , bottomPadding(0) , explicitTopPadding(false) , explicitLeftPadding(false) , explicitRightPadding(false) , explicitBottomPadding(false) { } void UkuiBasePositionerPrivate::setTopPadding(qreal value, bool reset) { Q_Q(UkuiBasePositioner); qreal oldPadding = q->topPadding(); if (!reset || extra.isAllocated()) { extra.value().topPadding = value; extra.value().explicitTopPadding = !reset; } if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { setPositioningDirty(); emit q->topPaddingChanged(); } } void UkuiBasePositionerPrivate::setLeftPadding(qreal value, bool reset) { Q_Q(UkuiBasePositioner); qreal oldPadding = q->leftPadding(); if (!reset || extra.isAllocated()) { extra.value().leftPadding = value; extra.value().explicitLeftPadding = !reset; } if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { setPositioningDirty(); emit q->leftPaddingChanged(); } } void UkuiBasePositionerPrivate::setRightPadding(qreal value, bool reset) { Q_Q(UkuiBasePositioner); qreal oldPadding = q->rightPadding(); if (!reset || extra.isAllocated()) { extra.value().rightPadding = value; extra.value().explicitRightPadding = !reset; } if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { setPositioningDirty(); emit q->rightPaddingChanged(); } } void UkuiBasePositionerPrivate::setBottomPadding(qreal value, bool reset) { Q_Q(UkuiBasePositioner); qreal oldPadding = q->bottomPadding(); if (!reset || extra.isAllocated()) { extra.value().bottomPadding = value; extra.value().explicitBottomPadding = !reset; } if ((!reset && !qFuzzyCompare(oldPadding, value)) || (reset && !qFuzzyCompare(oldPadding, padding()))) { setPositioningDirty(); emit q->bottomPaddingChanged(); } } UkuiPositionerAttached::UkuiPositionerAttached(QObject *parent) : QObject(parent), m_index(-1), m_isFirstItem(false), m_isLastItem(false) { QQuickItem *attachedItem = qobject_cast(parent); if (attachedItem) { UkuiBasePositioner *positioner = qobject_cast(attachedItem->parent()); if (positioner) { positioner->updateAttachedProperties(this, attachedItem); } } } void UkuiPositionerAttached::setIndex(int index) { if (m_index == index) return; m_index = index; emit indexChanged(); } void UkuiPositionerAttached::setIsFirstItem(bool isFirstItem) { if (m_isFirstItem == isFirstItem) return; m_isFirstItem = isFirstItem; emit isFirstItemChanged(); } void UkuiPositionerAttached::setIsLastItem(bool isLastItem) { if (m_isLastItem == isLastItem) return; m_isLastItem = isLastItem; emit isLastItemChanged(); } UkuiColumn::UkuiColumn(QQuickItem *parent) : UkuiBasePositioner(Vertical, parent) { } void UkuiColumn::setFoldMode(bool isFoldMode) { if (m_isFoldMode == isFoldMode) { return; } m_isFoldMode = isFoldMode; UkuiBasePositionerPrivate *d = static_cast(UkuiBasePositionerPrivate::get(this)); d->setPositioningDirty(); Q_EMIT foldModeChanged(); } bool UkuiColumn::isFoldMode() const { return m_isFoldMode; } int UkuiColumn::heightOffset() const { return m_heightOffset; } void UkuiColumn::doPositioning(QSizeF *contentSize) { if (m_isFoldMode) { // 1. 初始化变量 qreal voffset = topPadding(); const qreal padding = leftPadding() + rightPadding(); const qreal foldHeight = 8; // 折叠消息露出的高度 contentSize->setWidth(qMax(contentSize->width(), padding)); qreal maxHeight = 0; // 记录最新消息的高度 QRect secondItemRect = QRect(0, 0, 0, 0); // 存储第二项的位置(用于放置后续项) // 2. 遍历 int totalItems = positionedItems.count(); for (int ii = 0; ii < totalItems; ++ii) { PositionedItem &child = positionedItems[ii]; child.item->setVisible(true); // 3. 处理前三个项 if (ii < 3) { if (ii == 0) { // 3.1 最新消息(不缩放) maxHeight = child.item->height(); child.item->setScale(1.0); child.setYScale(1.0); child.item->setZ(3); positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child); child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding)); voffset += child.item->height(); m_heightOffset = 0; } else { // 3.2 折叠消息(缩放效果) qreal baseScale = (ii == 1) ? 0.95 : 0.9; qreal scaledHeight = child.item->height() * baseScale; qreal yScale = 1.0; // 如果缩放后高度仍大于第一条高度,则进行二次缩放 if ((scaledHeight > maxHeight) && maxHeight > 0) { yScale = maxHeight / scaledHeight; scaledHeight = maxHeight; } child.item->setScale(baseScale); child.setYScale(yScale); qreal yPos = voffset - (scaledHeight - foldHeight); qreal xPos = child.itemX() + leftPadding() - child.leftPadding; int z = ii == 1 ? 2 : 1; child.item->setZ(z); child.item->setTransformOrigin(QQuickItem::Top); positionItem(xPos, yPos, &child); // 更新内容尺寸(考虑缩放) qreal scaledWidth = child.item->width() * baseScale; contentSize->setWidth(qMax(contentSize->width(), scaledWidth + padding)); // 记录第二项位置,用于完全折叠项position if (ii == 1) { secondItemRect = QRect(xPos, yPos, scaledWidth, scaledHeight); } // 垂直偏移增加(只增加露出的8像素) voffset += foldHeight; m_heightOffset = yPos + child.item->height() - maxHeight - (foldHeight * ii); } } else { // 4. 处理index≥3的项(放在第三项位置并完全覆盖) qreal baseScale = 0.9; qreal scaledHeight = child.item->height() * baseScale; qreal yScale = 1.0; // 如果缩放后高度仍大于第一条高度,则进行二次缩放 if ((scaledHeight > secondItemRect.height()) && secondItemRect.height() > 0) { yScale = secondItemRect.height() / scaledHeight; scaledHeight = secondItemRect.height(); } child.item->setScale(baseScale); child.setYScale(yScale); child.item->setZ(0); child.item->setTransformOrigin(QQuickItem::Top); child.item->setTransformOrigin(QQuickItem::Top); positionItem(secondItemRect.x(), secondItemRect.y(), &child); } } contentSize->setHeight(voffset + bottomPadding()); } else { //Precondition: All items in the positioned list have a valid item pointer and should be positioned qreal voffset = topPadding(); const qreal padding = leftPadding() + rightPadding(); contentSize->setWidth(qMax(contentSize->width(), padding)); for (int ii = 0; ii < positionedItems.count(); ++ii) { PositionedItem &child = positionedItems[ii]; child.item->setVisible(true); child.item->setScale(1.0); child.setYScale(1.0); positionItem(child.itemX() + leftPadding() - child.leftPadding, voffset, &child); child.updatePadding(leftPadding(), topPadding(), rightPadding(), bottomPadding()); contentSize->setWidth(qMax(contentSize->width(), child.item->width() + padding)); voffset += child.item->height(); voffset += spacing(); } if (voffset - topPadding() != 0)//If we positioned any items, undo the spacing from the last item voffset -= spacing(); m_heightOffset = 0; contentSize->setHeight(voffset + bottomPadding()); } Q_EMIT heightOffsetChanged(); } void UkuiColumn::reportConflictingAnchors() { UkuiBasePositionerPrivate *d = static_cast(UkuiBasePositionerPrivate::get(this)); for (int ii = 0; ii < positionedItems.count(); ++ii) { const PositionedItem &child = positionedItems.at(ii); if (child.item) { QQuickAnchors *anchors = QQuickItemPrivate::get(static_cast(child.item))->_anchors; if (anchors) { QQuickAnchors::Anchors usedAnchors = anchors->usedAnchors(); if (usedAnchors & QQuickAnchors::TopAnchor || usedAnchors & QQuickAnchors::BottomAnchor || usedAnchors & QQuickAnchors::VCenterAnchor || anchors->fill() || anchors->centerIn()) { d->anchorConflict = true; break; } } } } if (d->anchorConflict) { qmlWarning(this) << "Cannot specify top, bottom, verticalCenter, fill or centerIn anchors for items inside Column." << " Column will not function."; } } ukui-sidebar/src/layout/ukui-column.h0000664000175000017500000003240015167643374016630 0ustar fengfeng/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. * Copyright (C) 2025, KylinSoft Co., Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ** iaom ** qiqi49 ****************************************************************************/ #ifndef UKUI_FLOW_H #define UKUI_FLOW_H #include #include #include #include #include #include #include class QPropertyAnimation; class UkuiBasePositionerPrivate; class UkuiScale: public QQuickTransform { Q_OBJECT Q_PROPERTY(QVector3D origin READ origin WRITE setOrigin NOTIFY originChanged) Q_PROPERTY(qreal xScale READ xScale WRITE setXScale NOTIFY xScaleChanged) Q_PROPERTY(qreal yScale READ yScale WRITE setYScale NOTIFY yScaleChanged) Q_PROPERTY(qreal zScale READ zScale WRITE setZScale NOTIFY zScaleChanged) public: UkuiScale(QObject *parent = nullptr); ~UkuiScale(); QVector3D origin() const; void setOrigin(const QVector3D &point); qreal xScale() const; void setXScale(qreal); qreal yScale() const; void setYScale(qreal); qreal zScale() const; void setZScale(qreal); void applyTo(QMatrix4x4* matrix) const override; Q_SIGNALS: void originChanged(); void xScaleChanged(); void yScaleChanged(); void zScaleChanged(); void scaleChanged(); private: QVector3D m_origin; qreal m_xScale = 1.0; qreal m_yScale = 1.0; qreal m_zScale = 1.0; }; class UkuiPositionerAttached : public QObject { Q_OBJECT public: UkuiPositionerAttached(QObject *parent); Q_PROPERTY(int index READ index NOTIFY indexChanged) Q_PROPERTY(bool isFirstItem READ isFirstItem NOTIFY isFirstItemChanged) Q_PROPERTY(bool isLastItem READ isLastItem NOTIFY isLastItemChanged) int index() const { return m_index; } void setIndex(int index); bool isFirstItem() const { return m_isFirstItem; } void setIsFirstItem(bool isFirstItem); bool isLastItem() const { return m_isLastItem; } void setIsLastItem(bool isLastItem); Q_SIGNALS: void indexChanged(); void isFirstItemChanged(); void isLastItemChanged(); private: int m_index; bool m_isFirstItem; bool m_isLastItem; }; class UkuiBasePositioner : public QQuickImplicitSizeItem { Q_OBJECT Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged) Q_PROPERTY(QQuickTransition *populate READ populate WRITE setPopulate NOTIFY populateChanged) Q_PROPERTY(QQuickTransition *move READ move WRITE setMove NOTIFY moveChanged) Q_PROPERTY(QQuickTransition *add READ add WRITE setAdd NOTIFY addChanged) Q_PROPERTY(QQuickTransition *remove READ removeTransition WRITE setRemoveTransition NOTIFY removeTransitionChanged) Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged) Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged) Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged) Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged) Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged) public: enum PositionerType { None = 0x0, Horizontal = 0x1, Vertical = 0x2, Both = 0x3 }; UkuiBasePositioner(PositionerType, QQuickItem *parent); ~UkuiBasePositioner(); qreal spacing() const; void setSpacing(qreal); QQuickTransition *populate() const; void setPopulate(QQuickTransition *); QQuickTransition *move() const; void setMove(QQuickTransition *); QQuickTransition *add() const; void setAdd(QQuickTransition *); QQuickTransition *removeTransition() const; void setRemoveTransition(QQuickTransition *transition); static UkuiPositionerAttached *qmlAttachedProperties(QObject *obj); void updateAttachedProperties(UkuiPositionerAttached *specificProperty = nullptr, QQuickItem *specificPropertyOwner = nullptr) const; qreal padding() const; void setPadding(qreal padding); void resetPadding(); qreal topPadding() const; void setTopPadding(qreal padding); void resetTopPadding(); qreal leftPadding() const; void setLeftPadding(qreal padding); void resetLeftPadding(); qreal rightPadding() const; void setRightPadding(qreal padding); void resetRightPadding(); qreal bottomPadding() const; void setBottomPadding(qreal padding); void resetBottomPadding(); Q_INVOKABLE void forceLayout(); protected: UkuiBasePositioner(UkuiBasePositionerPrivate &dd, PositionerType at, QQuickItem *parent); void componentComplete() override; void itemChange(ItemChange, const ItemChangeData &) override; void updatePolish() override; Q_SIGNALS: void spacingChanged(); void populateChanged(); void moveChanged(); void addChanged(); void removeTransitionChanged(); void paddingChanged(); void topPaddingChanged(); void leftPaddingChanged(); void rightPaddingChanged(); void bottomPaddingChanged(); void positioningComplete(); protected Q_SLOTS: void prePositioning(); protected: virtual void doPositioning(QSizeF *contentSize)=0; virtual void reportConflictingAnchors()=0; class PositionedItem { public: PositionedItem(QQuickItem *i); ~PositionedItem(); bool operator==(const PositionedItem &other) const { return other.item == item; } qreal itemX() const; qreal itemY() const; void moveTo(const QPointF &pos); void transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget); bool prepareTransition(QQuickItemViewTransitioner *transitioner, const QRectF &viewBounds); void startTransition(QQuickItemViewTransitioner *transitioner); void updatePadding(qreal lp, qreal tp, qreal rp, qreal bp); // 添加自定义过渡属性 void setScaleTransition(qreal start, qreal end); void setYTransition(qreal start, qreal end); void applyCustomTransitions(); void addTransformToItem(QQuickTransform* transform); void clearTransformFromItem(); void setYScale(qreal scale); QQuickItem *item; QQuickItemViewTransitionableItem *transitionableItem; int index; bool isNew; bool isVisible; qreal yScale = 1.0; // Animation bool hasScaleTransition = false; qreal startScale = 0.0; qreal endScale = 0.0; qreal topPadding; qreal leftPadding; qreal rightPadding; qreal bottomPadding; }; QList positionedItems; QList unpositionedItems;//Still 'in' the positioner, just not positioned void positionItem(qreal x, qreal y, PositionedItem *target); void positionItemX(qreal, PositionedItem *target); void positionItemY(qreal, PositionedItem *target); void removePositionedItem(QList *items, int index); void clearPositionedItems(QList *items); private: Q_DISABLE_COPY(UkuiBasePositioner) Q_DECLARE_PRIVATE(UkuiBasePositioner) }; class UkuiBasePositionerPrivate : public QQuickImplicitSizeItemPrivate, public QQuickItemChangeListener { Q_DECLARE_PUBLIC(UkuiBasePositioner) public: struct ExtraData { ExtraData(); qreal padding; qreal topPadding; qreal leftPadding; qreal rightPadding; qreal bottomPadding; bool explicitTopPadding : 1; bool explicitLeftPadding : 1; bool explicitRightPadding : 1; bool explicitBottomPadding : 1; }; QLazilyAllocated extra; UkuiBasePositionerPrivate() : spacing(0), type(UkuiBasePositioner::None) , transitioner(0), positioningDirty(false) , doingPositioning(false), anchorConflict(false), layoutDirection(Qt::LeftToRight) { } void init(UkuiBasePositioner::PositionerType at) { type = at; } qreal spacing; UkuiBasePositioner::PositionerType type; QQuickItemViewTransitioner *transitioner; void watchChanges(QQuickItem *other); void unwatchChanges(QQuickItem* other); void setPositioningDirty() { Q_Q(UkuiBasePositioner); if (!positioningDirty) { positioningDirty = true; q->polish(); } } bool positioningDirty : 1; bool doingPositioning : 1; bool anchorConflict : 1; Qt::LayoutDirection layoutDirection; void mirrorChange() override { effectiveLayoutDirectionChange(); } bool isLeftToRight() const { if (type == UkuiBasePositioner::Vertical) return true; else return effectiveLayoutMirror ? layoutDirection == Qt::RightToLeft : layoutDirection == Qt::LeftToRight; } void itemSiblingOrderChanged(QQuickItem* other) override { Q_UNUSED(other); setPositioningDirty(); } void itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &) override { if (change.sizeChange()) setPositioningDirty(); } void itemVisibilityChanged(QQuickItem *) override { setPositioningDirty(); } void itemDestroyed(QQuickItem *item) override { Q_Q(UkuiBasePositioner); int index = q->positionedItems.indexOf(UkuiBasePositioner::PositionedItem(item)); if (index >= 0) q->removePositionedItem(&q->positionedItems, index); } static Qt::LayoutDirection getLayoutDirection(const UkuiBasePositioner *positioner) { return positioner->d_func()->layoutDirection; } static Qt::LayoutDirection getEffectiveLayoutDirection(const UkuiBasePositioner *positioner) { if (positioner->d_func()->effectiveLayoutMirror) return positioner->d_func()->layoutDirection == Qt::RightToLeft ? Qt::LeftToRight : Qt::RightToLeft; else return positioner->d_func()->layoutDirection; } virtual void effectiveLayoutDirectionChange() { } inline qreal padding() const { return extra.isAllocated() ? extra->padding : 0.0; } void setTopPadding(qreal value, bool reset = false); void setLeftPadding(qreal value, bool reset = false); void setRightPadding(qreal value, bool reset = false); void setBottomPadding(qreal value, bool reset = false); }; class Q_AUTOTEST_EXPORT UkuiColumn : public UkuiBasePositioner { Q_OBJECT Q_PROPERTY(bool isFoldMode READ isFoldMode WRITE setFoldMode NOTIFY foldModeChanged) Q_PROPERTY(int heightOffset READ heightOffset NOTIFY heightOffsetChanged) public: UkuiColumn(QQuickItem *parent=nullptr); void setFoldMode(bool isFoldMode); bool isFoldMode() const; int heightOffset() const; protected: void doPositioning(QSizeF *contentSize) override; void reportConflictingAnchors() override; private: Q_DISABLE_COPY(UkuiColumn) bool m_isFoldMode = true; // 由于scale之后,内部的高度仍然保持不变 // 导致处于折叠状态时,内部children的高度会与ui显示的不一致 // 需要手动计算一下偏移量 int m_heightOffset = 0; Q_SIGNALS: void foldModeChanged(); void heightOffsetChanged(); }; QML_DECLARE_TYPEINFO(UkuiPositionerAttached, QML_HAS_ATTACHED_PROPERTIES) #endif //UKUI_FLOW_H ukui-sidebar/src/model/0000775000175000017500000000000015167643374013773 5ustar fengfengukui-sidebar/src/model/shortcut-item.cpp0000664000175000017500000001500015167643374017302 0ustar fengfeng/* * Copyright (C) 2025, 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: youdiansaodongxi * */ #include "shortcut-item.h" #include "shortcut-model.h" #include "shortcut-config.h" using namespace UkuiShortcut; class UkuiShortcut::ShortcutItemPrivate { public: Shortcut* m_shortcut = {nullptr}; StatusInfo m_statusInfos; PluginStateType::AddState m_addState; int m_pluginIndex; PluginStateType::FixState m_fixState; }; UkuiShortcut::ShortcutItem::ShortcutItem(Shortcut *shortcut, QObject *parent) : QObject{parent}, d(new ShortcutItemPrivate) { d->m_shortcut = shortcut; if (d->m_shortcut->pluginMetaData().value(PluginMetaType::PC).pluginType() == PluginMetaType::ProgressBar) { d->m_addState = PluginStateType::NotAdd; d->m_pluginIndex = d->m_shortcut->pluginMetaData().value(PluginMetaType::PC).index(); d->m_shortcut->setAddedState(true); d->m_fixState = PluginStateType::Fix; } else { QString id = d->m_shortcut->pluginId(); ShortcutConfig::instance().recordShortcut(id); d->m_addState = ShortcutConfig::instance().getShortcutState(id); d->m_pluginIndex = ShortcutConfig::instance().getShortcutIndex(id, d->m_addState); d->m_shortcut->setAddedState(d->m_addState == PluginStateType::Add); d->m_fixState = PluginStateType::NotFix; connect(&ShortcutConfig::instance(), &ShortcutConfig::configChanged, this, [=] { QString id = d->m_shortcut->pluginId(); auto state = ShortcutConfig::instance().getShortcutState(id); int index = ShortcutConfig::instance().getShortcutIndex(id, state); QVector roles(0); if (d->m_addState != state) { d->m_addState = state; d->m_shortcut->setAddedState(d->m_addState == PluginStateType::Add); roles.append(ShortcutModel::AddState); } if (d->m_pluginIndex != index) { d->m_pluginIndex = index; roles.append(ShortcutModel::PluginIndex); } if (roles.isEmpty()) return; Q_EMIT itemDataChanged(roles); }); } d->m_statusInfos = d->m_shortcut->currentStatus(); connect(d->m_shortcut, &Shortcut::enableStatusChanged, this, [=] { QVector roles(0); roles.append(ShortcutModel::IsEnable); Q_EMIT itemDataChanged(roles); }); connect(d->m_shortcut, &Shortcut::statusChanged, this, [=] (const StatusInfo &info) { QVector roles(0); compareDataChanges(roles, info, d->m_statusInfos); d->m_statusInfos = info; if (roles.isEmpty()) return; Q_EMIT itemDataChanged(roles); }); } ShortcutItem::~ShortcutItem() { if(d) { delete d; d = nullptr; } } QString ShortcutItem::pluginId() const { return d->m_shortcut->pluginId(); } bool ShortcutItem::isEnable() const { return d->m_shortcut->isEnable(); } bool ShortcutItem::isVisible(PluginMetaType::SystemMode systemMode) const { return d->m_shortcut->pluginMetaData().value(systemMode).isVisible(); } bool ShortcutItem::disabled() const { return d->m_statusInfos.isDisabled(); } QString ShortcutItem::name() const { return d->m_statusInfos.getName(); } QString ShortcutItem::statusName() const { return d->m_statusInfos.getStatusName(); } QString ShortcutItem::widgetId() const { return d->m_statusInfos.getWidgetId(); } QString ShortcutItem::icon() const { return d->m_statusInfos.getIcon(); } QString ShortcutItem::tooltip() const { return d->m_statusInfos.getToolTip(); } Color::ColorRole ShortcutItem::color() const { return d->m_statusInfos.getColor(); } int ShortcutItem::value() const { return d->m_statusInfos.getValue(); } QVariant ShortcutItem::menu() const { return QVariant::fromValue >(d->m_statusInfos.getMenu()); } PluginMetaType::PluginType ShortcutItem::itemType(PluginMetaType::SystemMode systemMode) const { return d->m_shortcut->pluginMetaData().value(systemMode).pluginType(); } int ShortcutItem::row() const { return 1; } int ShortcutItem::column(PluginMetaType::SystemMode systemMode) const { return d->m_shortcut->pluginMetaData().value(systemMode).pluginType() == PluginMetaType::MenuButton ? 2 : 1; } PluginStateType::AddState ShortcutItem::addState() const { return d->m_addState; } int ShortcutItem::pluginIndex() const { return d->m_pluginIndex; } PluginStateType::FixState ShortcutItem::fixState() const { return d->m_fixState; } void ShortcutItem::active(PluginMetaType::Action action, PluginMetaType::SystemMode systemMode) { PluginMetaType::PredefinedAction preAction = d->m_shortcut->pluginMetaData().value(systemMode).preAction(); if (preAction != PluginMetaType::NoAction) { Q_EMIT requestExecAction(preAction); } d->m_shortcut->active(action); } void ShortcutItem::setValue(int value) { d->m_shortcut->setValue(value); } void ShortcutItem::compareDataChanges(QVector &roles, const StatusInfo &infoA, const StatusInfo &infoB) const { if (infoA.getName() != infoB.getName()) { roles.append(ShortcutModel::Name); } if (infoA.getStatusName() != infoB.getStatusName()) { roles.append(ShortcutModel::StatusName); } if (infoA.getWidgetId() != infoB.getWidgetId()) { roles.append(ShortcutModel::WidgetId); } if (infoA.getColor() != infoB.getColor()) { roles.append(ShortcutModel::Color); } if (infoA.getToolTip() != infoB.getToolTip()) { roles.append(ShortcutModel::ToolTip); } if (infoA.getIcon() != infoB.getIcon()) { roles.append(ShortcutModel::Icon); } if (infoA.isDisabled() != infoB.isDisabled()) { roles.append(ShortcutModel::Disabled); } if (infoA.getValue() != infoB.getValue()) { roles.append(ShortcutModel::Value); } } ukui-sidebar/src/model/shortcut-config.cpp0000664000175000017500000001567415167606206017623 0ustar fengfeng/* * Copyright (C) 2025, 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: youdiansaodongxi * */ #include "shortcut-config.h" #include #include static const QStringList SHORTCUT_ADDED_LIST = {"WiFi", "BluetoothShortcut", "StatusChangeShortcut", "AutoRotationShortcut", "EyeCareShortcut", "DarkModeShortcut", "Clock", "Notebook", "MultiScreenShortcut", "ScreenShot", "ServicesAndSupportsShortcut", "SplitviewManagerShortcut"}; static const QStringList SHORTCUT_NOT_ADDED_LIST = {"FlightModeShortcut", "ClipboardShortcut", "PowerModeShortcut", "VPN", "ConnectivityShortcut"}; using namespace UkuiShortcut; ShortcutConfig &ShortcutConfig::instance() { static ShortcutConfig shortcutConfig; return shortcutConfig; } void ShortcutConfig::setShortcutOrder(const int &indexFrom, const int &indexTo, PluginStateType::AddState state) { if (indexFrom < 0 || indexTo < 0) return; if (state == PluginStateType::Add) { if ((indexFrom > m_addedList.length() - 1) || indexTo > m_addedList.length() - 1) return; m_addedList.move(indexFrom, indexTo); m_config->setValue(QStringLiteral("addedList"), m_addedList); } else { if ((indexFrom > m_notAddedList.length() - 1) || indexTo > m_notAddedList.length() - 1) return; m_notAddedList.move(indexFrom, indexTo); m_config->setValue(QStringLiteral("notAddedList"), m_notAddedList); } m_config->forceSync(); verify(); } void ShortcutConfig::setShortcutOrder(const QString &idFrom, const int &indexTo, PluginStateType::AddState stateTo) { if (stateTo == PluginStateType::Add) { if (m_addedList.contains(idFrom)) return; m_notAddedList.removeAll(idFrom); m_addedList.insert(indexTo, idFrom); } else { if (m_notAddedList.contains(idFrom)) return; m_addedList.removeAll(idFrom); m_notAddedList.insert(indexTo, idFrom); } m_config->setValue(QStringLiteral("addedList"), m_addedList); m_config->setValue(QStringLiteral("notAddedList"), m_notAddedList); m_config->forceSync(); verify(); } void ShortcutConfig::changeShortcutState(const QString &idFrom, PluginStateType::AddState stateFrom, bool atEnd) { if (stateFrom == PluginStateType::Add) { if (!m_addedList.contains(idFrom)) return; m_addedList.removeAll(idFrom); if (atEnd) { m_notAddedList.append(idFrom); } else { m_notAddedList.prepend(idFrom); } } else { if (!m_notAddedList.contains(idFrom)) return; m_notAddedList.removeAll(idFrom); if (atEnd) { m_addedList.append(idFrom); } else { m_addedList.prepend(idFrom); } } m_config->setValue(QStringLiteral("addedList"), m_addedList); m_config->setValue(QStringLiteral("notAddedList"), m_notAddedList); m_config->forceSync(); verify(); } void ShortcutConfig::recordShortcut(const QString &key) { if (m_addedList.contains(key) || m_notAddedList.contains(key)) { return; } m_notAddedList.append(key); m_config->setValue(QStringLiteral("notAddedList"), m_notAddedList); m_config->forceSync(); verify(); } PluginStateType::AddState ShortcutConfig::getShortcutState(const QString &key) { if (m_addedList.contains(key)) { return PluginStateType::Add; } else { return PluginStateType::NotAdd; } } int ShortcutConfig::getShortcutIndex(const QString &key, PluginStateType::AddState state) { if (state == PluginStateType::Add) { return m_addedList.indexOf(key); } else { return m_notAddedList.indexOf(key); } } ShortcutConfig::ShortcutConfig(QObject *parent) : QObject{parent} { initConfig(); verify(); } void ShortcutConfig::initConfig() { if (!m_config) { m_config = UkuiQuick::ConfigLoader::getConfig("org.ukui.shortcut", UkuiQuick::ConfigLoader::Local, "ukui-sidebar"); } const auto &data = m_config->data(); //版本号校验 if (!data.contains(QStringLiteral("version"))) { m_config->setValue(QStringLiteral("version"), QStringLiteral("1.0")); m_config->setValue(QStringLiteral("addedList"), SHORTCUT_ADDED_LIST); m_config->setValue(QStringLiteral("notAddedList"), SHORTCUT_NOT_ADDED_LIST); m_addedList = SHORTCUT_ADDED_LIST; m_notAddedList = SHORTCUT_NOT_ADDED_LIST; } else { if (!data.contains(QStringLiteral("addedList"))) { m_config->setValue(QStringLiteral("addedList"), SHORTCUT_ADDED_LIST); m_addedList = SHORTCUT_ADDED_LIST; } else { m_addedList = m_config->getValue(QStringLiteral("addedList")).toStringList(); } if (!data.contains(QStringLiteral("notAddedList"))) { m_config->setValue(QStringLiteral("notAddedList"), SHORTCUT_NOT_ADDED_LIST); m_notAddedList = SHORTCUT_NOT_ADDED_LIST; } else { m_notAddedList = m_config->getValue(QStringLiteral("notAddedList")).toStringList(); } } connect(m_config, &UkuiQuick::Config::configChanged, this, &ShortcutConfig::configChanged); m_config->forceSync(); } void ShortcutConfig::verify() { QSet setAdd(m_addedList.begin(), m_addedList.end()); QSet setNotAdd(m_notAddedList.begin(), m_notAddedList.end()); if (setAdd.intersects(setNotAdd)) { qDebug() << "shortcut config duplicated"; setAdd.intersect(setNotAdd); for (const QString &id : setAdd) { m_notAddedList.removeAll(id); } m_config->setValue(QStringLiteral("notAddedList"), m_notAddedList); m_config->forceSync(); } } ukui-sidebar/src/model/widget-delegate.cpp0000664000175000017500000000637515167606206017536 0ustar fengfeng/* * Copyright (C) 2024, 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 "widget-delegate.h" #include #include #include #include #include namespace UkuiShortcut { WidgetDelegate::WidgetDelegate(QQuickItem* parent) { m_widgetLoader = new UkuiQuick::WidgetLoader(this); m_widgetLoader->addWidgetSearchPath(QStringLiteral(":/shortcut")); m_widgetLoader->setShowInFilter(UkuiQuick::WidgetMetadata::Host::Shortcut); loadContainer(); } WidgetDelegate::~WidgetDelegate() { if(m_container) { Q_EMIT m_container->aboutToDeleted(); m_container->deleteLater(); m_container = nullptr; } } QString WidgetDelegate::quickWidgetId() const { return m_quickWidgetId; } void WidgetDelegate::setQuickWidgetId(const QString& id) { if(m_quickWidgetId != id) { m_quickWidgetId = id; Q_EMIT quickWidgetIdChanged(); } loadWidget(); } qreal WidgetDelegate::preferredWidth() const { return m_preferredWidth; } qreal WidgetDelegate::preferredHeight() const { return m_preferredHeight; } void WidgetDelegate::loadContainer() { auto widget = m_widgetLoader->loadWidget(QStringLiteral("org.ukui.shortcutContainer")); auto container = qobject_cast(widget); if (!container) { qWarning() << "Load shortcutContainer failed!"; delete widget; return; } m_container = container; auto contItem = qobject_cast(UkuiQuick::WidgetQuickItem::loadWidgetItem(m_container, new QQmlContext(UkuiQuick::SharedEngineComponent::sharedEngine(), this))); if (!contItem) { qWarning() << "Load taskManagerContainerItem failed!"; return; } contItem->setParentItem(this); m_preferredWidth = contItem->childrenRect().width(); m_preferredHeight = contItem->childrenRect().height(); setSize(contItem->childrenRect().size()); connect(contItem, &QQuickItem::childrenRectChanged, this, [&, contItem]() { setSize(contItem->childrenRect().size()); m_preferredWidth = contItem->childrenRect().width(); m_preferredHeight = contItem->childrenRect().height(); Q_EMIT preferredWidthChanged(); Q_EMIT preferredHeightChanged(); }); } void WidgetDelegate::loadWidget() { if(m_widget) { m_container->removeWidget(m_widget); } m_widget = m_widgetLoader->loadWidget(m_quickWidgetId); if (m_widget) qDebug() << "Loading widget:" << m_widget->id(); m_container->addWidget(m_widget); } } ukui-sidebar/src/model/shortcut-model.h0000664000175000017500000000561115167643374017120 0ustar fengfeng/* * Copyright (C) 2025, 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: youdiansaodongxi * */ #ifndef SHORTCUTMODEL_H #define SHORTCUTMODEL_H #include #include "short-cut-manager.h" #include "edit-shortcut-model.h" #include "shortcut-filter-model.h" namespace UkuiShortcut { class ShortcutItem; class ShortcutModel : public QAbstractListModel { Q_OBJECT public: enum Role { Disabled = 0, Name, StatusName, WidgetId, Icon, ToolTip, Color, Value, Menu, Row, Column, ItemType, IsEnable, IsVisible, AddState, PluginIndex, PluginId, FixState }; Q_ENUM(Role) explicit ShortcutModel(QObject *parent = nullptr); int rowCount(const QModelIndex &parent) const override; QVariant data(const QModelIndex &index, int role) const override; QHash roleNames() const override; void insertShortcut(Shortcut *shortcut); Q_INVOKABLE UkuiShortcut::EditShortcutModel* getModel(PluginStateType::AddState state); Q_INVOKABLE UkuiShortcut::ShortcutFilterModel* prosessBarModel(); Q_INVOKABLE QString editIconName(); void active(int index, PluginMetaType::Action action); /** * 给插件设置value,可以反射 * @brief setValue * @param index * @param value */ void setValue(int index, int value); /** * 前端在拖动进度条时,需要屏蔽插件的value更新,用于保证前端进度条拖动的流畅性 * @param disable */ void disableValueUpdate(bool disable); void updateValue(int idx); Q_SIGNALS: void requestExecAction(UkuiShortcut::PluginMetaType::PredefinedAction action); private Q_SLOTS: void updateCurrentMode(const QString &key); private: void initShortcutModel(); ShortcutManager *m_shortcutManager = nullptr; QVector m_shortcutItems; PluginMetaType::SystemMode m_currentMode = PluginMetaType::PC; bool m_disableValueUpdate = false; EditShortcutModel* m_addModel = nullptr; EditShortcutModel* m_notAddModel = nullptr; ShortcutFilterModel* m_progressBarModel = nullptr; }; } // UkuiShortcut #endif // SHORTCUTMODEL_H ukui-sidebar/src/model/shortcut-filter-model.cpp0000664000175000017500000000551415167606206020731 0ustar fengfeng/* * 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-7-28. // #include "shortcut-filter-model.h" #include "shortcut-item.h" #include "global-settings.h" #include "shortcut-model.h" #include using namespace UkuiShortcut; ShortcutFilterModel::ShortcutFilterModel(ShortcutModel *sourceModel, PluginStateType::FixState fixState, QObject *parent) : QSortFilterProxyModel(parent) { QSortFilterProxyModel::setSourceModel(sourceModel); m_sourceModel = sourceModel; m_fixState = fixState; connect(m_sourceModel, &ShortcutModel::dataChanged, this, &ShortcutFilterModel::onSourceModelDataChanged); sort(0); } QVariant ShortcutFilterModel::data(const QModelIndex &index, int role) const { return sourceModel()->data(mapToSource(index), role); } void ShortcutFilterModel::active(int i, PluginMetaType::Action action) { m_sourceModel->active(mapToSource(index(i, 0)).row(), action); } void ShortcutFilterModel::setValue(int i, int value) { m_sourceModel->setValue(mapToSource(index(i, 0)).row(), value); } void ShortcutFilterModel::disableValueUpdate(bool disable) { m_sourceModel->disableValueUpdate(disable); } void ShortcutFilterModel::updateValue(int idx) { if (idx < 0 || idx >= rowCount()) return; QModelIndex current = index(idx, 0); Q_EMIT dataChanged(current, current, {ShortcutModel::Value}); } bool ShortcutFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { const QModelIndex modelIndex = sourceModel()->index(source_row, 0, source_parent); return (modelIndex.data(ShortcutModel::FixState).toInt() == m_fixState) && modelIndex.data(ShortcutModel::IsEnable).toBool() && modelIndex.data(ShortcutModel::IsVisible).toBool(); } bool ShortcutFilterModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const { return source_left.data(ShortcutModel::PluginIndex).toInt() < source_right.data(ShortcutModel::PluginIndex).toInt(); } void ShortcutFilterModel::onSourceModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { if (roles.contains(ShortcutModel::PluginIndex)) { invalidate(); } } ukui-sidebar/src/model/widget-delegate.h0000664000175000017500000000366015167606206017175 0ustar fengfeng/* * Copyright (C) 2024, 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 WIDGET_DELEGATE_H #define WIDGET_DELEGATE_H #include namespace UkuiQuick { class WidgetContainer; class Widget; class WidgetLoader; } namespace UkuiShortcut { class WidgetDelegate : public QQuickItem { Q_OBJECT Q_PROPERTY(QString quickWidgetId READ quickWidgetId WRITE setQuickWidgetId NOTIFY quickWidgetIdChanged) Q_PROPERTY(qreal preferredWidth READ preferredWidth NOTIFY preferredWidthChanged) Q_PROPERTY(qreal preferredHeight READ preferredHeight NOTIFY preferredHeightChanged) public: explicit WidgetDelegate(QQuickItem *parent = nullptr); ~WidgetDelegate(); QString quickWidgetId() const; void setQuickWidgetId(const QString &id); qreal preferredWidth() const; qreal preferredHeight() const; Q_SIGNALS: void quickWidgetIdChanged(); void preferredWidthChanged(); void preferredHeightChanged(); private: void loadContainer(); void loadWidget(); QString m_quickWidgetId; UkuiQuick::WidgetLoader *m_widgetLoader = nullptr; UkuiQuick::WidgetContainer *m_container = nullptr; UkuiQuick::Widget *m_widget = nullptr; qreal m_preferredWidth = 0; qreal m_preferredHeight = 0; }; } #endif //WIDGET_DELEGATE_H ukui-sidebar/src/model/shortcut-config.h0000664000175000017500000000360215167606206017254 0ustar fengfeng/* * Copyright (C) 2025, 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: youdiansaodongxi * */ #ifndef SHORTCUTCONFIG_H #define SHORTCUTCONFIG_H #include #include #include #include "plugin-state.h" namespace UkuiShortcut { class ShortcutConfig : public QObject { Q_OBJECT public: static ShortcutConfig & instance(); void setShortcutOrder(const int &indexFrom, const int &indexTo, PluginStateType::AddState state); void setShortcutOrder(const QString &idFrom, const int &indexTo, PluginStateType::AddState stateTo); void changeShortcutState(const QString &idFrom, PluginStateType::AddState stateFrom, bool atEnd); void recordShortcut(const QString &key); PluginStateType::AddState getShortcutState(const QString &key); int getShortcutIndex(const QString &key, PluginStateType::AddState state); Q_SIGNALS: void configChanged(const QString &key); private: explicit ShortcutConfig(QObject *parent = nullptr); void initConfig(); void verify(); UkuiQuick::Config *m_config {nullptr}; int m_separateIndex = 5; QStringList m_orderList; QStringList m_addedList; QStringList m_notAddedList; QMap m_idMap; }; } #endif // SHORTCUTCONFIG_H ukui-sidebar/src/model/edit-shortcut-model.h0000664000175000017500000000371115167643374020042 0ustar fengfeng/* * Copyright (C) 2025, 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: youdiansaodongxi * */ #ifndef EDITSHORTCUTMODEL_H #define EDITSHORTCUTMODEL_H #include #include "shortcut-filter-model.h" #include "plugin-state.h" namespace UkuiShortcut { class ShortcutModel; class EditShortcutModel : public ShortcutFilterModel { Q_OBJECT public: explicit EditShortcutModel(ShortcutModel* sourceModel, PluginStateType::AddState addState, QObject *parent = nullptr); Q_INVOKABLE void moveItem(int sourceIndex, int targetIndex); Q_INVOKABLE void setOrder(QString fromId, int toIndex); Q_INVOKABLE void changeState(QString idFrom, PluginStateType::AddState stateFrom, bool atEnd = true); Q_INVOKABLE void updateItemRect(QQuickItem* flowItem); Q_INVOKABLE void findTargetItem(qreal x, qreal y, QObject* resultObj); protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; private: int m_itemWidth = 80; int m_itemHeight = 72; int m_columns = 4; int m_rowSpacing = 12; int m_columnSpacing = 12; int m_flowWidth; Qt::LayoutDirection m_layoutDirection{Qt::LayoutDirection::LeftToRight}; QList m_items; PluginStateType::AddState m_addState = PluginStateType::Add; }; } #endif // EDITSHORTCUTMODEL_H ukui-sidebar/src/model/plugin-state.h0000664000175000017500000000071415167606206016553 0ustar fengfeng#ifndef PLUGINSTATE_H #define PLUGINSTATE_H #include namespace UkuiShortcut { class PluginStateType { Q_GADGET public: enum AddState { Add = 0, //已添加 NotAdd, //未添加 }; Q_DECLARE_FLAGS(AddStates, AddState) Q_ENUM(AddState) enum FixState { Fix = 0, //已固定 NotFix, //未固定 }; Q_DECLARE_FLAGS(FixStates, FixState) Q_ENUM(FixState) }; } #endif // PLUGINSTATE_H ukui-sidebar/src/model/shortcut-filter-model.h0000664000175000017500000000376315167606206020402 0ustar fengfeng/* * 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-7-28. // #ifndef SHORTCUTFILTERMODEL_H #define SHORTCUTFILTERMODEL_H #include #include "plugin-common-data.h" #include "plugin-state.h" namespace UkuiShortcut { class ShortcutModel; class ShortcutFilterModel : public QSortFilterProxyModel { Q_OBJECT public: explicit ShortcutFilterModel(ShortcutModel* sourceModel, PluginStateType::FixState fixState, QObject *parent = nullptr); QVariant data(const QModelIndex &index, int role) const override; Q_INVOKABLE void active(int i, PluginMetaType::Action action); Q_INVOKABLE void setValue(int i, int value); Q_INVOKABLE void disableValueUpdate(bool disable); Q_INVOKABLE void updateValue(int idx); protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override; protected Q_SLOTS: void onSourceModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()); private: ShortcutModel* m_sourceModel = nullptr; PluginStateType::FixState m_fixState = PluginStateType::Fix; }; } // UkuiShortcut #endif //SHORTCUTFILTERMODEL_H ukui-sidebar/src/model/shortcut-item.h0000664000175000017500000000430215167643374016752 0ustar fengfeng/* * Copyright (C) 2025, 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: youdiansaodongxi * */ #ifndef SHORTCUTITEM_H #define SHORTCUTITEM_H #include #include #include #include "ukui-shortcut.h" #include "plugin-state.h" namespace UkuiShortcut { class ShortcutItemPrivate; class ShortcutItem : public QObject { Q_OBJECT public: explicit ShortcutItem(Shortcut* shortcut, QObject *parent = nullptr); ~ShortcutItem(); QString pluginId() const; bool isEnable() const; bool isVisible(PluginMetaType::SystemMode systemMode) const; bool disabled() const; QString name() const; QString statusName() const; QString widgetId() const; QString icon() const; QString tooltip() const; Color::ColorRole color() const; int value() const; QVariant menu() const; PluginMetaType::PluginType itemType(PluginMetaType::SystemMode systemMode) const; int row() const; int column(PluginMetaType::SystemMode systemMode) const; PluginStateType::AddState addState() const; int pluginIndex() const; PluginStateType::FixState fixState() const; void active(PluginMetaType::Action action, PluginMetaType::SystemMode systemMode); void setValue(int value); Q_SIGNALS: void itemDataChanged(QVector &roles); void requestExecAction(UkuiShortcut::PluginMetaType::PredefinedAction action); private: void compareDataChanges(QVector &roles, const StatusInfo &infoA, const StatusInfo &infoB) const; ShortcutItemPrivate *d = nullptr; }; } #endif // SHORTCUTITEM_H ukui-sidebar/src/model/shortcut-model.cpp0000664000175000017500000001552415167643374017457 0ustar fengfeng/* * Copyright (C) 2025, 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: youdiansaodongxi * */ #include "shortcut-model.h" #include "shortcut-config.h" #include "shortcut-item.h" #include "global-settings.h" #include #include using namespace UkuiShortcut; ShortcutModel::ShortcutModel(QObject *parent) : QAbstractListModel(parent) { initShortcutModel(); m_addModel = new EditShortcutModel(this, PluginStateType::Add, this); m_notAddModel = new EditShortcutModel(this, PluginStateType::NotAdd, this); m_progressBarModel = new ShortcutFilterModel(this, PluginStateType::Fix, this); qRegisterMetaType("EditShortcutModel*"); qRegisterMetaType("ShortcutFilterModel*"); updateCurrentMode(TABLET_MODE); } int ShortcutModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent) return m_shortcutItems.length(); } QVariant ShortcutModel::data(const QModelIndex &index, int role) const { int row = index.row(); if (row < 0 || row >= m_shortcutItems.length()) { return {}; } ShortcutItem* shortcut = m_shortcutItems.value(row); switch (role) { case Disabled: { return shortcut->disabled(); } case Name: { return shortcut->name(); } case StatusName: { return shortcut->statusName(); } case WidgetId: { return shortcut->widgetId(); } case Icon: { return shortcut->icon(); } case ToolTip: { return shortcut->tooltip(); } case Color: { return shortcut->color(); } case Value: { return shortcut->value(); } case Menu: { return shortcut->menu(); } case Row: { return shortcut->row(); } case Column: { return shortcut->column(m_currentMode); } case ItemType: { return shortcut->itemType(m_currentMode); } case IsEnable: { return shortcut->isEnable(); } case IsVisible: { return shortcut->isVisible(m_currentMode); } case AddState: { return shortcut->addState(); } case PluginIndex: { return shortcut->pluginIndex(); } case PluginId: { return shortcut->pluginId(); } case FixState: { return shortcut->fixState(); } default: break; } return {}; } QHash ShortcutModel::roleNames() const { QHash names; names.insert(Disabled, "disabled"); names.insert(Name, "name"); names.insert(StatusName, "statusName"); names.insert(WidgetId, "widgetId"); names.insert(Icon, "icon"); names.insert(ToolTip, "tooltip"); names.insert(Color, "color"); names.insert(Value, "value"); names.insert(Menu, "menu"); names.insert(Row, "row"); names.insert(Column, "column"); names.insert(ItemType, "itemType"); names.insert(IsEnable, "isEnable"); names.insert(IsVisible, "isVisible"); names.insert(AddState, "addState"); names.insert(PluginIndex, "pluginIndex"); names.insert(PluginId, "pluginId"); // names.insert(FixState, "fixState"); return names; } void ShortcutModel::insertShortcut(Shortcut *shortcut) { if (!shortcut) return; ShortcutItem* shortcutItem = new ShortcutItem(shortcut, this); beginInsertRows(QModelIndex(), m_shortcutItems.length(), m_shortcutItems.length()); m_shortcutItems.append(shortcutItem); endInsertRows(); connect(shortcutItem, &ShortcutItem::requestExecAction, this, &ShortcutModel::requestExecAction); connect(shortcutItem, &ShortcutItem::itemDataChanged, this, [=] (QVector &roles) { QModelIndex current = index(m_shortcutItems.indexOf(shortcutItem), 0); if (m_disableValueUpdate && roles.contains(Value)) { roles.remove(roles.indexOf(Value)); if (roles.empty()) { return; } } Q_EMIT dataChanged(current, current, roles); }); } EditShortcutModel *ShortcutModel::getModel(PluginStateType::AddState state) { return state == PluginStateType::Add ? m_addModel : m_notAddModel; } ShortcutFilterModel *ShortcutModel::prosessBarModel() { return m_progressBarModel; } QString ShortcutModel::editIconName() { return QIcon::fromTheme("edit-symbolic").isNull() ? "://icon/edit.svg" : "edit-symbolic"; } void ShortcutModel::active(int index, PluginMetaType::Action action) { if (index < 0 || index >= m_shortcutItems.size()) return; ShortcutItem *shortcutItem = m_shortcutItems.at(index); shortcutItem->active(action, m_currentMode); } void ShortcutModel::setValue(int index, int value) { if (index < 0 || index >= m_shortcutItems.size()) return; ShortcutItem *shortcutItem = m_shortcutItems.at(index); shortcutItem->setValue(value); } void ShortcutModel::disableValueUpdate(bool disable) { m_disableValueUpdate = disable; } void ShortcutModel::updateValue(int idx) { if (idx < 0 || idx >= m_shortcutItems.size()) return; QModelIndex current = index(idx, 0); Q_EMIT dataChanged(current, current, {ShortcutModel::Value}); } void ShortcutModel::updateCurrentMode(const QString &key) { if (key == TABLET_MODE) { bool isTabletMode = Sidebar::GlobalSettings::globalInstance()->getValue(TABLET_MODE).toBool(); auto mode = isTabletMode ? PluginMetaType::Tablet : PluginMetaType::PC; if (mode != m_currentMode) { m_currentMode = mode; if (m_shortcutItems.length() == 0) return; QModelIndex from = index(0, 0); QModelIndex to = index(m_shortcutItems.length() - 1, 0); dataChanged(from, to, {Column, ItemType, IsVisible}); } } } void ShortcutModel::initShortcutModel() { m_shortcutManager = ShortcutManager::getInstance(); for (const auto &item : m_shortcutManager->getShortcuts()) { insertShortcut(item); } connect(Sidebar::GlobalSettings::globalInstance(), &Sidebar::GlobalSettings::valueChanged, this, &ShortcutModel::updateCurrentMode); } ukui-sidebar/src/model/edit-shortcut-model.cpp0000664000175000017500000001011615167643374020372 0ustar fengfeng/* * Copyright (C) 2025, 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: youdiansaodongxi * */ #include "edit-shortcut-model.h" #include "shortcut-model.h" #include "shortcut-config.h" #include #include #include using namespace UkuiShortcut; EditShortcutModel::EditShortcutModel(ShortcutModel *sourceModel, PluginStateType::AddState addState, QObject *parent) : ShortcutFilterModel(sourceModel, PluginStateType::NotFix, parent) { QSortFilterProxyModel::setSourceModel(sourceModel); m_addState = addState; m_layoutDirection = QGuiApplication::layoutDirection(); connect(qGuiApp, &QGuiApplication::layoutDirectionChanged, this, [this] { m_layoutDirection = QGuiApplication::layoutDirection(); }); invalidate(); } void EditShortcutModel::moveItem(int sourceIndex, int targetIndex) { int srcRow = data(index(sourceIndex, 0), ShortcutModel::PluginIndex).toInt(); int targetRow = data(index(targetIndex, 0), ShortcutModel::PluginIndex).toInt(); ShortcutConfig::instance().setShortcutOrder(srcRow, targetRow, m_addState); } void EditShortcutModel::setOrder(QString fromId, int toIndex) { int targetRow = data(index(toIndex, 0), ShortcutModel::PluginIndex).toInt(); ShortcutConfig::instance().setShortcutOrder(fromId, targetRow, m_addState); } void EditShortcutModel::changeState(QString idFrom, PluginStateType::AddState stateFrom, bool atEnd) { ShortcutConfig::instance().changeShortcutState(idFrom, stateFrom, atEnd); } void EditShortcutModel::updateItemRect(QQuickItem *flowItem) { QList items = flowItem->childItems(); int currentRow = 0; int currentColumn = 0; for (int i = 0; i < items.count(); ++i) { QQuickItem* item = items.at(i); const int columnSpan = item->property("columnSpan").toInt(); if (columnSpan == 0) break; if (currentColumn + columnSpan > m_columns) { currentRow++; currentColumn = 0; } const qreal x = currentColumn * (m_itemWidth + m_columnSpacing); const qreal y = currentRow * (m_itemHeight + m_rowSpacing); const QRect rect = QRect(x, y, m_itemWidth * columnSpan + m_columnSpacing * (columnSpan - 1), m_itemHeight); item->setProperty("targetRect", rect); currentColumn += columnSpan; } flowItem->setProperty("rows", currentRow + 1); m_items = items; m_flowWidth = flowItem->width(); } void EditShortcutModel::findTargetItem(qreal x, qreal y, QObject *resultObj) { if (m_layoutDirection == Qt::LayoutDirection::RightToLeft) { x = m_flowWidth - x; } QList items = m_items; for (int i = 0; i < items.count(); ++i) { QQuickItem* item = items.at(i); const QRect rect = item->property("targetRect").toRect(); if (rect.contains(x, y)) { resultObj->setProperty("index", i); resultObj->setProperty("offset", rect.width() > 80 ? (rect.x() + rect.width()/2 > x) ? 0 : 1 : -1); return; } } resultObj->setProperty("index", -1); resultObj->setProperty("offset", 0); } bool EditShortcutModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { const QModelIndex modelIndex = sourceModel()->index(source_row, 0, source_parent); return (modelIndex.data(ShortcutModel::AddState).toInt() == m_addState) && ShortcutFilterModel::filterAcceptsRow(source_row, source_parent); } ukui-sidebar/src/sidebar-dbus-service.cpp0000664000175000017500000000554315167606206017401 0ustar fengfeng/* * 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-dbus-service.h" #include "sidebaradaptor.h" #include #include #include #define SIDEBAR_DBUS_SERVICE "org.ukui.Sidebar" #define SIDEBAR_DBUS_PATH "/org/ukui/Sidebar" #define SIDEBAR_DBUS_INTERFACE "org.ukui.Sidebar" namespace Sidebar { SidebarDbusService::SidebarDbusService(SidebarMain *parent) : QObject(parent), QDBusContext(), m_adaptor(new SidebarAdaptor(this)) { QDBusReply reply = QDBusConnection::sessionBus().interface()->registerService(SIDEBAR_DBUS_SERVICE, QDBusConnectionInterface::ReplaceExistingService, QDBusConnectionInterface::DontAllowReplacement); if (reply.value() != QDBusConnectionInterface::ServiceNotRegistered) { bool res = QDBusConnection::sessionBus().registerObject(SIDEBAR_DBUS_PATH, this); if (!res) { QDBusConnection::sessionBus().interface()->unregisterService(SIDEBAR_DBUS_SERVICE); } } connect(parent, &SidebarMain::stateChange, m_adaptor, &SidebarAdaptor::stateChange); } SidebarMain *SidebarDbusService::parent() { return qobject_cast(QObject::parent()); } void SidebarDbusService::sidebarActive() { active(QStringLiteral("sidebar")); } void SidebarDbusService::shortcutsActive() { active(QStringLiteral("shortcut")); } void SidebarDbusService::active(const QString &module) { // 快捷按钮界面 if (module == QStringLiteral("shortcut")) { parent()->requestShortcut(SidebarMain::Active); // PC侧边栏(PC通知页面) } else if (module == QStringLiteral("sidebar")) { parent()->requestSidebar(SidebarMain::Active); // 通知中心 } else if (module == QStringLiteral("notice")) { parent()->requestNotificationCenter(SidebarMain::Active); } } void SidebarDbusService::shortcutWidgetActive(const QString &id, bool showReturnButton) { if (id == "") return; parent()->requestWidgetActive(id, showReturnButton); } } // Sidebar ukui-sidebar/src/log-utils.h0000664000175000017500000000243215167643374014764 0ustar fengfeng/* * Copyright (C) 2024, 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 LOGUTILS_H #define LOGUTILS_H #include class LogUtils { public: static void initLogFile(const QString &fileName); static void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg); private: static void checkLogFile(); static bool checkFileSize(const QString &fileName); static void clearFile(const QString &fileName); static quint64 m_startUpTime; static int m_logFileId; static QString m_logFileName; static QString m_currentLogFile; }; #endif // LOGUTILS_H ukui-sidebar/src/sidebar-main.cpp0000664000175000017500000003621615167606206015733 0ustar fengfeng/* * 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-main.h" #include #include #include #include #include #include #include #include #include "global-settings.h" #include "short-cut-manager.h" #include "screen-monitor.h" #include "hand-gesture-helper.h" #include "date-time-utils.h" #include "window-blur-helper.h" #include "app-manager.h" #include "sidebar-window-helper.h" #include "sidebar-view.h" #include "notification-window.h" #include "popup-notification-window.h" #include "notification-model.h" #include "tablet-popup-view.h" #include "status-bar-view.h" #include "right-hand-gesture-view.h" #include "event-track.h" #include "shortcuts-window.h" #include "sidebar-dbus-service.h" #include "model/widget-delegate.h" #include "layout/ukui-column.h" #include "plugin-state.h" //注册托盘 #define TRAY_ICON ":/icon/kylin-tool-box.svg" #define TRAY_NULL_ICON ":/icon/kylin-tool-box-null.svg" #define SETTING_ICON ":/icon/application-menu.svg" #define SHORTCUT_TRAY_ICON ":/icon/ukui-zs-kernel-version-symbolic.svg" using namespace Sidebar; SidebarMain::SidebarMain(QObject *parent) : QObject(parent) { createSystray(); startSidebar(); } SidebarMain::~SidebarMain() { //if (m_systemTrayMenu) { // delete m_systemTrayMenu; // m_systemTrayMenu = nullptr; //} if (m_popupPC) { delete m_popupPC; m_popupPC = nullptr; } } void SidebarMain::requestWidgetActive(const QString &id, bool showReturnButton) { if (m_shortcutsWindow) { bool same = (id == m_shortcutsWindow->currentId()); if (m_shortcutsWindow->requestMenuWidget(id, showReturnButton)) { requestShortcut(same ? SidebarMain::Active : SidebarMain::Show); } } } void SidebarMain::initPublicObjects() { GlobalSettings::globalInstance(); ScreenMonitor::getInstance(); HandGestureHelper::getInstance(); SidebarWindowHelper::instance(); } void SidebarMain::loadQML() { QQmlContext *rootContext = UkuiQuick::SharedEngineView::sharedEngine()->rootContext(); rootContext->setContextProperty("isOpenGLEnv", false); rootContext->setContextProperty("dateTimeUtils", new Sidebar::DateTimeUtils(this)); rootContext->setContextProperty("appManager", AppManager::getInstance()); rootContext->setContextProperty("screenMonitor", ScreenMonitor::getInstance()); const bool isLiteMode = GlobalSettings::globalInstance()->getValue(IS_LITE_MODE).toBool(); rootContext->setContextProperty("isLiteMode", isLiteMode); initShortcut(); // 更新特效开关变量 rootContext->setContextProperty("isOpenGLEnv", !isLiteMode && (QQuickWindow::sceneGraphBackend() == "")); initSidebar(); initPopupWindow(); if (!isLiteMode) { loadTabletWindows(); connect(GlobalSettings::globalInstance(), &GlobalSettings::valueChanged, this, [this] (const QString &key) { if (key == TABLET_MODE) { loadTabletWindows(); } }); } connect(GlobalSettings::globalInstance(), &GlobalSettings::valueChanged, this, [rootContext] (const QString &key) { if (key == IS_LITE_MODE) { const bool isLiteMode = GlobalSettings::globalInstance()->getValue(key).toBool(); rootContext->setContextProperty("isLiteMode", isLiteMode); rootContext->setContextProperty("isOpenGLEnv", !isLiteMode && (QQuickWindow::sceneGraphBackend() == "")); } }); qDebug() << "loadQML isOpenGLEnv:" << (QQuickWindow::sceneGraphBackend() == "") << QQuickWindow::sceneGraphBackend(); } void SidebarMain::initSidebar() { m_notificationPC = new SidebarView; m_notificationPC->rootContext()->setContextProperty("isNotificationCenter", false); m_notificationPC->rootContext()->setContextProperty("groupModel", UkuiNotification::NotificationCenterWindow::globalGroupModel()); m_notificationPC->rootContext()->setContextProperty("sourceModel", UkuiNotification::NotificationModel::instance()); m_notificationPC->rootContext()->setContextProperty("handGestureHelper", HandGestureHelper::getInstance()); m_notificationPC->init(); //屏幕右侧响应左划动作 RightHandGestureView *handGestureView = new RightHandGestureView; handGestureView->init(); connect(UkuiNotification::NotificationModel::instance(), &UkuiNotification::NotificationModel::unreadMessageCountChanged, [this] { bool viewShowed = (m_notificationPC && m_notificationPC->isVisible()) || (m_notificationTablet && m_notificationTablet->isVisible()); if (!viewShowed) { sidebarStateChanged(false); } }); connect(m_notificationPC, &SidebarView::visibleChanged, this, [=] (bool arg) { UkuiNotification::NotificationModel::instance()->storePopupNotification(arg); if (arg) { sidebarStateChanged(); } }); } void SidebarMain::initShortcut() { m_shortcutsWindow = new ShortcutsWindow; } void SidebarMain::initNotificationTablet() { m_notificationTablet = new UkuiNotification::NotificationCenterWindow; m_notificationTablet->rootContext()->setContextProperty("isNotificationCenter", true); m_notificationTablet->init(); connect(m_notificationTablet, &UkuiNotification::NotificationCenterWindow::visibleChanged, this, [=] (bool arg) { if (arg) { sidebarStateChanged(); } }); //状态栏(响应下划动作) StatusBarView *statusBarView = new StatusBarView; statusBarView->init(); } void SidebarMain::initPopupWindow() { m_popupPC = new UkuiNotification::PopupNotificationWindow; connect(m_notificationPC, &SidebarView::visibleChanged, m_popupPC, [=](const bool isSidebarShow) { bool needDisplace = isSidebarShow && !m_notificationPC->isWindowFold() && (m_notificationPC->screen() == m_popupPC->screen()); m_popupPC->updatePopupWindowGeometry(needDisplace, m_notificationPC->width()); }); connect(m_notificationPC, &SidebarView::isWindowFoldChanged, m_popupPC, [=]() { bool needDisplace = m_notificationPC->isVisible() && !m_notificationPC->isWindowFold() && (m_notificationPC->screen() == m_popupPC->screen()); m_popupPC->updatePopupWindowGeometry(needDisplace, m_notificationPC->width()); }); m_popupPC->loadQML(); } void SidebarMain::loadTabletWindows() { bool isTabletMode = GlobalSettings::globalInstance()->getValue(TABLET_MODE).toBool(); if (isTabletMode) { if (!m_notificationTablet) { initNotificationTablet(); } if (!m_popupTablet) { initTabletPopupWindow(); } } else { if (m_popupTablet) { m_popupTablet->close(); //m_popupTablet->deleteLater(); delete m_popupTablet; m_popupTablet = nullptr; } if (m_notificationTablet) { disconnect(m_notificationTablet, nullptr, this, nullptr); m_notificationTablet->close(); //m_notificationTablet->deleteLater(); delete m_notificationTablet; m_notificationTablet = nullptr; } } } void SidebarMain::initTabletPopupWindow() { m_popupTablet = new UkuiNotification::TabletPopupView; } void SidebarMain::parseMessage(const QString &msg) { QStringList args = msg.split(" "); if (args.isEmpty()) { return; } //show if (args.first() == QStringLiteral("show")) { if (args.length() > 1) { if (args.at(1) == QStringLiteral("control")) { requestShortcut(Active); } else if (args.at(1) == QStringLiteral("notify")) { requestNotificationCenter(Active); } } } else if (args.first() == QStringLiteral("quit")) { QCoreApplication::quit(); } } void SidebarMain::registerItems() { const char uri[] = "org.ukui.sidebar.core"; SidebarWindowDefineModule::defineModules(uri, 1, 0); // 公用部分 包括自定义图标item qmlRegisterType("org.ukui.sidebar.core", 1, 0, "SettingMonitor"); //qmlRegisterType("org.ukui.sidebar.core", 1, 0, "WindowBlurHelper"); qmlRegisterUncreatableType("org.ukui.sidebar.core", 1, 0, "PluginColorRole", "Enum"); qmlRegisterUncreatableType("org.ukui.sidebar.core", 1, 0, "EventTrack", "Only attached prop."); qmlRegisterUncreatableType("org.ukui.positioner", 1, 0, "UkuiPositioner", "UkuiPositioner is an attached property"); qmlRegisterUncreatableType("org.ukui.positioner", 1, 0, "UkuiBasePositioner", "UkuiBasePositioner is an abstract type that is only available as an attached property."); qmlRegisterType("org.ukui.positioner", 1, 0, "UkuiColumn"); // 控制中心: 注册类用于在qml访问枚举变量 qmlRegisterUncreatableType("org.ukui.sidebar.shortcut.core", 1, 0, "ShortcutPlugin", "Enum"); qmlRegisterUncreatableType("org.ukui.sidebar.shortcut.core", 1, 0, "PluginState", "Enum"); qmlRegisterType("org.ukui.sidebar.shortcut.core", 1, 0, "WidgetDelegate"); // 通知中心专用部分 qmlRegisterUncreatableType("org.ukui.notification.core", 1, 0, "NotificationItem", "Enum"); //注册元类型 用于信号与槽,与qml交互 qRegisterMetaType("Color::ColorRole"); qRegisterMetaType("StatusInfo::MenuItem"); qRegisterMetaType("PluginMetaType::Action"); qRegisterMetaType("PluginMetaType::PluginType"); qRegisterMetaType("PluginMetaType::SystemMode"); qRegisterMetaType("PluginStateType::AddState"); } //注册托盘、创建托盘菜单 void SidebarMain::createSystray() { int intervalTime = 100, registerCount = 0; while (!QSystemTrayIcon::isSystemTrayAvailable() && registerCount <= 5) { ++registerCount; intervalTime *= 2; QThread::msleep(intervalTime); } m_systemTray = new QSystemTrayIcon(this); if (nullptr == m_systemTray) { qWarning() << "Allocate space trayIcon failed"; return; } m_systemTray->setIcon(QIcon::fromTheme("ukui-control-symbolic", QIcon(SHORTCUT_TRAY_ICON))); m_systemTray->setToolTip(tr("Shortcuts")); m_systemTray->setVisible(true); //m_systemTrayMenu = new QMenu; //auto open = new QAction(QObject::tr("Open"), m_systemTrayMenu); //auto openSetUp = new QAction(QIcon::fromTheme("document-page-setup-symbolic", QIcon(SETTING_ICON)), // tr("Set up notification center"), m_systemTrayMenu); //m_systemTrayMenu->addAction(open); //m_systemTrayMenu->addAction(openSetUp); //m_systemTray->setContextMenu(m_systemTrayMenu); //connect(open, &QAction::triggered, [this] { // requestSidebar(Active); //}); //connect(openSetUp, &QAction::triggered, [] { // AppManager::getInstance()->launchAppWithArguments("/usr/share/applications/ukui-control-center.desktop", {"-m", "Notice"}, "ukui-control-center"); //}); connect(m_systemTray, &QSystemTrayIcon::activated, [this] (QSystemTrayIcon::ActivationReason reason) { if (reason == QSystemTrayIcon::Trigger) { if (m_shortcutsWindow->currentId() == "") { requestShortcut(SidebarMain::Active); } else { m_shortcutsWindow->hideMenuWidget(); } } }); } void SidebarMain::startSidebar() { SidebarMain::registerItems(); initPublicObjects(); loadQML(); // 初始化侧边栏dbus接口 new Sidebar::SidebarDbusService(this); sidebarStateChanged(); } void SidebarMain::updateSystrayIcon(bool clearRedPoint) { if (!m_systemTray) { return; } if (clearRedPoint) { m_systemTray->setToolTip(tr("NotificationCenter")); m_systemTray->setIcon(QIcon::fromTheme("ukui-tool-symbolic", QIcon(TRAY_ICON))); } else { m_systemTray->setToolTip(tr("%1 Notifications").arg(UkuiNotification::NotificationCenterWindow::globalGroupModel()->rowCount(QModelIndex()))); m_systemTray->setIcon(QIcon::fromTheme("ukui-tool-box-null-symbolic", QIcon(TRAY_NULL_ICON))); } } void SidebarMain::sidebarStateChanged(bool clearMsg) { QVariantMap data; if (clearMsg) { data.insert("unreadMsg", 0); } else { data.insert("unreadMsg", UkuiNotification::NotificationModel::instance()->getUnreadMessageCount()); } Q_EMIT stateChange("sidebar", data); } void SidebarMain::requestSidebar(SidebarMain::Request request) { if (!m_notificationPC) { return; } switch (request) { case Active: { m_notificationPC->activeWindow(!m_notificationPC->isVisible()); break; } case Show: { m_notificationPC->activeWindow(true); break; } case Hide: { m_notificationPC->activeWindow(false); break; } case DirectlyHide: { m_notificationPC->setWindowVisible(false); break; } default: break; } } void SidebarMain::requestNotificationCenter(SidebarMain::Request request) { if (!m_notificationTablet) { return; } switch (request) { case Active: { m_notificationTablet->activeNotificationCenter(!m_notificationTablet->isVisible()); break; } case Show: { m_notificationTablet->activeNotificationCenter(true); break; } case Hide: { m_notificationTablet->activeNotificationCenter(false); break; } default: break; } } void SidebarMain::requestShortcut(SidebarMain::Request request) { if (!m_shortcutsWindow) { return; } switch (request) { case Active: { m_shortcutsWindow->activeShortcutsWindow(!m_shortcutsWindow->isVisible()); break; } case Show: { m_shortcutsWindow->activeShortcutsWindow(true); break; } case Hide: { m_shortcutsWindow->activeShortcutsWindow(false); break; } default: break; } } ukui-sidebar/src/sidebar-main.h0000664000175000017500000000536415167606206015400 0ustar fengfeng/* * 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_MAIN_H #define UKUI_SIDEBAR_SIDEBAR_MAIN_H #include class QMenu; class QAction; class QSystemTrayIcon; class ShortcutsWindow; namespace Sidebar { class SidebarView; class SidebarDbusService; } namespace UkuiNotification { class NotificationCenterWindow; class PopupNotificationWindow; class TabletPopupView; } class SidebarMain : public QObject { Q_OBJECT public: enum Request { Active, Show, Hide, DirectlyHide }; explicit SidebarMain(QObject *parent = nullptr); ~SidebarMain() override; void requestWidgetActive(const QString &id, bool showReturnButton); public Q_SLOTS: void parseMessage(const QString &msg); void requestSidebar(SidebarMain::Request request); void requestShortcut(SidebarMain::Request request); void requestNotificationCenter(SidebarMain::Request request); Q_SIGNALS: void stateChange(const QString &module, const QVariantMap &data); private Q_SLOTS: void loadTabletWindows(); private: void startSidebar(); static void registerItems(); inline void initPublicObjects(); void loadQML(); //系统托盘 设置menu界面、添加动作 和 创建systray实例 void createSystray(); void updateSystrayIcon(bool clearRedPoint = true); void sidebarStateChanged(bool clearMsg = true); void initSidebar(); void initShortcut(); void initNotificationTablet(); void initPopupWindow(); void initTabletPopupWindow(); private: // 侧边栏-控制中心 ShortcutsWindow *m_shortcutsWindow {nullptr}; // 侧边栏-PC通知中心 Sidebar::SidebarView *m_notificationPC {nullptr}; // 侧边栏-平板模式通知中心 UkuiNotification::NotificationCenterWindow *m_notificationTablet {nullptr}; UkuiNotification::PopupNotificationWindow *m_popupPC {nullptr}; UkuiNotification::TabletPopupView *m_popupTablet {nullptr}; // 系统托盘 QSystemTrayIcon* m_systemTray {nullptr}; //QMenu *m_systemTrayMenu {nullptr}; }; #endif // UKUI_SIDEBAR_SIDEBAR_MAIN_H ukui-sidebar/src/log-utils.cpp0000664000175000017500000001057115167643374015322 0ustar fengfeng/* * Copyright (C) 2024, 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 "log-utils.h" #include #include #include #include #include #define LOG_FILE_COUNT 2 #define MAX_LOG_FILE_SIZE 4194304 #define MAX_LOG_CHECK_INTERVAL 43200000 quint64 LogUtils::m_startUpTime = 0; int LogUtils::m_logFileId = -1; QString LogUtils::m_logFileName; QString LogUtils::m_currentLogFile; static QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.log/ukui-sidebar/"; void LogUtils::messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) { checkLogFile(); QByteArray localMsg = msg.toLocal8Bit(); QByteArray currentTime = QTime::currentTime().toString().toLocal8Bit(); const char *file = context.file ? context.file : ""; const char *function = context.function ? context.function : ""; FILE *log_file = fopen(m_currentLogFile.toLocal8Bit().constData(), "a+"); switch (type) { case QtDebugMsg: if (!log_file) { break; } fprintf(log_file, "Debug: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); break; case QtInfoMsg: fprintf(log_file? log_file: stdout, "Info: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); break; case QtWarningMsg: fprintf(log_file? log_file: stderr, "Warning: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); break; case QtCriticalMsg: fprintf(log_file? log_file: stderr, "Critical: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); break; case QtFatalMsg: fprintf(log_file? log_file: stderr, "Fatal: %s: %s (%s:%u, %s)\n", currentTime.constData(), localMsg.constData(), file, context.line, function); break; } if (log_file) { fclose(log_file); } } void LogUtils::initLogFile(const QString &fileName) { QDir dir; if (!dir.exists(logFilePath)) { if (!dir.mkpath(logFilePath)) { qWarning() << "Unable to create" << logFilePath; return; } } m_logFileName = logFilePath + fileName + "-%1.log"; for (int i = 0; i < LOG_FILE_COUNT; ++i) { m_currentLogFile = m_logFileName.arg(i); if (QFile::exists(m_currentLogFile)) { if (checkFileSize(m_currentLogFile)) { m_logFileId = i; break; } } else { QFile file(m_currentLogFile); file.open(QIODevice::WriteOnly); file.close(); } } if (m_logFileId < 0) { m_logFileId = 0; m_currentLogFile = m_logFileName.arg(m_logFileId); clearFile(m_currentLogFile); } qInfo() << "Current log file:" << m_currentLogFile; } void LogUtils::checkLogFile() { quint64 logTime = QDateTime::currentDateTime().toMSecsSinceEpoch(); quint64 spacing = std::max(logTime, m_startUpTime) - std::min(logTime, m_startUpTime); if (spacing <= MAX_LOG_CHECK_INTERVAL || checkFileSize(m_currentLogFile)) { return; } m_logFileId = ((m_logFileId + 1) % LOG_FILE_COUNT); m_currentLogFile = m_logFileName.arg(m_logFileId); if (!checkFileSize(m_currentLogFile)) { clearFile(m_currentLogFile); } } bool LogUtils::checkFileSize(const QString &fileName) { return QFile(fileName).size() < MAX_LOG_FILE_SIZE; } void LogUtils::clearFile(const QString &fileName) { QFile file(fileName); file.open(QIODevice::WriteOnly); file.write(""); file.flush(); file.close(); } ukui-sidebar/translations/0000775000175000017500000000000015167643374014625 5ustar fengfengukui-sidebar/translations/ukui-sidebar_ky.ts0000664000175000017500000001356315167606206020265 0ustar fengfeng CollapsedList %1 more notifications داعى ٪1 ۇقتۇرۇۇ جاسالات EditButtonView enter editing mode تۅپتۅش ۅرنۅگۉنۅ كىرۉۉ There are currently no quick control options available, please %1 to add گەزەكتە تەز تىزگىندۅۅ تاندالمالارى جوق، ٪1 نى قوشۇڭ ExcludedPanel No add components تەتىكتەر قوشۇلبادى NotificationCenterHeader Notification Center ۇقتۇرۇۇ بوربورۇ No new notifications جاڭى ۇقتۇرۇۇ جوق Clear All مايەكتەشۉۉ جازما دارەگىن تازالوو NotificationCenterLabel Notification Center ۇقتۇرۇۇ بوربورۇ Clear all بَارْدِي تَزَالُو Notification setting إسْكِرْتُوي پَارَامِتْرَلِيَرِي NotificationCenterPC No new notifications received جاڭى ۇقتۇرۇۇ تاپشۇرۇۋالمىدى NotificationList %1 more notifications داعى ٪1 ۇقتۇرۇۇ جاسالات Show less بۉكتۅلۉۉ Close all بَارْدِي جَابُو PopupNotificationItem Close جابۇۇ one notification from %1 ٪1 نان بىر ۇقتۇرۇۇ PopupView %1 more notifications داعى ٪1 ۇقتۇرۇۇ جاسالات QObject Administrator باشقارعۇۇچۇ Standard user ۅلچۅمدۉۉ ىشتەتۉۉچۉ Show the current state of the sidebar. ۇقۇق ،امال جاعىنداقى توسمولور. ازىرقى ابالىن كۅرسۅتۉۉ There are two options, 'notify' and 'control'. notify-&gt; ۇقتۇرۇۇ بوربورۇن اچتى، control-&gt; تىزگىندۅۅ بوربورۇن اچتى Quit sidebar. ۇقۇق ،امال جاعىنداقى توسمولوردون. جانىپ ukui-sidebar ۇقۇق ،امال تاراپ توسمولور ShortcuPanel Shortcuts تەز جالعانما Added components قوشۇلعان تەتىكتەر Done تۉگۅدۉ Click to enter editing mode رِيدَاكْسِيَا رِيجِيمِينِ كِيرُو Click to exit editing mode رِيدَاكْسِيَا رِيجِيمِينِن شَغُو Sidebar::DateTimeUtils Now ازىر Yesterday كەچە SidebarMain Shortcuts تەز جالعانما NotificationCenter ۇقتۇرۇۇ بوربورۇ %1 Notifications بىر پارچا ۇقتۇرۇۇ UkuiShortcut::PowerButton Power بىيلىك ukui-sidebar/translations/ukui-sidebar_ar.ts0000664000175000017500000000747415167606206020250 0ustar fengfeng CollapsedList %1 more notifications ٪1 المزيد من الإشعارات NotificationCenterHeader Notification Center مركز الإشعارات No new notifications لا توجد إشعارات جديدة Clear All مسح الكل NotificationCenterLabel Notification Center مركز الإشعارات NotificationCenterPC No new notifications received لم يتم تلقي إشعارات جديدة NotificationList %1 more notifications ٪1 المزيد من الإشعارات Show less عرض أقل PopupNotificationItem Close غلق PopupView %1 more notifications ٪1 المزيد من الإشعارات QObject Administrator مدير Standard user المستخدم القياسي Show the current state of the sidebar. إظهار الحالة الحالية للشريط الجانبي. There are two options, 'notify' and 'control'. هناك خياران ، "إشعار" و "تحكم". Quit sidebar. قم بإنهاء الشريط الجانبي. ukui-sidebar الشريط الجانبي ShortcuPanel Shortcuts اختصارات Sidebar::DateTimeUtils Now الآن Yesterday أمس SidebarMain Shortcuts اختصارات NotificationCenter مركز الإشعارات %1 Notifications ٪1 الإشعارات UkuiShortcut::PowerButton Power قوة ukui-sidebar/translations/ukui-sidebar_zh_Hant.ts0000664000175000017500000001204615167606206021230 0ustar fengfeng CollapsedList %1 more notifications 還有%1則通知 EditButtonView enter editing mode 進入編輯模式 There are currently no quick control options available, please %1 to add 暫無快捷控制項,請%1添加 ExcludedPanel No add components 未添加元件 NotificationCenterHeader Notification Center 通知中心 No new notifications 沒有新通知 Clear All 清空 NotificationCenterLabel Notification Center 通知中心 Clear all 全部清空 Notification setting 通知設置 NotificationCenterPC No new notifications received 沒有收到新通知 NotificationList %1 more notifications 還有%1則通知 Show less 摺疊 Close all 全部關閉 PopupNotificationItem Close 關閉 one notification from %1 來自%1 的1條通知 PopupView %1 more notifications 還有%1則通知 QObject Administrator 管理員 Standard user 普通使用者 Show the current state of the sidebar. 顯示側邊欄現在的狀態。 There are two options, 'notify' and 'control'. notify -&gt;打開通知中心,control -&gt; 打開控制中心。 Quit sidebar. 退出側邊欄。 ukui-sidebar 側邊欄 ShortcuPanel Shortcuts 快捷操作 Added components 已添加元件 Done 完成 Click to enter editing mode 點擊進入編輯模式 Click to exit editing mode 點擊退出編輯模式 Sidebar::DateTimeUtils Now 現在 Yesterday 昨天 SidebarMain Shortcuts 快捷操作 NotificationCenter 通知中心 %1 Notifications %1 條通知 UkuiShortcut::PowerButton Power 電源 ukui-sidebar/translations/ukui-sidebar_vi.ts0000664000175000017500000000726215167606206020257 0ustar fengfeng CollapsedList %1 more notifications %1 thông báo khác NotificationCenterHeader Notification Center Trung tâm thông báo No new notifications Không có thông báo mới Clear All Xóa tất cả NotificationCenterLabel Notification Center Trung tâm thông báo NotificationCenterPC No new notifications received Không nhận được thông báo mới NotificationList %1 more notifications %1 thông báo khác Show less Hiển thị ít hơn PopupNotificationItem Close Đóng PopupView %1 more notifications %1 thông báo khác QObject Administrator Quản trị viên Standard user Người dùng tiêu chuẩn Show the current state of the sidebar. Hiển thị trạng thái hiện tại của thanh bên. There are two options, 'notify' and 'control'. Có hai tùy chọn, 'thông báo' và 'kiểm soát'. Quit sidebar. Thoát thanh bên. ukui-sidebar Thanh bên ShortcuPanel Shortcuts Phím tắt Sidebar::DateTimeUtils Now Bây giờ Yesterday Hôm qua SidebarMain Shortcuts Phím tắt NotificationCenter Trung tâm thông báo %1 Notifications %1 Thông báo UkuiShortcut::PowerButton Power Sức mạnh ukui-sidebar/translations/ukui-sidebar_fr.ts0000664000175000017500000000740715167606206020251 0ustar fengfeng CollapsedList %1 more notifications Il existe également une notification %1 NotificationCenterHeader Notification Center Centre de notifications No new notifications Pas de nouvelles notifications Clear All vide NotificationCenterLabel Notification Center Centre de notifications NotificationCenterPC No new notifications received Aucune nouvelle notification n’a été reçue NotificationList %1 more notifications Il existe également une notification %1 Show less plier PopupNotificationItem Close Arrêter PopupView %1 more notifications Il existe également une notification %1 QObject Administrator administrateur Standard user Utilisateurs réguliers Show the current state of the sidebar. Affiche l’état actuel de la barre latérale. There are two options, 'notify' and 'control'. Notifier -&gt; ouvre le centre de notifications, et Contrôle -&gt; ouvre le centre de contrôle. Quit sidebar. Quittez la barre latérale. ukui-sidebar Barre latérale ShortcuPanel Shortcuts Actions rapides Sidebar::DateTimeUtils Now Tout de suite Yesterday Hier SidebarMain Shortcuts Actions rapides NotificationCenter Centre de notifications %1 Notifications %1 notifications UkuiShortcut::PowerButton Power alimentation ukui-sidebar/translations/ukui-sidebar_zh_HK.ts0000664000175000017500000001101315167606206020631 0ustar fengfeng CollapsedList %1 more notifications 还有%1个通知 NotificationCenterHeader Notification Center 通知中心 No new notifications 没有新通知 Clear All 清空聊天記錄 NotificationCenterLabel Notification Center 通知中心 Notification setting 通知設置 Clear all 全部清空 NotificationCenterPC No new notifications received 未收到新通知 NotificationList %1 more notifications 还有%1个通知 Show less 折疊 Close all 全部關閉 PopupNotificationItem Close 關閉 PopupView %1 more notifications 还有%1个通知 QObject Administrator 管理員 Standard user 普通用戶 Show the current state of the sidebar. 显示侧边栏的当前状态。 There are two options, 'notify' and 'control'. 有两个选项,“通知”和“控制”。 Quit sidebar. 退出侧边栏。 ukui-sidebar 側邊欄 ShortcuPanel Shortcuts 快捷方式 Added components 已添加組件 Done 完成 Click to enter editing mode 點擊進入編輯模式 Click to exit editing mode 點擊退出編輯模式 Sidebar::DateTimeUtils Now 现在 Yesterday 昨天 SidebarMain Shortcuts 快捷方式 NotificationCenter 通知中心 %1 Notifications %1 條通知 UkuiShortcut::PowerButton Power 電源 ExcludedPanel No add components 未添加組件 ukui-sidebar/translations/ukui-sidebar_kk.ts0000664000175000017500000001341215167606206020240 0ustar fengfeng CollapsedList %1 more notifications جانە ٪1 ۇقتٸرۋ قىلىندى EditButtonView enter editing mode تالداۋجاساۋ نۇسقاسنا كىرۋ There are currently no quick control options available, please %1 to add كەزەكتە تەز تٸزگٸندەۋ تالدانبالارٸ جوق، ٪1 نى قوس ExcludedPanel No add components دەتالدار قوسىلمادى NotificationCenterHeader Notification Center ۇقتٸرۋ ورتالىعى No new notifications جاڭا ۇقتٸرۋ جوق Clear All اڭگىمەلەسۋ قاتەسىن تازالاۋ NotificationCenterLabel Notification Center ۇقتٸرۋ ورتالىعى Clear all بارلِغِن تَزَالَو Notification setting خَبَرْلَامَالَارْدِي بَابْتَاو NotificationCenterPC No new notifications received جاڭا ۇقتٸرۋ الىنبادى NotificationList %1 more notifications جانە ٪1 ۇقتٸرۋ قىلىندى Show less قوسىلماق Close all بارلِغِن جَابُ PopupNotificationItem Close تاقاۋ one notification from %1 ٪1 دان بٸر ۇقتٸرۋ PopupView %1 more notifications جانە ٪1 ۇقتٸرۋ قىلىندى QObject Administrator باسقارۋشٸسٸ Standard user ولشەمدى پايدالانۋشٸ Show the current state of the sidebar. جان جاقتاداعٸ سۇيەنىش قازىرعى كۇيىن كورسەتۋ There are two options, 'notify' and 'control'. notify-&gt; ۇقتٸرۋ ورتالىقتى اشتٸ، control-&gt; مەڭگەرۋ ورتالىقتى اشتٸ Quit sidebar. جان جاقتاداعٸ سۇيەنىشتەن شەگنىپ ukui-sidebar جان جاق سۇيەنىش ShortcuPanel Shortcuts تەز قولدانبا Added components قوسىلعان دەتالدار Done توگەدى Click to enter editing mode رِيدَاكْسِيَا رِيجِيمِينِي كِيرِينِز Click to exit editing mode رِيدَاكْسِيَا رِيجِيمِينِن شَغُو Sidebar::DateTimeUtils Now قازىر Yesterday كەشە SidebarMain Shortcuts تەز قولدانبا NotificationCenter ۇقتٸرۋ ورتالىعى %1 Notifications بٸر پارشا ۇقتٸرۋ UkuiShortcut::PowerButton Power قۋات ukui-sidebar/translations/ukui-sidebar_es.ts0000664000175000017500000000735015167606206020246 0ustar fengfeng CollapsedList %1 more notifications También hay una notificación %1 NotificationCenterHeader Notification Center Centro de notificaciones No new notifications No hay nuevas notificaciones Clear All vacío NotificationCenterLabel Notification Center Centro de notificaciones NotificationCenterPC No new notifications received No se han recibido nuevas notificaciones NotificationList %1 more notifications También hay una notificación %1 Show less doblar PopupNotificationItem Close Apaga PopupView %1 more notifications También hay una notificación %1 QObject Administrator administrador Standard user Usuarios habituales Show the current state of the sidebar. Muestra el estado actual de la barra lateral. There are two options, 'notify' and 'control'. Notificar -&gt; abre el Centro de notificaciones y Control -&gt; abre el Centro de control. Quit sidebar. Sal de la barra lateral. ukui-sidebar Barra lateral ShortcuPanel Shortcuts Acciones rápidas Sidebar::DateTimeUtils Now Ahora mismo Yesterday Ayer SidebarMain Shortcuts Acciones rápidas NotificationCenter Centro de notificaciones %1 Notifications %1 Notificaciones UkuiShortcut::PowerButton Power fuente de alimentación ukui-sidebar/translations/ukui-sidebar_bo_CN.ts0000664000175000017500000001514215167606206020615 0ustar fengfeng CollapsedList %1 more notifications ད་དུང་%1གི་བརྡ་སྦྱོར་ཡོད། EditButtonView enter editing mode རྩོམ་སྒྲིག་རྣམ་པར་ཞུགས། There are currently no quick control options available, please %1 to add གནས་སྐབས་སུ་མྱུར་ཐབས་ཚོད་འཛིན་གྱི་ཚན་མེད།%1སྣོན་རོགས། ExcludedPanel No add components སྒྲིག་ལྷུ་སྣོན་མེད། NotificationCenterHeader Notification Center ལྟེ་གནས་ལ་བརྡ་ཐོ་གཏོང No new notifications བརྡ་ཐོ་གསར་པ་མེད། Clear All གཙང་སེལ། NotificationCenterLabel Notification Center ལྟེ་གནས་ལ་བརྡ་ཐོ་གཏོང Clear all ཚང་མ་སྟོང་པ་རེད། Notification setting བརྡ་ཐོ་བཏང་ནས་འཛུགས་དགོས། NotificationCenterPC No new notifications received བརྡ་སྦྱོར་གསར་བ་མེད། NotificationList %1 more notifications ད་དུང་%1གི་བརྡ་སྦྱོར་ཡོད། Show less ལྟེབ་བརྩེགས Close all ཚང་མ་སྒོ་རྒྱག་དགོས། PopupNotificationItem Close ཁ་རྒྱག one notification from %1 %1ལས་ཐོན་པའི་བརྡ་སྦྱོར་ཞིག PopupView %1 more notifications ད་དུང་%1གི་བརྡ་སྦྱོར་ཡོད། QObject Administrator དོ་དམ་པ། Standard user སྤྱོད་མཁན་ཕལ་བ། Show the current state of the sidebar. འགྲམ་ངོས་སྡེའི་ད་ལྟའི་རྣམ་པ་འཆར་བ。 There are two options, 'notify' and 'control'. notify -&gt;བརྡ་སྦྱོར་ལྟེ་གནས་ཁ་ཕྱེcontrol -&gt;ཚོད་འཛིན་ལྟེ་གནས་ཁ་ཕྱེ。 Quit sidebar. འགྲམ་ངོས་སྡེ་ལས་ཕྱིར་འབུད།。 ukui-sidebar ལོགས་ངོས་ཀྱི་ར་བ། ShortcuPanel Shortcuts མྱུར་ཐབས་བཀོལ་སྤྱོད། Added components སྒྲིག་ལྷུ་སྣོན་ཟིན། Done ལེགས་གྲུབ། Click to enter editing mode རྩོམ་སྒྲིག་གི་དཔེ་དབྱིབས་ལ་འཇབ་རྒོལ་བྱེད་དགོས། Click to exit editing mode རྩོམ་སྒྲིག་བྱེད་སྟངས་ལས་ཕྱིར་འབུད་པ། Sidebar::DateTimeUtils Now ད་ལྟ་ Yesterday ཁ་སང་། SidebarMain Shortcuts མྱུར་ཐབས་བཀོལ་སྤྱོད། NotificationCenter བརྡ་སྦྱོར་ལྟེ་གནས། %1 Notifications %1གི་བརྡ་སྦྱོར། UkuiShortcut::PowerButton Power སྟོབས་ཤུགས། ukui-sidebar/translations/ukui-sidebar_zh_CN.ts0000664000175000017500000001250215167643374020642 0ustar fengfeng CollapsedList %1 more notifications 还有%1则通知 EditButtonView enter editing mode 进入编辑模式 There are currently no quick control options available, please %1 to add 暂无快捷控制项,请%1添加 ExcludedPanel No add components 未添加组件 NotificationCenterHeader Notification Center 通知中心 No new notifications 没有新通知 Clear All 清空 NotificationCenterLabel Notification Center 通知中心 Clear all 全部清空 Notification setting 通知设置 NotificationCenterPC No new notifications received 没有收到新通知 NotificationList %1 more notifications 还有%1则通知 Show less 折叠 Close all 全部关闭 PopupNotificationItem Close 关闭 one notification from %1 来自%1的1条通知 PopupView %1 more notifications 还有%1则通知 QObject Administrator 管理员 Standard user 普通用户 Show the current state of the sidebar. 显示侧边栏现在的状态。 There are two options, 'notify' and 'control'. notify -&gt;打开通知中心,control -&gt; 打开控制中心。 Quit sidebar. 退出侧边栏。 ukui-sidebar 侧边栏 ShortcuPanel Shortcuts 快捷操作 Added components 已添加组件 Done 完成 Click to enter editing mode 点击进入编辑模式 Click to exit editing mode 点击退出编辑模式 Open settings 打开设置 Shortcuts back to Shortcuts 返回快捷面板 Sidebar::DateTimeUtils Now 现在 Yesterday 昨天 SidebarMain Shortcuts 快捷操作 NotificationCenter 通知中心 %1 Notifications %1 条通知 UkuiShortcut::PowerButton Power 电源 ukui-sidebar/translations/ukui-sidebar_mn.ts0000664000175000017500000001525415167606206020253 0ustar fengfeng CollapsedList %1 more notifications ᠪᠠᠰᠠ %1 ᠮᠡᠳᠡᠭᠳᠡᠯ ᠪᠤᠢ EditButtonView enter editing mode ᠨᠠᠢᠷᠠᠭᠤᠯᠬᠤ ᠮᠤᠳ᠋ᠸᠯ ᠳ᠋ᠤ᠌ ᠣᠷᠣᠬᠤ There are currently no quick control options available, please %1 to add ᠳᠦᠳᠡ ᠡᠵᠡᠮᠳᠡᠬᠦ ᠳᠦᠷᠦᠯ ᠪᠠᠢᠬᠤ ᠥᠬᠡᠢ᠂ %1 ᠢ᠋\ ᠵᠢ ᠨᠡᠮᠡᠬᠡᠷᠡᠢ ExcludedPanel No add components ᠳᠤᠨᠤᠭᠯᠠᠯ ᠤ᠋ᠨ ᠪᠦᠯᠦᠭ ᠨᠡᠮᠡᠬᠡ ᠥᠬᠡᠢ NotificationCenterHeader Notification Center ᠮᠡᠳᠡᠭᠳᠡᠯ ᠤ᠋ᠨ ᠳᠦᠪ No new notifications ᠰᠢᠨ᠎ᠡ ᠮᠡᠳᠡᠭᠳᠡᠯ ᠪᠠᠢᠬᠤ ᠥᠬᠡᠢ Clear All ᠬᠣᠭᠣᠰᠣᠯᠠᠬᠤ NotificationCenterLabel Notification Center ᠮᠡᠳᠡᠭᠳᠡᠯ ᠤ᠋ᠨ ᠳᠦᠪ Clear all ᠪᠦᠬᠦᠨ ᠢ ᠬᠣᠭᠣᠰᠣᠨ ᠴᠡᠪᠡᠷᠯᠡᠨ᠎ᠡ ᠃ Notification setting ᠮᠡᠳᠡᠭᠳᠡᠯ ᠲᠣᠬᠢᠷᠠᠭᠤᠯᠬᠤ ᠬᠡᠷᠡᠭᠲᠡᠶ᠃ NotificationCenterPC No new notifications received ᠰᠢᠨ᠎ᠡ ᠮᠡᠳᠡᠭᠳᠡᠯ ᠬᠤᠷᠢᠶᠠᠵᠤ ᠣᠯᠤᠭᠰᠠᠨ ᠥᠬᠡᠢ NotificationList %1 more notifications ᠪᠠᠰᠠ %1 ᠮᠡᠳᠡᠭᠳᠡᠯ ᠪᠤᠢ Show less ᠨᠤᠭᠤᠯᠠᠬᠤ Close all ᠪᠦᠬᠦᠨ ᠢ ᠬᠠᠭᠠᠪᠠ ᠃ PopupNotificationItem Close ᠬᠠᠭᠠᠬᠤ one notification from %1 %1 ᠡᠴᠡ ᠢᠷᠡᠯᠳᠡᠢ1 ᠮᠡᠳᠡᠭᠳᠡᠯ PopupView %1 more notifications ᠪᠠᠰᠠ %1 ᠮᠡᠳᠡᠭᠳᠡᠯ ᠪᠤᠢ QObject Administrator ᠬᠠᠮᠢᠶᠠᠷᠤᠭᠴᠢ Standard user ᠡᠩ ᠤ᠋ᠨ ᠬᠡᠷᠡᠭᠯᠡᠭᠴᠢ Show the current state of the sidebar. ᠬᠠᠵᠠᠭᠤ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠤ᠋ᠨ ᠣᠳᠣᠬᠠᠨ ᠤ᠋ ᠪᠠᠢᠳᠠᠯ ᠢ᠋ ᠢᠯᠡᠷᠡᠬᠦᠯᠦᠨ᠎ᠡ᠃ There are two options, 'notify' and 'control'. notify -&gt; ᠮᠡᠳᠡᠭᠳᠡᠯ ᠤ᠋ᠨ ᠳᠦᠪ ᠢ᠋ ᠨᠡᠬᠡᠬᠡᠵᠤ᠂control -&gt; ᠡᠵᠡᠮᠳᠡᠯ ᠤ᠋ᠨ ᠳᠦᠪ ᠢ᠋ ᠨᠡᠬᠡᠬᠡᠨ᠎ᠡ᠃ Quit sidebar. ᠬᠠᠵᠠᠭᠤ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ᠡᠴᠡ ᠪᠤᠴᠠᠵᠤ ᠭᠠᠷᠤᠨ᠎ᠠ᠃ ukui-sidebar ᠬᠠᠵᠠᠭᠤ ᠵᠢᠨ ᠪᠠᠭᠠᠷ ShortcuPanel Shortcuts ᠲᠦᠳᠡ ᠠᠵᠢᠯᠯᠠᠬᠤᠢ Added components ᠲᠣᠨᠣᠭᠯᠠᠯ ᠤ᠋ᠨ ᠪᠦᠯᠦᠭ ᠢ᠋ ᠨᠢᠬᠡᠨᠳᠡ ᠨᠡᠮᠡᠪᠡ Done ᠪᠡᠶᠡᠯᠡᠭᠦᠯᠬᠦ Click to enter editing mode ᠨᠠᠢ᠌ᠷᠠᠭᠤᠯᠬᠤ ᠵᠠᠭᠪᠤᠷ ᠲᠤ ᠣᠷᠣᠬᠤ ᠶᠢ ᠳᠠᠭᠤᠳᠠᠨ᠎ᠠ ᠃ Click to exit editing mode ᠨᠠᠢ᠌ᠷᠠᠭᠤᠯᠤᠭᠴᠢ ᠶᠢᠨ ᠵᠠᠭᠪᠤᠷ ᠢ ᠳᠠᠷᠤᠵᠤ ᠭᠠᠷᠭᠠᠨ᠎ᠠ ᠃ Sidebar::DateTimeUtils Now ᠤᠳᠤ ᠪᠡᠷ Yesterday ᠦᠴᠦᠬᠡᠳᠦᠷ SidebarMain Shortcuts ᠲᠦᠳᠡ ᠠᠵᠢᠯᠯᠠᠬᠤᠢ NotificationCenter ᠮᠡᠳᠡᠭᠳᠡᠯ ᠤ᠋ᠨ ᠳᠦᠪ %1 Notifications %1 ᠵᠤᠷᠪᠤᠰ ᠮᠡᠳᠡᠭᠳᠡᠯ UkuiShortcut::PowerButton Power ᠴᠠᠬᠢᠯᠭᠠᠨ ᠡᠭᠦᠰᠭᠡᠭᠴᠢ ukui-sidebar/translations/ukui-sidebar_de.ts0000664000175000017500000000737415167606206020235 0ustar fengfeng CollapsedList %1 more notifications Es gibt auch eine %1-Benachrichtigung NotificationCenterHeader Notification Center Mitteilungszentrale No new notifications Keine neuen Benachrichtigungen Clear All leer NotificationCenterLabel Notification Center Mitteilungszentrale NotificationCenterPC No new notifications received Es sind keine neuen Benachrichtigungen eingegangen NotificationList %1 more notifications Es gibt auch eine %1-Benachrichtigung Show less falten PopupNotificationItem Close Herunterfahren PopupView %1 more notifications Es gibt auch eine %1-Benachrichtigung QObject Administrator Standard user Regelmäßige Benutzer Show the current state of the sidebar. Zeigt den aktuellen Status der Seitenleiste an. There are two options, 'notify' and 'control'. Benachrichtigen -&gt; öffnet die Mitteilungszentrale und Strg -&gt; öffnet das Kontrollzentrum. Quit sidebar. Verlassen Sie die Seitenleiste. ukui-sidebar Seitenleiste ShortcuPanel Shortcuts Schnelle Aktionen Sidebar::DateTimeUtils Now Jetzt gerade Yesterday Gestern SidebarMain Shortcuts Schnelle Aktionen NotificationCenter Mitteilungszentrale %1 Notifications %1 Benachrichtigungen UkuiShortcut::PowerButton Power Stromversorgung ukui-sidebar/translations/ukui-sidebar_ug.ts0000664000175000017500000001354515167606206020255 0ustar fengfeng CollapsedList %1 more notifications يەنە %1 ئۇقتۇرۇش قىلىنىدۇ EditButtonView enter editing mode تەھرىرلەش ئەندىزىسىگە كىرىش There are currently no quick control options available, please %1 to add نۆۋەتتە تېز تىزگىنلەش تاللانمىلىرى يوق، %1 نى قوشۇڭ ExcludedPanel No add components دېتاللار قوشۇلمىدى NotificationCenterHeader Notification Center ئۇقتۇرۇش مەركىزى No new notifications يېڭى ئۇقتۇرۇش يوق Clear All پاراڭلىشىش خاتىرىسىنى تازىلاش NotificationCenterLabel Notification Center ئۇقتۇرۇش مەركىزى Clear all ھەممىسى بىكار بولۇش Notification setting ئۇقتۇرۇش تەسىس قىلىش NotificationCenterPC No new notifications received يېڭى ئۇقتۇرۇش تاپشۇرۇۋالمىدى NotificationList %1 more notifications يەنە %1 ئۇقتۇرۇش قىلىنىدۇ Show less قاتلىماق Close all ھەممىسى تاقالدى PopupNotificationItem Close ياپ one notification from %1 %1 دىن بىر ئۇقتۇرۇش PopupView %1 more notifications يەنە %1 ئۇقتۇرۇش قىلىنىدۇ QObject Administrator باشقۇرغۇچى Standard user ئۆلچەملىك ئىشلەتكۈچى Show the current state of the sidebar. يان تەرەپتىكى رىشاتكىنىڭ ھازىرقى ھالىتىنى كۆرسىتىش There are two options, 'notify' and 'control'. notify-&gt; ئۇقتۇرۇش مەركىزىنى ئاچتى، control-&gt; كونترول مەركىزىنى ئاچتى Quit sidebar. يان تەرەپتىكى رىشاتكىدىن چېكىنىپ ukui-sidebar يان تەرەپ رىشاتكىسى ShortcuPanel Shortcuts تېزلەتمىلەر Added components قوشۇلغان دېتاللار Done تۈگىدى Click to enter editing mode تەھرىرلەش ئەندىزىسىگە كىرمەك Click to exit editing mode تەھرىرلەش ئەندىزىسىدىن چېكىنىپ چىقماق Sidebar::DateTimeUtils Now ھازىر Yesterday SidebarMain Shortcuts تېزلەتمىلەر NotificationCenter ئۇقتۇرۇش مەركىزى %1 Notifications بىر پارچە ئۇقتۇرۇش UkuiShortcut::PowerButton Power توك مەنبەسىنى باشقۇرۇش ukui-sidebar/translations/ukui-sidebar_ug_CN.ts0000664000175000017500000001005015167606206020621 0ustar fengfeng CollapsedList %1 more notifications يەنە ٪1 ئۇقتۇرۇش قىلىنىدۇ NotificationCenterHeader Notification Center ئۇقتۇرۇش مەركىزى No new notifications يېڭى ئۇقتۇرۇش يوق Clear All بىكار قىلىش NotificationCenterLabel Notification Center ئۇقتۇرۇش مەركىزى NotificationCenterPC No new notifications received يېڭى ئۇقتۇرۇش تاپشۇرۇۋالمىدى NotificationList %1 more notifications يەنە ٪1 ئۇقتۇرۇش قىلىنىدۇ Show less قاتلىماق PopupNotificationItem Close ياپ PopupView %1 more notifications يەنە ٪1 ئۇقتۇرۇش قىلىنىدۇ QObject Administrator باشقۇرغۇچى Standard user ئادەتتىكى خېرىدار Show the current state of the sidebar. يان تەرەپتىكى رىشاتكىنىڭ ھازىرقى ھالىتىنى كۆرسىتىش There are two options, 'notify' and 'control'. notify-&gt; ئۇقتۇرۇش مەركىزىنى ئاچتى، control-&gt; كونترول مەركىزىنى ئاچتى Quit sidebar. يان تەرەپتىكى رىشاتكىدىن چېكىنىپ ukui-sidebar يان تەرەپ رىشاتكىسى ShortcuPanel Shortcuts تېز مەشغۇلات قىلىش Sidebar::DateTimeUtils Now ھازىر Yesterday تۈنۈگۈن SidebarMain Shortcuts تېز مەشغۇلات قىلىش NotificationCenter ئۇقتۇرۇش مەركىزى %1 Notifications بىر پارچە ئۇقتۇرۇش UkuiShortcut::PowerButton Power توك مەنبەسى ukui-sidebar/README.md0000664000175000017500000001336515167606206013364 0ustar fengfeng# ukui-sidebar ## 简介 ukui-sidebar是ukui桌面环境中的侧边栏快捷工具,主要包括控制中心和通知中心两个部分。 ### 编译 ```shell # 使用不同发行版对应的包管理器安装编译依赖,以debian系举个栗子: # 1.0. 侧边栏目前的依赖如下(可能会有改动): pkgconf libxcb1-dev libgsettings-qt-dev qtbase5-dev qt5-qmake qtchooser qttools5-dev-tools qtdeclarative5-dev libkf5windowsystem-dev libqt5x11extras5-dev libkysdk-waylandhelper-dev libopencv-dev # 1.1. 直接使用apt下载并安装全部依赖 sudo apt install pkgconf libxcb1-dev libgsettings-qt-dev qtbase5-dev qt5-qmake qtchooser qttools5-dev-tools qtdeclarative5-dev libkf5windowsystem-dev libqt5x11extras5-dev libkysdk-waylandhelper-dev libopencv-dev # 2.0. 也可以使用mk-build-deps工具,检查并安装编译依赖,该工具包含在devscripts包中 sudo apt install devscripts # 2.1. 自动安装依赖,在源码根目录执行: sudo mk-build-deps -i # 2.2. 手动检查并安装依赖,在源码根目录执行: sudo mk-build-deps # 2.3. 查看生成的 xxx.deb包(xxx是版本号),使用dpkg -I解析deb包的编译依赖 dpkg -I ukui-sidebar-build-deps_xxx_all.deb # 3. 编译:进入源码根目录,打开终端,编译侧边栏 mkdir build; cd build; qmake ..; make; sudo make install ``` ### 控制中心 控制主要功能是提供了一组系统设置快捷键,类似手机上的下滑控制中心。快捷键按钮均基于libukui-shortcut-dev提供的插件接口实现。 ### 通知中心 通知中心可以显示用户最近的消息通知,提供了便捷的消息分组查看和删除功能。 ## 运行 ukui-sidebar作为ukui桌面环境组件,默认开机自启,且无法关闭。侧边栏有pc模式和平板模式两种显示模式,pc模式下,侧边栏可通过点击托盘图标或从屏幕右边缘左滑唤起,也可以通过快捷键 super + a 唤起。平板模式下,侧边栏分为控制中心和通知中心两部分,控制中心唤起方式和上面提到的pc模式的三种方法相同,通知中心需要从屏幕上边缘下滑唤起。 ## 快捷键,命令行和交互接口 ### 快捷键 目前侧边栏只有 super + a 一组快捷键。 ### 命令行 ```shell Options: -S, --state Show the current state of the sidebar. -s, --show