From ba6f0a1d2de98aef4925ae8d1abfcc379c9f0771 Mon Sep 17 00:00:00 2001 From: Ly-sec Date: Tue, 4 Nov 2025 22:50:22 +0100 Subject: [PATCH] Tray: hide all non pinned entries, reactive chevron i18n: translation changes for tray --- Assets/Translations/de.json | 4 +- Assets/Translations/en.json | 4 +- Assets/Translations/es.json | 4 +- Assets/Translations/fr.json | 4 +- Assets/Translations/pt.json | 4 +- Assets/Translations/tr.json | 4 +- Assets/Translations/uk-UA.json | 4 +- Assets/Translations/zh-CN.json | 4 +- Modules/Bar/Extras/TrayDropdownPanel.qml | 84 ++++++++++++++---------- Modules/Bar/Extras/TrayMenu.qml | 29 +++++--- Modules/Bar/Widgets/Tray.qml | 33 +++++++--- 11 files changed, 117 insertions(+), 61 deletions(-) diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index ce511f49..1a916a4c 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -771,7 +771,9 @@ "description": "Ausschlussregeln für die Tray-Symbolleiste hinzufügen, unterstützt Platzhalter (*).", "label": "Ausschlussliste", "placeholder": "z.B., nm-applet, Fcitx*" - } + }, + "pin-application": "Anwendung anheften", + "unpin-application": "Anheftung aufheben" }, "widgets": { "section": { diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index ac455145..35c28c50 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -772,8 +772,8 @@ "label": "Blacklist", "placeholder": "e.g., nm-applet, Fcitx*" }, - "add-as-favorite": "Add as Favorite", - "remove-from-favorites": "Remove from Favorites" + "pin-application": "Pin Application", + "unpin-application": "Unpin Application" }, "widgets": { "section": { diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index 6ee4a312..418adb1f 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -771,7 +771,9 @@ "description": "Agregar reglas de exclusión de la bandeja, admite comodines (*).", "label": "Lista negra", "placeholder": "ej., nm-applet, Fcitx*" - } + }, + "pin-application": "Fijar Aplicación", + "unpin-application": "Desfijar Aplicación" }, "widgets": { "section": { diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 68ee83f0..5758939e 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -771,7 +771,9 @@ "description": "Ajouter des règles d'exclusion pour la boîte à miniatures, prend en charge les caractères génériques (*).", "label": "Liste noire", "placeholder": "ex: nm-applet, Fcitx*" - } + }, + "pin-application": "Épingler l'Application", + "unpin-application": "Désépingler l'Application" }, "widgets": { "section": { diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index 86fab3f0..0bbeb198 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -771,7 +771,9 @@ "description": "Adicione regras de exclusão para a bandeja do sistema, suporta curingas (*).", "label": "Lista Negra", "placeholder": "ex: nm-applet, Fcitx*" - } + }, + "pin-application": "Fixar Aplicativo", + "unpin-application": "Desfixar Aplicativo" }, "widgets": { "section": { diff --git a/Assets/Translations/tr.json b/Assets/Translations/tr.json index 64276f95..c1f34767 100644 --- a/Assets/Translations/tr.json +++ b/Assets/Translations/tr.json @@ -771,7 +771,9 @@ "description": "Tepsi hariç tutma kuralları ekleyin, joker karakterleri destekler (*).", "label": "Kara liste", "placeholder": "örn., nm-applet, Fcitx*" - } + }, + "pin-application": "Uygulamayı Sabitle", + "unpin-application": "Sabitlemeyi Kaldır" }, "widgets": { "section": { diff --git a/Assets/Translations/uk-UA.json b/Assets/Translations/uk-UA.json index a75c70db..37ad21fe 100644 --- a/Assets/Translations/uk-UA.json +++ b/Assets/Translations/uk-UA.json @@ -771,7 +771,9 @@ "description": "Додайте правила виключення з трея, підтримує шаблони (*).", "label": "Чорний список", "placeholder": "напр., nm-applet, Fcitx*" - } + }, + "pin-application": "Закріпити Застосунок", + "unpin-application": "Відкріпити Застосунок" }, "widgets": { "section": { diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index 2ac08e2c..e7002e8a 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -771,7 +771,9 @@ "description": "添加托盘排除规则,支持通配符 (*)。", "label": "黑名单", "placeholder": "例如:nm-applet, Fcitx*" - } + }, + "pin-application": "固定应用程序", + "unpin-application": "取消固定应用程序" }, "widgets": { "section": { diff --git a/Modules/Bar/Extras/TrayDropdownPanel.qml b/Modules/Bar/Extras/TrayDropdownPanel.qml index 96339471..ba3262d0 100644 --- a/Modules/Bar/Extras/TrayDropdownPanel.qml +++ b/Modules/Bar/Extras/TrayDropdownPanel.qml @@ -16,7 +16,7 @@ NPanel { // Widget info for menu functionality property string widgetSection: "" property int widgetIndex: -1 - + // Trigger refresh when settings change property int settingsVersion: 0 @@ -24,26 +24,36 @@ NPanel { readonly property var favoritesList: { // Reference settingsVersion to force recalculation when it changes var _ = root.settingsVersion - if (widgetSection === "" || widgetIndex < 0) return [] + if (widgetSection === "" || widgetIndex < 0) + return [] var widgets = Settings.data.bar.widgets[widgetSection] - if (!widgets || widgetIndex >= widgets.length) return [] + if (!widgets || widgetIndex >= widgets.length) + return [] var widgetSettings = widgets[widgetIndex] - if (!widgetSettings || widgetSettings.id !== "Tray") return [] + if (!widgetSettings || widgetSettings.id !== "Tray") + return [] return widgetSettings.favorites || [] } function wildCardMatch(str, rule) { - if (!str || !rule) return false + if (!str || !rule) + return false let escaped = rule.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') let pattern = '^' + escaped.replace(/\\\*/g, '.*') + '$' - try { return new RegExp(pattern, 'i').test(str) } catch(e) { return false } + try { + return new RegExp(pattern, 'i').test(str) + } catch (e) { + return false + } } function isFavorite(item) { - if (!favoritesList || favoritesList.length === 0) return false + if (!favoritesList || favoritesList.length === 0) + return false const title = item?.tooltipTitle || item?.name || item?.id || "" for (var i = 0; i < favoritesList.length; i++) { - if (wildCardMatch(title, favoritesList[i])) return true + if (wildCardMatch(title, favoritesList[i])) + return true } return false } @@ -51,7 +61,9 @@ NPanel { // Dynamic sizing based on item count // Show items that are NOT favorites (non-favorites go to dropdown) readonly property var trayValuesAll: (SystemTray.items && SystemTray.items.values) ? SystemTray.items.values : [] - readonly property var trayValues: trayValuesAll.filter(function(it){ return !root.isFavorite(it) }) + readonly property var trayValues: trayValuesAll.filter(function (it) { + return !root.isFavorite(it) + }) readonly property int itemCount: trayValues.length readonly property int maxColumns: 8 readonly property real cellSize: Math.round(Style.capsuleHeight * 0.65) @@ -126,32 +138,34 @@ NPanel { hoverEnabled: true acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - onClicked: (mouse) => { - if (!modelData) - return - if (mouse.button === Qt.RightButton && modelData.hasMenu && modelData.menu && trayMenu.item) { - trayMenu.item.menu = modelData.menu - trayMenu.item.screen = root.screen - trayMenu.item.trayItem = modelData - trayMenu.item.widgetSection = root.widgetSection - trayMenu.item.widgetIndex = root.widgetIndex - const menuX = (root.columns > 1) ? (trayIcon.width / 2) : 0 - const menuY = trayIcon.height - trayMenu.item.showAt(trayIcon, menuX, menuY) - } else if (mouse.button === Qt.LeftButton) { - modelData.activate?.() - // Close the dropdown after activation - PanelService.getPanel("trayDropdownPanel", root.screen)?.close() - } else if (mouse.button === Qt.MiddleButton) { - modelData.secondaryActivate?.() - PanelService.getPanel("trayDropdownPanel", root.screen)?.close() - } - } + onClicked: mouse => { + if (!modelData) + return + if (mouse.button === Qt.RightButton && modelData.hasMenu && modelData.menu && trayMenu.item) { + trayMenu.item.menu = modelData.menu + trayMenu.item.screen = root.screen + trayMenu.item.trayItem = modelData + trayMenu.item.widgetSection = root.widgetSection + trayMenu.item.widgetIndex = root.widgetIndex + const menuX = (root.columns > 1) ? (trayIcon.width / 2) : 0 + const menuY = trayIcon.height + trayMenu.item.showAt(trayIcon, menuX, menuY) + } else if (mouse.button === Qt.LeftButton) { + modelData.activate() + // Close the dropdown after activation + PanelService.getPanel("trayDropdownPanel", root.screen)?.close() + } else if (mouse.button === Qt.MiddleButton) { + modelData.secondaryActivate() + PanelService.getPanel("trayDropdownPanel", root.screen)?.close() + } + } - onWheel: (wheel) => { - if (wheel.angleDelta.y > 0) modelData?.scrollUp?.() - else if (wheel.angleDelta.y < 0) modelData?.scrollDown?.() - } + onWheel: wheel => { + if (wheel.angleDelta.y > 0) + modelData?.scrollUp() + else if (wheel.angleDelta.y < 0) + modelData?.scrollDown() + } onEntered: TooltipService.show(Screen, trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection()) onExited: TooltipService.hide() @@ -169,4 +183,4 @@ NPanel { source: "TrayMenu.qml" } } -} \ No newline at end of file +} diff --git a/Modules/Bar/Extras/TrayMenu.qml b/Modules/Bar/Extras/TrayMenu.qml index 63909569..4357bc94 100644 --- a/Modules/Bar/Extras/TrayMenu.qml +++ b/Modules/Bar/Extras/TrayMenu.qml @@ -303,18 +303,23 @@ PopupWindow { // Check if item is already a favorite readonly property bool isFavorite: { - if (!root.trayItem || root.widgetSection === "" || root.widgetIndex < 0) return false + if (!root.trayItem || root.widgetSection === "" || root.widgetIndex < 0) + return false const itemName = root.trayItem.tooltipTitle || root.trayItem.name || root.trayItem.id || "" - if (!itemName) return false - + if (!itemName) + return false + var widgets = Settings.data.bar.widgets[root.widgetSection] - if (!widgets || root.widgetIndex >= widgets.length) return false + if (!widgets || root.widgetIndex >= widgets.length) + return false var widgetSettings = widgets[root.widgetIndex] - if (!widgetSettings || widgetSettings.id !== "Tray") return false - + if (!widgetSettings || widgetSettings.id !== "Tray") + return false + var favorites = widgetSettings.favorites || [] for (var i = 0; i < favorites.length; i++) { - if (favorites[i] === itemName) return true + if (favorites[i] === itemName) + return true } return false } @@ -343,7 +348,7 @@ PopupWindow { NText { Layout.fillWidth: true color: Color.mPrimary - text: addToFavoriteEntry.isFavorite ? I18n.tr("settings.bar.tray.remove-from-favorites") : I18n.tr("settings.bar.tray.add-as-favorite") + text: addToFavoriteEntry.isFavorite ? I18n.tr("settings.bar.tray.unpin-application") : I18n.tr("settings.bar.tray.pin-application") pointSize: Style.fontSizeS font.weight: Font.Medium verticalAlignment: Text.AlignVCenter @@ -414,6 +419,14 @@ PopupWindow { Settings.saveImmediate() Logger.i("TrayMenu", "Added", itemName, "as favorite") + + // Close the tray dropdown panel after pinning + if (root.screen) { + const panel = PanelService.getPanel("trayDropdownPanel", root.screen) + if (panel) { + panel.close() + } + } } function removeFromFavorites() { diff --git a/Modules/Bar/Widgets/Tray.qml b/Modules/Bar/Widgets/Tray.qml index b1472dca..15176b76 100644 --- a/Modules/Bar/Widgets/Tray.qml +++ b/Modules/Bar/Widgets/Tray.qml @@ -109,7 +109,7 @@ Rectangle { } // Build inline (favorites) and dropdown (non-favorites) lists - // If favorites list is empty, all items are inline + // If favorites list is empty, all items go to dropdown (none inline) // If favorites list has items, favorites are inline, rest go to dropdown if (favorites && favorites.length > 0) { let fav = [] @@ -132,15 +132,19 @@ Rectangle { const cand = newItems[v] let isFavorite = false for (var f = 0; f < filteredItems.length; f++) { - if (filteredItems[f] === cand) { isFavorite = true; break } + if (filteredItems[f] === cand) { + isFavorite = true + break + } } - if (!isFavorite) nonFav.push(cand) + if (!isFavorite) + nonFav.push(cand) } dropdownItems = nonFav } else { - // No favorites: all items are inline - filteredItems = newItems - dropdownItems = [] + // No favorites: all items go to dropdown (none inline) + filteredItems = [] + dropdownItems = newItems } } @@ -303,9 +307,20 @@ Rectangle { NIconButton { id: dropdownButton visible: dropdownItems.length > 0 - width: itemSize - height: itemSize - icon: isVertical ? (barPosition === "left" ? "chevron-right" : "chevron-left") : "chevron-down" + width: Math.round(itemSize * 1.4) + height: Math.round(itemSize * 1.4) + icon: { + if (barPosition === "top") + return "chevron-down" + else if (barPosition === "bottom") + return "chevron-up" + else if (barPosition === "left") + return "chevron-right" + else if (barPosition === "right") + return "chevron-left" + else + return "chevron-down" // default fallback + } tooltipText: I18n.tr("open-control-center") // reuse generic tooltip text onClicked: { const panel = PanelService.getPanel("trayDropdownPanel", root.screen)