Tray: hide all non pinned entries, reactive chevron

i18n: translation changes for tray
This commit is contained in:
Ly-sec
2025-11-04 22:50:22 +01:00
parent 3b0b3fb57e
commit ba6f0a1d2d
11 changed files with 117 additions and 61 deletions
+3 -1
View File
@@ -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": {
+2 -2
View File
@@ -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": {
+3 -1
View File
@@ -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": {
+3 -1
View File
@@ -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": {
+3 -1
View File
@@ -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": {
+3 -1
View File
@@ -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": {
+3 -1
View File
@@ -771,7 +771,9 @@
"description": "Додайте правила виключення з трея, підтримує шаблони (*).",
"label": "Чорний список",
"placeholder": "напр., nm-applet, Fcitx*"
}
},
"pin-application": "Закріпити Застосунок",
"unpin-application": "Відкріпити Застосунок"
},
"widgets": {
"section": {
+3 -1
View File
@@ -771,7 +771,9 @@
"description": "添加托盘排除规则,支持通配符 (*)。",
"label": "黑名单",
"placeholder": "例如:nm-applet, Fcitx*"
}
},
"pin-application": "固定应用程序",
"unpin-application": "取消固定应用程序"
},
"widgets": {
"section": {
+49 -35
View File
@@ -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"
}
}
}
}
+21 -8
View File
@@ -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() {
+24 -9
View File
@@ -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)