diff --git a/package/components/AboutWindow.qml b/package/components/AboutWindow.qml index 68a0425..23ce73b 100644 --- a/package/components/AboutWindow.qml +++ b/package/components/AboutWindow.qml @@ -8,13 +8,21 @@ // 深/浅主题由 isDarkMode 切换(networkview.qml 依据 DockPalette 检测任务栏深浅后传入), // 默认浅色,保证组件独立预览时与原版视觉一致 // 对外依赖:accentColor、isDarkMode,由 networkview.qml 实例化时传入,触发方式为 show()/raise()/requestActivate() +// 公共能力复用:主题色取自 WindowTheme,标题栏/圆角卡片取自 TitleBar,消除三窗口样板重复 import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Window 2.15 +import "." Window { id: root + // 公共主题色:集中定义于 WindowTheme.qml,随 isDarkMode 切换深浅 + WindowTheme { + id: theme + isDarkMode: root.isDarkMode + } + // 对外依赖:关闭按钮 hover 态文字高亮色,由父组件传入 // 默认值与 networkview.qml 中 root.accentRed 一致,确保独立可用 property color accentColor: Qt.rgba(220 / 255, 38 / 255, 38 / 255, 1) @@ -27,14 +35,6 @@ Window { // 默认 false(浅色)保证组件独立预览时与原版视觉一致 property bool isDarkMode: false - // ---- 主题感知颜色:isDarkMode 为 false 时取值与原浅色硬编码完全一致 ---- - readonly property color winBg: isDarkMode ? "#202020" : "#FFFFFF" - readonly property color cardBg: isDarkMode ? "#2A2A2A" : "#FFFFFF" - readonly property color lineColor: isDarkMode ? "#383838" : "#E8E8E8" - readonly property color textPrimary: isDarkMode ? "#E0E0E0" : "#333333" - readonly property color textSecondary: isDarkMode ? "#AAAAAA" : "#666666" - readonly property color textTertiary: isDarkMode ? "#888888" : "#999999" - // 复制成功状态标记:true 时复制图标变绿并显示"已复制"提示, // 2 秒后由 copyResetTimer 复位 property bool copied: false @@ -58,66 +58,22 @@ Window { // 窗口主体:圆角卡片(背景与边框随 isDarkMode 切换深浅),1px 边框模拟 DTK 窗口描边 Rectangle { anchors.fill: parent - color: root.winBg + color: theme.winBg radius: 12 border.width: 1 - border.color: root.lineColor + border.color: theme.lineColor ColumnLayout { anchors.fill: parent spacing: 0 - // 自定义标题栏:左侧"关于"标题 + 右侧圆形关闭按钮,整栏可拖动窗口 - Rectangle { + // 公共标题栏:标题文字 + 圆形关闭按钮,整栏可拖动 + TitleBar { Layout.fillWidth: true - Layout.preferredHeight: 44 - color: "transparent" - - // 拖动层:声明在关闭按钮之前(位于其下方),避免遮挡按钮点击与 hover - // 用 startSystemMove() 系统级窗口拖动(drag.target 对 Window 无效, - // 与 SettingsWindow/TrafficChartWindow 一致) - MouseArea { - anchors.fill: parent - cursorShape: Qt.OpenHandCursor - onPressed: root.startSystemMove() - } - - Text { - anchors.left: parent.left - anchors.leftMargin: 16 - anchors.verticalCenter: parent.verticalCenter - text: qsTr("About") - font.pixelSize: 15 - font.weight: Font.Bold - color: root.textPrimary - } - - // 关闭按钮:28x28 圆形,hover 时淡红底 + 红色 ×(颜色由 accentColor 决定) - Rectangle { - anchors.right: parent.right - anchors.rightMargin: 12 - anchors.verticalCenter: parent.verticalCenter - width: 28 - height: 28 - radius: 14 - color: aboutCloseMouse.containsMouse ? Qt.rgba(220 / 255, 38 / 255, 38 / 255, 0.15) : "transparent" - - Text { - anchors.centerIn: parent - text: "×" - font.pixelSize: 20 - font.weight: Font.Bold - color: aboutCloseMouse.containsMouse ? accentColor : root.textSecondary - } - - MouseArea { - id: aboutCloseMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.hide() - } - } + titleText: qsTr("About") + textColor: theme.textPrimary + secondaryTextColor: theme.textSecondary + closeHoverColor: root.accentColor } // 标题区上方间距 @@ -136,7 +92,7 @@ Window { text: qsTr("Network Speed Monitor") font.pixelSize: 18 font.weight: Font.Bold - color: root.textPrimary + color: theme.textPrimary Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter } @@ -144,7 +100,7 @@ Window { Text { text: "JNetApplet" font.pixelSize: 12 - color: root.textTertiary + color: theme.textTertiary Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter } @@ -161,7 +117,7 @@ Window { Layout.leftMargin: 24 Layout.rightMargin: 24 Layout.preferredHeight: 1 - color: root.lineColor + color: theme.lineColor } // 信息区上方间距 @@ -192,7 +148,7 @@ Window { Text { text: version font.pixelSize: 12 - color: root.textPrimary + color: theme.textPrimary Layout.fillWidth: true } } @@ -213,7 +169,7 @@ Window { Text { text: "Jokul" font.pixelSize: 12 - color: root.textPrimary + color: theme.textPrimary Layout.fillWidth: true } } @@ -234,7 +190,7 @@ Window { Text { text: qsTr("Monitor network speed and traffic") font.pixelSize: 12 - color: root.textPrimary + color: theme.textPrimary Layout.fillWidth: true wrapMode: Text.WordWrap } @@ -256,7 +212,7 @@ Window { Text { text: "git.jokul.space/Jokul/JNetApplet" font.pixelSize: 11 - color: root.textTertiary + color: theme.textTertiary Layout.fillWidth: true wrapMode: Text.WrapAnywhere } @@ -277,7 +233,7 @@ Window { width: copiedHintText.implicitWidth + 10 height: 18 radius: 4 - color: root.cardBg + color: theme.cardBg border.width: 1 border.color: "#22A34A" @@ -313,9 +269,9 @@ Window { width: 10 height: 10 radius: 2 - color: root.cardBg + color: theme.cardBg border.width: 1 - border.color: copyRepoMouse.containsMouse ? root.textPrimary : root.textTertiary + border.color: copyRepoMouse.containsMouse ? theme.textPrimary : theme.textTertiary } // 前层矩形(左上),复制成功时边框短暂变绿 @@ -325,9 +281,9 @@ Window { width: 10 height: 10 radius: 2 - color: root.cardBg + color: theme.cardBg border.width: 1 - border.color: copied ? "#22A34A" : (copyRepoMouse.containsMouse ? root.textPrimary : root.textTertiary) + border.color: copied ? "#22A34A" : (copyRepoMouse.containsMouse ? theme.textPrimary : theme.textTertiary) } } } diff --git a/package/components/SettingsWindow.qml b/package/components/SettingsWindow.qml index 2a80d1f..c0ae6ca 100644 --- a/package/components/SettingsWindow.qml +++ b/package/components/SettingsWindow.qml @@ -9,6 +9,8 @@ // 对外依赖:applet(C++ 后端对象)、networkInterfaces(接口列表)、activeInterface(当前接口)、 // accentColor(强调色)、isDarkMode(深色模式标记),由 networkview.qml 实例化时传入, // 触发方式为 show()/raise()/requestActivate() +// 公共能力复用:主题色取自 WindowTheme(本窗口 winBg 浅色 #F5F5F5、lineColor 浅色 +// #E0E0E0 与其他窗口不同,通过覆盖 WindowTheme 的浅色对实现),标题栏/圆角卡片取自 TitleBar import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 @@ -22,6 +24,15 @@ Window { // 与 NetworkPopup 共享同一份实现,消除跨组件重复定义 NetCommon { id: common } + // 公共主题色:集中定义于 WindowTheme.qml,随 isDarkMode 切换深浅。 + // 本窗口 winBg 浅色 #F5F5F5、lineColor 浅色 #E0E0E0 与默认值不同,在此覆盖 + WindowTheme { + id: theme + isDarkMode: root.isDarkMode + lightWinBg: "#F5F5F5" + lightLineColor: "#E0E0E0" + } + // 对外依赖:C++ 后端对象,用于获取/设置接口、字体颜色等 property var applet: null @@ -39,15 +50,8 @@ Window { // 默认 false(浅色)保证组件独立预览时与原版视觉一致 property bool isDarkMode: false - // ---- 主题感知颜色:isDarkMode 为 false 时取值与原浅色硬编码完全一致 ---- - readonly property color winBg: isDarkMode ? "#202020" : "#F5F5F5" - readonly property color cardBg: isDarkMode ? "#2A2A2A" : "#FFFFFF" - readonly property color lineColor: isDarkMode ? "#383838" : "#E0E0E0" - readonly property color textPrimary: isDarkMode ? "#E0E0E0" : "#333333" - readonly property color textSecondary: isDarkMode ? "#AAAAAA" : "#666666" - readonly property color textTertiary: isDarkMode ? "#888888" : "#999999" - readonly property color iconGray: isDarkMode ? "#AAAAAA" : "#777777" - readonly property color hoverBg: isDarkMode ? "#353535" : "#F0F0F0" + // ---- 设置窗口特有颜色(不属于三窗口公共主题)---- + // 命令显示区底色 readonly property color codeBg: isDarkMode ? "#2A2A2A" : "#E8E8E8" // 选中态蓝色系:深色模式下背景压暗、文字改浅蓝,保证深色卡片上的对比度 readonly property color selBg: isDarkMode ? "#1A3A5C" : "#E3F2FD" @@ -83,76 +87,30 @@ Window { // 主容器:提供不透明背景(随 isDarkMode 切换深浅)+ 圆角 + 边框 Rectangle { anchors.fill: parent - color: root.winBg + color: theme.winBg radius: 12 border.width: 1 - border.color: root.lineColor + border.color: theme.lineColor ColumnLayout { anchors.fill: parent anchors.margins: 0 spacing: 0 - // 自定义标题栏(可拖动) - Rectangle { + // 公共标题栏:标题文字 + 圆形关闭按钮,整栏可拖动 + TitleBar { Layout.fillWidth: true - Layout.preferredHeight: 44 - color: "transparent" - - // 拖动层:声明在关闭按钮之前(位于其下方),避免遮挡按钮点击与 hover - // 用 startSystemMove() 系统级窗口拖动,由窗口管理器接管移动, - // 这是 frameless Window 的正确做法,pressed 即触发,丝滑无抖动 - MouseArea { - anchors.fill: parent - cursorShape: Qt.OpenHandCursor - onPressed: root.startSystemMove() - } - - // 标题文字 - Text { - anchors.left: parent.left - anchors.leftMargin: 16 - anchors.verticalCenter: parent.verticalCenter - text: qsTr("Settings") - font.pixelSize: 15 - font.weight: Font.Bold - color: root.textPrimary - } - - // 关闭按钮 - Rectangle { - id: closeButton - anchors.right: parent.right - anchors.rightMargin: 12 - anchors.verticalCenter: parent.verticalCenter - width: 28 - height: 28 - radius: 14 - color: closeMouse.containsMouse ? Qt.rgba(220/255, 38/255, 38/255, 0.15) : "transparent" - - Text { - anchors.centerIn: parent - text: "×" - font.pixelSize: 20 - font.weight: Font.Bold - color: closeMouse.containsMouse ? accentColor : root.textSecondary - } - - MouseArea { - id: closeMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.hide() - } - } + titleText: qsTr("Settings") + textColor: theme.textPrimary + secondaryTextColor: theme.textSecondary + closeHoverColor: root.accentColor } // 分隔线 Rectangle { Layout.fillWidth: true Layout.preferredHeight: 1 - color: root.lineColor + color: theme.lineColor } // 内容区域 @@ -170,7 +128,7 @@ Window { text: qsTr("Network Interface") font.pixelSize: 13 font.weight: Font.Bold - color: root.textSecondary + color: theme.textSecondary } // 接口列表容器:最多显示约 5 行(160px),超出部分垂直滚动 @@ -181,10 +139,10 @@ Window { Layout.preferredHeight: networkInterfaces.length > 0 ? Math.min(ifaceColumn.implicitHeight, 160) + 20 : 80 - color: root.cardBg + color: theme.cardBg radius: 10 border.width: 1 - border.color: root.lineColor + border.color: theme.lineColor // 用 ScrollView 而非裸 Flickable:自带滚轮滚动支持, // 且滚动条显示时自动让出内容宽度,不会遮挡行内文字 @@ -209,8 +167,8 @@ Window { implicitWidth: 4 radius: 2 // 按压/悬停加深、默认稍淡,保证滚动条在卡片背景上可见 - color: ifaceScrollBar.pressed ? root.textSecondary - : (ifaceScrollBar.hovered ? root.textSecondary : root.textTertiary) + color: ifaceScrollBar.pressed ? theme.textSecondary + : (ifaceScrollBar.hovered ? theme.textSecondary : theme.textTertiary) } } @@ -239,7 +197,7 @@ Window { // 背景优先级:选中 > hover;选中行 hover 时稍加深以保留交互反馈 color: isActive ? (hovered ? root.selBgHover : root.selBg) - : (hovered ? root.hoverBg : "transparent") + : (hovered ? theme.hoverBg : "transparent") // 选中行加细边框增强视觉;未选中保持透明边框占位,避免切换时出现 1px 抖动 border.width: 1 border.color: isActive ? root.selBorder : "transparent" @@ -267,7 +225,7 @@ Window { horizontalAlignment: Text.AlignHCenter text: common.interfaceIcon(modelData) font.pixelSize: 14 - color: ifaceRow.isActive ? ifaceRow.activeColor : root.iconGray + color: ifaceRow.isActive ? ifaceRow.activeColor : theme.iconGray } // 自绘单选圆点:替代 RadioButton 作纯视觉指示器, @@ -281,7 +239,7 @@ Window { color: "transparent" border.width: 2 border.color: ifaceRow.isActive ? ifaceRow.activeColor - : (ifaceRow.hovered ? root.textSecondary : root.textTertiary) + : (ifaceRow.hovered ? theme.textSecondary : theme.textTertiary) Rectangle { anchors.centerIn: parent @@ -300,7 +258,7 @@ Window { text: modelData font.pixelSize: 13 font.weight: ifaceRow.isActive ? Font.Medium : Font.Normal - color: ifaceRow.isActive ? ifaceRow.activeColor : root.textPrimary + color: ifaceRow.isActive ? ifaceRow.activeColor : theme.textPrimary elide: Text.ElideRight } @@ -309,7 +267,7 @@ Window { Layout.alignment: Qt.AlignVCenter text: common.interfaceDescription(modelData) font.pixelSize: 12 - color: root.textTertiary + color: theme.textTertiary } } } @@ -322,7 +280,7 @@ Window { anchors.centerIn: parent text: qsTr("No network interface detected") font.pixelSize: 12 - color: root.textTertiary + color: theme.textTertiary visible: networkInterfaces.length === 0 } } @@ -334,7 +292,7 @@ Window { text: qsTr("Font Color") font.pixelSize: 13 font.weight: Font.Bold - color: root.textSecondary + color: theme.textSecondary } TextColorPicker { @@ -353,7 +311,7 @@ Window { text: qsTr("Refresh Interval") font.pixelSize: 13 font.weight: Font.Bold - color: root.textSecondary + color: theme.textSecondary } // 三个间隔选项按钮:1 秒 / 2 秒 / 5 秒 @@ -371,17 +329,17 @@ Window { radius: 8 // 选中态蓝色填充边框,未选中态卡片背景,hover 态加深 color: applet && applet.refreshInterval === modelData - ? root.selBg : (intervalMouse.containsMouse ? root.hoverBg : root.cardBg) + ? root.selBg : (intervalMouse.containsMouse ? theme.hoverBg : theme.cardBg) border.width: 1 border.color: applet && applet.refreshInterval === modelData - ? root.selBorder : root.lineColor + ? root.selBorder : theme.lineColor Text { anchors.centerIn: parent text: (modelData / 1000) + "s" font.pixelSize: 13 color: applet && applet.refreshInterval === modelData - ? root.selText : root.textPrimary + ? root.selText : theme.textPrimary } MouseArea { @@ -455,10 +413,10 @@ Window { y: (root.height - height) / 2 background: Rectangle { - color: root.winBg + color: theme.winBg radius: 12 border.width: 1 - border.color: root.lineColor + border.color: theme.lineColor } contentItem: ColumnLayout { @@ -477,7 +435,7 @@ Window { Text { text: qsTr("The following command uninstalls the plugin and restarts dde-shell. Please copy and run it in terminal:") font.pixelSize: 12 - color: root.textPrimary + color: theme.textPrimary Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter @@ -497,7 +455,7 @@ Window { text: "sudo rm -rf /usr/share/dde-shell/space.jokul.JNetApplet/ && systemctl --user restart dde-shell@DDE" font.pixelSize: 10 font.family: "monospace" - color: root.textSecondary + color: theme.textSecondary wrapMode: Text.WordWrap } } @@ -513,16 +471,16 @@ Window { Rectangle { Layout.fillWidth: true Layout.preferredHeight: 36 - color: cancelUninstallMouse.containsMouse ? root.hoverBg : root.cardBg + color: cancelUninstallMouse.containsMouse ? theme.hoverBg : theme.cardBg radius: 8 border.width: 1 - border.color: root.lineColor + border.color: theme.lineColor Text { anchors.centerIn: parent text: qsTr("Cancel") font.pixelSize: 13 - color: root.textPrimary + color: theme.textPrimary } MouseArea { diff --git a/package/components/TitleBar.qml b/package/components/TitleBar.qml new file mode 100644 index 0000000..a4d86b9 --- /dev/null +++ b/package/components/TitleBar.qml @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2026 Jokul +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +// 独立窗口公共自定义标题栏 +// 消除 AboutWindow / SettingsWindow / TrafficChartWindow 三个独立顶层窗口之间的 +// 标题栏样板重复(此前各窗口各持一份"拖动层 + 标题文字 + 圆形关闭按钮"的拷贝)。 +// 现提取为本组件,各窗口在圆角卡片顶部的 ColumnLayout 中实例化 TitleBar 即可。 +// 对外能力: +// - titleText:标题栏文字 +// - textColor / secondaryTextColor:标题文字色与关闭按钮默认文字色(取主题色) +// - closeHoverColor:关闭按钮 hover 态文字高亮色(accentColor,默认红色) +// - 拖动:整栏按住调用 Window.window.startSystemMove() 系统级拖动(frameless +// Window 的正确做法,drag.target 对 Window 无效);拖动层声明在按钮下方, +// 不遮挡关闭/额外按钮的点击与 hover +// - 关闭按钮:28x28 圆形,hover 时淡红底 + 红色 ×,点击 Window.window.hide() +// - extraActions:default property,供子窗口在关闭按钮左侧填充额外按钮 +// (如 TrafficChartWindow 的"置顶"按钮),其逻辑仍保留在子窗口内 +import QtQuick 2.15 +import QtQuick.Window 2.15 + +Item { + id: titleBar + + // 标题栏文字,由子窗口传入(qsTr 文案在子窗口侧) + property string titleText: "" + + // 标题文字颜色:取主题色 textPrimary + property color textColor: "#333333" + + // 关闭按钮默认文字色:取主题色 textSecondary + property color secondaryTextColor: "#666666" + + // 关闭按钮 hover 态文字高亮色:取子窗口 accentColor(默认红色) + property color closeHoverColor: Qt.rgba(220 / 255, 38 / 255, 38 / 255, 1) + + // 额外右侧按钮容器:default property 让子窗口直接把按钮写进标题栏, + // 按钮将布局在关闭按钮左侧(用于置顶按钮等) + default property alias extraActions: actionHost.data + + implicitHeight: 44 + + // 拖动层:声明在关闭/额外按钮之前(位于其下方),避免遮挡按钮点击与 hover + // 用 startSystemMove() 系统级窗口拖动,由窗口管理器接管移动, + // 这是 frameless Window 的正确做法,pressed 即触发,丝滑无抖动 + MouseArea { + anchors.fill: parent + cursorShape: Qt.OpenHandCursor + onPressed: Window.window.startSystemMove() + } + + // 标题文字 + Text { + anchors.left: parent.left + anchors.leftMargin: 16 + anchors.verticalCenter: parent.verticalCenter + text: titleBar.titleText + font.pixelSize: 15 + font.weight: Font.Bold + color: titleBar.textColor + } + + // 额外右侧按钮容器:右缘贴关闭按钮左侧,高度与标题栏一致 + Item { + id: actionHost + anchors.right: closeButton.left + anchors.rightMargin: 4 + anchors.top: parent.top + anchors.bottom: parent.bottom + } + + // 关闭按钮:28x28 圆形,hover 时淡红底 + 红色 ×(颜色由 closeHoverColor 决定) + Rectangle { + id: closeButton + anchors.right: parent.right + anchors.rightMargin: 12 + anchors.verticalCenter: parent.verticalCenter + width: 28 + height: 28 + radius: 14 + color: closeMouse.containsMouse ? Qt.rgba(220 / 255, 38 / 255, 38 / 255, 0.15) : "transparent" + + Text { + anchors.centerIn: parent + text: "×" + font.pixelSize: 20 + font.weight: Font.Bold + color: closeMouse.containsMouse ? titleBar.closeHoverColor : titleBar.secondaryTextColor + } + + MouseArea { + id: closeMouse + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: Window.window.hide() + } + } +} diff --git a/package/components/TrafficChartWindow.qml b/package/components/TrafficChartWindow.qml index b4245cb..2c9499a 100644 --- a/package/components/TrafficChartWindow.qml +++ b/package/components/TrafficChartWindow.qml @@ -13,6 +13,8 @@ // - 数据通过属性注入:applet 即 networkview.qml 的 root.applet(C++ 后端对象), // 为 null 时组件可独立预览(Canvas 显示"暂无历史数据"空状态) // 触发方式:右键菜单"流量波动图" -> show()/raise()/requestActivate() +// 公共能力复用:主题色取自 WindowTheme,标题栏(含置顶/关闭按钮)取自 TitleBar, +// 消除三窗口样板重复 import QtQuick 2.15 import QtQuick.Layouts 1.15 import QtQuick.Window 2.15 @@ -25,6 +27,12 @@ Window { // 与 networkview.qml、NetworkPopup 共享同一份实现,消除跨组件重复定义 NetCommon { id: common } + // 公共主题色:集中定义于 WindowTheme.qml,随 isDarkMode 切换深浅 + WindowTheme { + id: theme + isDarkMode: root.isDarkMode + } + // 对外依赖:关闭按钮 hover 态文字高亮色,由父组件传入 // 默认值与 networkview.qml 中 root.accentRed 一致,确保独立可用 property color accentColor: Qt.rgba(220 / 255, 38 / 255, 38 / 255, 1) @@ -39,16 +47,10 @@ Window { // 默认 false(浅色)保证组件独立预览时与原版视觉一致 property bool isDarkMode: false - // ---- 主题感知颜色:isDarkMode 为 false 时取值与原浅色硬编码完全一致 ---- - readonly property color winBg: isDarkMode ? "#202020" : "#FFFFFF" - readonly property color lineColor: isDarkMode ? "#383838" : "#E8E8E8" - readonly property color textPrimary: isDarkMode ? "#E0E0E0" : "#333333" - readonly property color textSecondary: isDarkMode ? "#AAAAAA" : "#666666" - readonly property color textTertiary: isDarkMode ? "#888888" : "#999999" - // 置顶按钮 hover 底色:浅色用淡黑、深色用淡白,保证两种卡片背景上均可见 + // 置顶按钮 hover 底色(本窗口特有):浅色用淡黑、深色用淡白,保证两种卡片背景上均可见 readonly property color pinHoverBg: isDarkMode ? Qt.rgba(1, 1, 1, 0.10) : Qt.rgba(0, 0, 0, 0.06) - // 图表绘制色:声明为 string 供 Canvas 2D 上下文直接使用 + // 图表绘制色(本窗口特有):声明为 string 供 Canvas 2D 上下文直接使用 //(QML color 类型含 alpha 时序列化为 #AARRGGBB,Canvas 无法正确解析,故不用 color 类型) readonly property string gridBaselineColor: isDarkMode ? "#383838" : "#DDDDDD" readonly property string gridLineColor: isDarkMode ? "#2A2A2A" : "#E5E5E5" @@ -148,47 +150,29 @@ Window { // 窗口主体:圆角卡片(背景与边框随 isDarkMode 切换深浅),1px 边框模拟 DTK 窗口描边(与 AboutWindow 一致) Rectangle { anchors.fill: parent - color: root.winBg + color: theme.winBg radius: 12 border.width: 1 - border.color: root.lineColor + border.color: theme.lineColor ColumnLayout { anchors.fill: parent spacing: 0 - // 自定义标题栏:左侧"流量波动图"标题 + 右侧置顶/关闭按钮,整栏可拖动窗口 - Rectangle { + // 公共标题栏:标题文字 + 置顶/关闭按钮,整栏可拖动。 + // 置顶按钮通过 TitleBar 的额外按钮槽(extraActions)注入,逻辑仍在本窗口 + TitleBar { Layout.fillWidth: true - Layout.preferredHeight: 44 - color: "transparent" - - // 拖动层:声明在关闭/置顶按钮之前(位于其下方),避免遮挡按钮点击与 hover - // 注意:drag.target 只对 Item 生效,对 Window 无效(原实现拖动不工作); - // 改用 startSystemMove() 系统级窗口拖动,这是 frameless Window 的正确做法, - // pressed 即触发,由窗口管理器接管移动,不干扰按钮的 hover/click - MouseArea { - anchors.fill: parent - cursorShape: Qt.OpenHandCursor - onPressed: root.startSystemMove() - } - - Text { - anchors.left: parent.left - anchors.leftMargin: 16 - anchors.verticalCenter: parent.verticalCenter - text: qsTr("Traffic Chart") - font.pixelSize: 15 - font.weight: Font.Bold - color: root.textPrimary - } + titleText: qsTr("Traffic Chart") + textColor: theme.textPrimary + secondaryTextColor: theme.textSecondary + closeHoverColor: root.accentColor // 置顶按钮:28x28 圆形(与关闭按钮一致),位于关闭按钮左侧 // 三态视觉:未置顶=灰色图钉轮廓;置顶=deepin 蓝填充 + 淡蓝底; // hover=淡灰底(置顶时淡蓝底优先) Rectangle { - anchors.right: chartCloseButton.left - anchors.rightMargin: 4 + anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter width: 28 height: 28 @@ -256,34 +240,6 @@ Window { onClicked: root.pinned = !root.pinned } } - - // 关闭按钮:28x28 圆形,hover 时淡红底 + 红色 ×(颜色由 accentColor 决定) - Rectangle { - id: chartCloseButton - anchors.right: parent.right - anchors.rightMargin: 12 - anchors.verticalCenter: parent.verticalCenter - width: 28 - height: 28 - radius: 14 - color: chartCloseMouse.containsMouse ? Qt.rgba(220 / 255, 38 / 255, 38 / 255, 0.15) : "transparent" - - Text { - anchors.centerIn: parent - text: "×" - font.pixelSize: 20 - font.weight: Font.Bold - color: chartCloseMouse.containsMouse ? root.accentColor : root.textSecondary - } - - MouseArea { - id: chartCloseMouse - anchors.fill: parent - hoverEnabled: true - cursorShape: Qt.PointingHandCursor - onClicked: root.hide() - } - } } // 顶部状态条:实时下行/上行速度(箭头颜色与折线一致,兼作图例) @@ -306,7 +262,7 @@ Window { // applet 为空时兜底为 0,保证独立预览不报错 text: common.formatSpeed(root.applet ? root.applet.downloadSpeed : 0) font.pixelSize: 12 - color: root.textPrimary + color: theme.textPrimary } Item { Layout.preferredWidth: 10 } @@ -321,7 +277,7 @@ Window { Text { text: common.formatSpeed(root.applet ? root.applet.uploadSpeed : 0) font.pixelSize: 12 - color: root.textPrimary + color: theme.textPrimary } Item { Layout.fillWidth: true } @@ -330,7 +286,7 @@ Window { text: (root.applet && root.applet.activeInterface ? root.applet.activeInterface : "—") + " · 5min" font.pixelSize: 12 - color: root.textTertiary + color: theme.textTertiary } } @@ -592,7 +548,7 @@ Window { text: root.hoverHint.length > 0 ? root.hoverHint : qsTr("Hover over the curve for details") font.pixelSize: 11 - color: root.hoverHint.length > 0 ? root.textPrimary : root.textTertiary + color: root.hoverHint.length > 0 ? theme.textPrimary : theme.textTertiary } } } diff --git a/package/components/WindowTheme.qml b/package/components/WindowTheme.qml new file mode 100644 index 0000000..3b20cb9 --- /dev/null +++ b/package/components/WindowTheme.qml @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2026 Jokul +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +// 独立窗口公共主题色提供者 +// 消除 AboutWindow / SettingsWindow / TrafficChartWindow 三个独立顶层窗口之间的 +// 主题颜色样板重复(此前各窗口各持一份 isDarkMode ? 深 : 浅 的颜色定义, +// 改一处需同步多处)。现集中到本文件,各窗口实例化 WindowTheme { id: theme } 后 +// 统一经 theme.xxx 访问,仅需向 theme.isDarkMode 传入深色模式标记。 +// 设计原因: +// - 深/浅主题由 networkview.qml 依据 DockPalette 检测任务栏深浅后通过 isDarkMode 传入, +// 浅色取值与原各窗口硬编码完全一致,保证独立预览时视觉不变。 +// - 个别窗口存在差异值(如 SettingsWindow 的 winBg 浅色为 #F5F5F5、lineColor 为 +// #E0E0E0),因此每个颜色拆成 light/dark 一对可覆盖属性,派生色由它们计算, +// 差异窗口仅需覆盖对应浅/深值即可,无需整体重写。 +import QtQuick 2.15 + +QtObject { + id: theme + + // 输入:深色模式标记,由父窗口从 networkview.qml 传入 + property bool isDarkMode: false + + // ---- 浅色/深色取色对(默认值与 AboutWindow/TrafficChartWindow 一致,个别窗口可覆盖差异值)---- + property color lightWinBg: "#FFFFFF" + property color darkWinBg: "#202020" + property color lightCardBg: "#FFFFFF" + property color darkCardBg: "#2A2A2A" + property color lightLineColor: "#E8E8E8" + property color darkLineColor: "#383838" + property color lightTextPrimary: "#333333" + property color darkTextPrimary: "#E0E0E0" + property color lightTextSecondary: "#666666" + property color darkTextSecondary: "#AAAAAA" + property color lightTextTertiary: "#999999" + property color darkTextTertiary: "#888888" + property color lightIconGray: "#777777" + property color darkIconGray: "#AAAAAA" + property color lightHoverBg: "#F0F0F0" + property color darkHoverBg: "#353535" + + // ---- 派生主题色:isDarkMode 为 false 时取值与原浅色硬编码完全一致 ---- + readonly property color winBg: isDarkMode ? darkWinBg : lightWinBg + readonly property color cardBg: isDarkMode ? darkCardBg : lightCardBg + readonly property color lineColor: isDarkMode ? darkLineColor : lightLineColor + readonly property color textPrimary: isDarkMode ? darkTextPrimary : lightTextPrimary + readonly property color textSecondary: isDarkMode ? darkTextSecondary : lightTextSecondary + readonly property color textTertiary: isDarkMode ? darkTextTertiary : lightTextTertiary + readonly property color iconGray: isDarkMode ? darkIconGray : lightIconGray + readonly property color hoverBg: isDarkMode ? darkHoverBg : lightHoverBg +}