mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2026-08-15 18:43:59 +00:00
Merge with noctalia main
This commit is contained in:
@@ -652,7 +652,8 @@
|
||||
"logout": "Abmelden",
|
||||
"reboot": "Neu starten",
|
||||
"shutdown": "Herunterfahren",
|
||||
"suspend": "Ruhezustand",
|
||||
"suspend": "Energiesparmodus",
|
||||
"hibernate": "Ruhezustand",
|
||||
"title": "Sitzungsmenü"
|
||||
},
|
||||
"settings": {
|
||||
@@ -879,7 +880,7 @@
|
||||
"programs": {
|
||||
"code": {
|
||||
"description": "Schreibe {Dateipfad}. Das Hyprluna-Theme muss manuell installiert und aktiviert werden",
|
||||
"description-missing": "Benötigt die Installation von {app}"
|
||||
"description-missing": "Kein Code-Client erkannt. Installieren Sie VSCode oder VSCodium."
|
||||
},
|
||||
"description": "Anwendungsspezifisches Theming.",
|
||||
"discord": {
|
||||
@@ -1441,8 +1442,8 @@
|
||||
"label": "Immer im Vordergrund"
|
||||
},
|
||||
"background-opacity": {
|
||||
"description": "Controls the transparency of the OSD background.",
|
||||
"label": "Background opacity"
|
||||
"description": "Kontrolliert die Transparenz des OSD Hintergrunds.",
|
||||
"label": "Hintergrund-Transparenz"
|
||||
},
|
||||
"description": "Bildschirm-Overlays wie Lautstärke- und Helligkeitsanzeigen konfigurieren.",
|
||||
"duration": {
|
||||
@@ -1567,6 +1568,15 @@
|
||||
},
|
||||
"title": "Sitzungsmenü"
|
||||
},
|
||||
"system-monitor": {
|
||||
"general": {
|
||||
"section": {
|
||||
"description": "Konfigurieren Sie das Verhalten und Aussehen des Systemmonitors.",
|
||||
"label": "Allgemein"
|
||||
}
|
||||
},
|
||||
"title": "Systemmonitor"
|
||||
},
|
||||
"user-interface": {
|
||||
"animation-disable": {
|
||||
"description": "Deaktivieren Sie alle Animationen für eine schnellere und reaktionsfreudigere Erfahrung.",
|
||||
|
||||
@@ -653,6 +653,7 @@
|
||||
"reboot": "Reboot",
|
||||
"shutdown": "Shutdown",
|
||||
"suspend": "Suspend",
|
||||
"hibernate": "Hibernate",
|
||||
"title": "Session Menu"
|
||||
},
|
||||
"settings": {
|
||||
@@ -879,7 +880,7 @@
|
||||
"programs": {
|
||||
"code": {
|
||||
"description": "Write {filepath}. Hyprluna theme needs to be installed and activated manually.",
|
||||
"description-missing": "Requires {app} to be installed"
|
||||
"description-missing": "No Code client detected. Install VSCode or VSCodium."
|
||||
},
|
||||
"description": "Application-specific theming.",
|
||||
"discord": {
|
||||
@@ -1567,6 +1568,15 @@
|
||||
},
|
||||
"title": "Session Menu"
|
||||
},
|
||||
"system-monitor": {
|
||||
"general": {
|
||||
"section": {
|
||||
"description": "Configure the System Monitor behavior and appearance.",
|
||||
"label": "General"
|
||||
}
|
||||
},
|
||||
"title": "System Monitor"
|
||||
},
|
||||
"user-interface": {
|
||||
"animation-disable": {
|
||||
"description": "Disable all animations for a faster, more responsive experience.",
|
||||
|
||||
@@ -653,6 +653,7 @@
|
||||
"reboot": "Reiniciar",
|
||||
"shutdown": "Apagar",
|
||||
"suspend": "Suspender",
|
||||
"hibernate": "Hibernación",
|
||||
"title": "Menú de sesión"
|
||||
},
|
||||
"settings": {
|
||||
@@ -879,7 +880,7 @@
|
||||
"programs": {
|
||||
"code": {
|
||||
"description": "Escribe {filepath}. El tema Hyprluna debe ser instalado y activado manualmente.",
|
||||
"description-missing": "Requiere que {app} esté instalado/a."
|
||||
"description-missing": "No se detectó cliente de Code. Instala VSCode o VSCodium."
|
||||
},
|
||||
"description": "Tematización específica de aplicaciones.",
|
||||
"discord": {
|
||||
@@ -1567,6 +1568,15 @@
|
||||
},
|
||||
"title": "Menú de sesión"
|
||||
},
|
||||
"system-monitor": {
|
||||
"general": {
|
||||
"section": {
|
||||
"description": "Configurar el comportamiento y la apariencia del Monitor del sistema.",
|
||||
"label": "General"
|
||||
}
|
||||
},
|
||||
"title": "Monitor del sistema"
|
||||
},
|
||||
"user-interface": {
|
||||
"animation-disable": {
|
||||
"description": "Desactiva todas las animaciones para una experiencia más rápida y con mayor capacidad de respuesta.",
|
||||
|
||||
@@ -653,6 +653,7 @@
|
||||
"reboot": "Redémarrer",
|
||||
"shutdown": "Éteindre",
|
||||
"suspend": "Mettre en veille",
|
||||
"hibernate": "Mise en veille prolongée",
|
||||
"title": "Menu de session"
|
||||
},
|
||||
"settings": {
|
||||
@@ -879,7 +880,7 @@
|
||||
"programs": {
|
||||
"code": {
|
||||
"description": "Écrire {filepath}. Le thème Hyprluna doit être installé et activé manuellement.",
|
||||
"description-missing": "Nécessite l'installation de {app}"
|
||||
"description-missing": "Aucun client Code détecté. Installez VSCode ou VSCodium."
|
||||
},
|
||||
"description": "Thématisation spécifique aux applications.",
|
||||
"discord": {
|
||||
@@ -1567,6 +1568,15 @@
|
||||
},
|
||||
"title": "Menu de session"
|
||||
},
|
||||
"system-monitor": {
|
||||
"general": {
|
||||
"section": {
|
||||
"description": "Configurer le comportement et l'apparence du Moniteur Système.",
|
||||
"label": "Général"
|
||||
}
|
||||
},
|
||||
"title": "Moniteur système"
|
||||
},
|
||||
"user-interface": {
|
||||
"animation-disable": {
|
||||
"description": "Désactiver toutes les animations pour une expérience plus rapide et plus réactive.",
|
||||
|
||||
@@ -653,6 +653,7 @@
|
||||
"reboot": "Opnieuw opstarten",
|
||||
"shutdown": "Uitschakelen",
|
||||
"suspend": "Onderbreken",
|
||||
"hibernate": "Slaperstand",
|
||||
"title": "Sessie-menu"
|
||||
},
|
||||
"settings": {
|
||||
@@ -879,7 +880,7 @@
|
||||
"programs": {
|
||||
"code": {
|
||||
"description": "Schrijf {filepath}. Het Hyprluna-thema moet handmatig worden geïnstalleerd en geactiveerd.",
|
||||
"description-missing": "Vereist dat {app} is geïnstalleerd."
|
||||
"description-missing": "Geen Code-client gedetecteerd. Installeer VSCode of VSCodium."
|
||||
},
|
||||
"description": "Toepassingsspecifieke theming.",
|
||||
"discord": {
|
||||
@@ -1567,6 +1568,15 @@
|
||||
},
|
||||
"title": "Sessiemenu"
|
||||
},
|
||||
"system-monitor": {
|
||||
"general": {
|
||||
"section": {
|
||||
"description": "Configureer het gedrag en de weergave van de Systeemmonitor.",
|
||||
"label": "Algemeen"
|
||||
}
|
||||
},
|
||||
"title": "Systeemmonitor"
|
||||
},
|
||||
"user-interface": {
|
||||
"animation-disable": {
|
||||
"description": "Schakel alle animaties uit voor een snellere, responsievere ervaring.",
|
||||
|
||||
@@ -653,6 +653,7 @@
|
||||
"reboot": "Reiniciar",
|
||||
"shutdown": "Desligar",
|
||||
"suspend": "Suspender",
|
||||
"hibernate": "Hibernação",
|
||||
"title": "Menu da Sessão"
|
||||
},
|
||||
"settings": {
|
||||
@@ -879,7 +880,7 @@
|
||||
"programs": {
|
||||
"code": {
|
||||
"description": "Escreva em {filepath}. O tema Hyprluna precisa ser instalado e ativado manualmente.",
|
||||
"description-missing": "Requer que o {app} esteja instalado."
|
||||
"description-missing": "Nenhum cliente Code detectado. Instale VSCode ou VSCodium."
|
||||
},
|
||||
"description": "Tematização específica de aplicativos.",
|
||||
"discord": {
|
||||
@@ -1567,6 +1568,15 @@
|
||||
},
|
||||
"title": "Menu de sessão"
|
||||
},
|
||||
"system-monitor": {
|
||||
"general": {
|
||||
"section": {
|
||||
"description": "Configure o comportamento e a aparência do Monitor do Sistema.",
|
||||
"label": "Geral"
|
||||
}
|
||||
},
|
||||
"title": "Monitor do Sistema"
|
||||
},
|
||||
"user-interface": {
|
||||
"animation-disable": {
|
||||
"description": "Desative todas as animações para uma experiência mais rápida e responsiva.",
|
||||
|
||||
@@ -653,6 +653,7 @@
|
||||
"reboot": "Перезагрузить",
|
||||
"shutdown": "Выключить",
|
||||
"suspend": "Приостановить",
|
||||
"hibernate": "Гибернация",
|
||||
"title": "Меню сеанса"
|
||||
},
|
||||
"settings": {
|
||||
@@ -879,7 +880,7 @@
|
||||
"programs": {
|
||||
"code": {
|
||||
"description": "Записать {filepath}. Тему Hyprluna нужно установить и активировать вручную.",
|
||||
"description-missing": "Требуется установка {app}"
|
||||
"description-missing": "Клиент Code не обнаружен. Установите VSCode или VSCodium."
|
||||
},
|
||||
"description": "Тематика для конкретных приложений.",
|
||||
"discord": {
|
||||
@@ -1567,6 +1568,15 @@
|
||||
},
|
||||
"title": "Меню сеанса"
|
||||
},
|
||||
"system-monitor": {
|
||||
"general": {
|
||||
"section": {
|
||||
"description": "Настроить поведение и внешний вид системного монитора.",
|
||||
"label": "Общее"
|
||||
}
|
||||
},
|
||||
"title": "Системный монитор"
|
||||
},
|
||||
"user-interface": {
|
||||
"animation-disable": {
|
||||
"description": "Отключить все анимации для более быстрого и отзывчивого взаимодействия.",
|
||||
|
||||
@@ -653,6 +653,7 @@
|
||||
"reboot": "Yeniden başlat",
|
||||
"shutdown": "Bilgisayarı kapat",
|
||||
"suspend": "Askıya al",
|
||||
"hibernate": "Hazırda Bekletme",
|
||||
"title": "Oturum Menüsü"
|
||||
},
|
||||
"settings": {
|
||||
@@ -879,7 +880,7 @@
|
||||
"programs": {
|
||||
"code": {
|
||||
"description": "{filepath} dosyasına yaz. Hyprluna temasının kurulu ve manuel olarak etkinleştirilmiş olması gerekir.",
|
||||
"description-missing": "Kurulum için {app} gereklidir"
|
||||
"description-missing": "Code istemcisi tespit edilmedi. VSCode veya VSCodium kurun."
|
||||
},
|
||||
"description": "Uygulamaya özel temalandırma.",
|
||||
"discord": {
|
||||
@@ -1567,6 +1568,15 @@
|
||||
},
|
||||
"title": "Oturum Menüsü"
|
||||
},
|
||||
"system-monitor": {
|
||||
"general": {
|
||||
"section": {
|
||||
"description": "Sistem İzleyicisinin davranışını ve görünümünü yapılandırın.",
|
||||
"label": "Genel"
|
||||
}
|
||||
},
|
||||
"title": "Sistem İzleme"
|
||||
},
|
||||
"user-interface": {
|
||||
"animation-disable": {
|
||||
"description": "Daha hızlı ve daha duyarlı bir deneyim için tüm animasyonları devre dışı bırakın.",
|
||||
|
||||
@@ -653,6 +653,7 @@
|
||||
"reboot": "Перезавантажити",
|
||||
"shutdown": "Вимкнути",
|
||||
"suspend": "Призупинити",
|
||||
"hibernate": "Гібернація",
|
||||
"title": "Меню сеансу"
|
||||
},
|
||||
"settings": {
|
||||
@@ -879,7 +880,7 @@
|
||||
"programs": {
|
||||
"code": {
|
||||
"description": "Записати {filepath}. Тему Hyprluna потрібно встановити та активувати вручну.",
|
||||
"description-missing": "Потрібна установка {app}"
|
||||
"description-missing": "Клієнт Code не виявлено. Встановіть VSCode або VSCodium."
|
||||
},
|
||||
"description": "Оформлення окремих програм.",
|
||||
"discord": {
|
||||
@@ -1567,6 +1568,15 @@
|
||||
},
|
||||
"title": "Меню сеансу"
|
||||
},
|
||||
"system-monitor": {
|
||||
"general": {
|
||||
"section": {
|
||||
"description": "Налаштуйте поведінку та зовнішній вигляд Системного монітора.",
|
||||
"label": "Загальне"
|
||||
}
|
||||
},
|
||||
"title": "Системний монітор"
|
||||
},
|
||||
"user-interface": {
|
||||
"animation-disable": {
|
||||
"description": "Вимкнути всі анімації для швидшого, більш відгукового досвіду.",
|
||||
|
||||
@@ -653,6 +653,7 @@
|
||||
"reboot": "重启",
|
||||
"shutdown": "关机",
|
||||
"suspend": "挂起",
|
||||
"hibernate": "休眠",
|
||||
"title": "会话菜单"
|
||||
},
|
||||
"settings": {
|
||||
@@ -879,7 +880,7 @@
|
||||
"programs": {
|
||||
"code": {
|
||||
"description": "写入 {filepath}。Hyprluna 主题需要手动安装和激活。",
|
||||
"description-missing": "需要安装 {app}"
|
||||
"description-missing": "未检测到 Code 客户端。请安装 VSCode 或 VSCodium。"
|
||||
},
|
||||
"description": "应用程序特定主题。",
|
||||
"discord": {
|
||||
@@ -1474,7 +1475,6 @@
|
||||
"description": "配置屏显菜单(OSD)的可见性与行为。",
|
||||
"label": "常规"
|
||||
}
|
||||
|
||||
},
|
||||
"title": "屏显菜单"
|
||||
},
|
||||
@@ -1568,6 +1568,15 @@
|
||||
},
|
||||
"title": "会话菜单"
|
||||
},
|
||||
"system-monitor": {
|
||||
"general": {
|
||||
"section": {
|
||||
"description": "配置系统监视器的行为和外观。",
|
||||
"label": "通用"
|
||||
}
|
||||
},
|
||||
"title": "系统监视器"
|
||||
},
|
||||
"user-interface": {
|
||||
"animation-disable": {
|
||||
"description": "禁用所有动画以获得更快、更流畅的体验。",
|
||||
|
||||
@@ -219,6 +219,10 @@
|
||||
"action": "suspend",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"action": "hibernate",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"action": "reboot",
|
||||
"enabled": true
|
||||
|
||||
@@ -42,6 +42,7 @@ Singleton {
|
||||
"powersaver": "leaf",
|
||||
"storage": "database",
|
||||
"ethernet": "sitemap",
|
||||
"ethernet-off": "sitemap-off",
|
||||
"keyboard": "keyboard",
|
||||
"shutdown": "power",
|
||||
"lock": "lock",
|
||||
@@ -49,6 +50,7 @@ Singleton {
|
||||
"logout": "logout",
|
||||
"reboot": "refresh",
|
||||
"suspend": "player-pause",
|
||||
"hibernate": "zzz",
|
||||
"nightlight-on": "moon",
|
||||
"nightlight-off": "moon-off",
|
||||
"nightlight-forced": "moon-stars",
|
||||
@@ -123,6 +125,7 @@ Singleton {
|
||||
"settings-about": "info-square-rounded",
|
||||
"settings-lock-screen": "lock",
|
||||
"settings-session-menu": "power",
|
||||
"settings-system-monitor": "activity",
|
||||
"bluetooth": "bluetooth",
|
||||
"bt-device-generic": "bluetooth",
|
||||
"bt-device-headphones": "headphones",
|
||||
|
||||
@@ -352,6 +352,9 @@ Singleton {
|
||||
}, {
|
||||
"action": "suspend",
|
||||
"enabled": true
|
||||
}, {
|
||||
"action": "hibernate",
|
||||
"enabled": true
|
||||
}, {
|
||||
"action": "reboot",
|
||||
"enabled": true
|
||||
@@ -436,12 +439,16 @@ Singleton {
|
||||
property bool spicetify: false
|
||||
property bool enableUserTemplates: false
|
||||
|
||||
property bool code_code: false
|
||||
property bool code_codium: false
|
||||
|
||||
property bool discord_vesktop: false // To be deleted soon
|
||||
property bool discord_webcord: false // To be deleted soon
|
||||
property bool discord_armcord: false // To be deleted soon
|
||||
property bool discord_equibop: false // To be deleted soon
|
||||
property bool discord_lightcord: false // To be deleted soon
|
||||
property bool discord_dorion: false // To be deleted soon
|
||||
property bool discord_vencord: false // To be deleted soon
|
||||
}
|
||||
|
||||
// night light
|
||||
@@ -654,7 +661,7 @@ Singleton {
|
||||
var anyDiscordEnabled = false
|
||||
|
||||
// Check if any Discord client was enabled
|
||||
const discordClients = ["discord_vesktop", "discord_webcord", "discord_armcord", "discord_equibop", "discord_lightcord", "discord_dorion"]
|
||||
const discordClients = ["discord_vesktop", "discord_webcord", "discord_armcord", "discord_equibop", "discord_lightcord", "discord_dorion", "discord_vencord"]
|
||||
|
||||
for (var i = 0; i < discordClients.length; i++) {
|
||||
if (adapter.templates[discordClients[i]]) {
|
||||
|
||||
@@ -8,13 +8,15 @@ import qs.Widgets
|
||||
|
||||
PopupWindow {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
|
||||
property var trayItem: null
|
||||
property var anchorItem: null
|
||||
property real anchorX
|
||||
property real anchorY
|
||||
property bool isSubMenu: false
|
||||
property bool isHovered: rootMouseArea.containsMouse
|
||||
property ShellScreen screen
|
||||
property string widgetSection: ""
|
||||
property int widgetIndex: -1
|
||||
|
||||
@@ -45,7 +47,7 @@ PopupWindow {
|
||||
implicitWidth: menuWidth
|
||||
|
||||
// Use the content height of the Flickable for implicit height
|
||||
implicitHeight: Math.min(screen.height * 0.9, flickable.contentHeight + (Style.marginS * 2))
|
||||
implicitHeight: Math.min(screen?.height * 0.9, flickable.contentHeight + (Style.marginS * 2))
|
||||
visible: false
|
||||
color: Color.transparent
|
||||
anchor.item: anchorItem
|
||||
|
||||
@@ -71,7 +71,7 @@ NIconButton {
|
||||
if (customIconPath !== "")
|
||||
return customIconPath.startsWith("file://") ? customIconPath : "file://" + customIconPath
|
||||
if (useDistroLogo)
|
||||
return DistroService.osLogo
|
||||
return HostService.osLogo
|
||||
return ""
|
||||
}
|
||||
visible: source !== ""
|
||||
|
||||
@@ -33,14 +33,21 @@ Item {
|
||||
}
|
||||
return {}
|
||||
}
|
||||
readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied !== undefined) ? widgetSettings.hideUnoccupied : false
|
||||
readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode
|
||||
readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied !== undefined) ? widgetSettings.hideUnoccupied : widgetMetadata.hideUnoccupied
|
||||
readonly property int characterCount: 2
|
||||
readonly property bool showWorkspaceNumbers: (widgetSettings.showWorkspaceNumbers !== undefined) ? widgetSettings.showWorkspaceNumbers : true
|
||||
readonly property bool showNumbersOnlyWhenOccupied: (widgetSettings.showNumbersOnlyWhenOccupied !== undefined) ? widgetSettings.showNumbersOnlyWhenOccupied : true
|
||||
readonly property bool colorizeIcons: (widgetSettings.colorizeIcons !== undefined) ? widgetSettings.colorizeIcons : widgetMetadata.colorizeIcons
|
||||
property ListModel localWorkspaces: ListModel {}
|
||||
property real masterProgress: 0.0
|
||||
property bool effectsActive: false
|
||||
property color effectColor: Color.mPrimary
|
||||
|
||||
// Wheel scroll handling
|
||||
property int wheelAccumulatedDelta: 0
|
||||
property bool wheelCooldown: false
|
||||
|
||||
function refreshWorkspaces() {
|
||||
localWorkspaces.clear()
|
||||
if (!screen)
|
||||
@@ -80,11 +87,34 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
function getFocusedLocalIndex() {
|
||||
for (var i = 0; i < localWorkspaces.count; i++) {
|
||||
if (localWorkspaces.get(i).isFocused === true)
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
function switchByOffset(offset) {
|
||||
if (localWorkspaces.count === 0)
|
||||
return
|
||||
var current = getFocusedLocalIndex()
|
||||
if (current < 0)
|
||||
current = 0
|
||||
var next = (current + offset) % localWorkspaces.count
|
||||
if (next < 0)
|
||||
next = localWorkspaces.count - 1
|
||||
const ws = localWorkspaces.get(next)
|
||||
if (ws && ws.idx !== undefined)
|
||||
CompositorService.switchToWorkspace(ws)
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
refreshWorkspaces()
|
||||
}
|
||||
|
||||
onScreenChanged: refreshWorkspaces()
|
||||
onHideUnoccupiedChanged: refreshWorkspaces()
|
||||
|
||||
implicitWidth: isVerticalBar ? taskbarGrid.implicitWidth + Style.marginM * 2 : Math.round(taskbarGrid.implicitWidth + Style.marginM * 2)
|
||||
implicitHeight: isVerticalBar ? Math.round(taskbarGrid.implicitHeight + Style.marginM * 2) : Style.barHeight
|
||||
@@ -128,6 +158,46 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Debounce timer for wheel interactions
|
||||
Timer {
|
||||
id: wheelDebounce
|
||||
interval: 150
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
root.wheelCooldown = false
|
||||
root.wheelAccumulatedDelta = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll to switch workspaces
|
||||
WheelHandler {
|
||||
id: wheelHandler
|
||||
target: root
|
||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||
onWheel: function (event) {
|
||||
if (root.wheelCooldown)
|
||||
return
|
||||
// Prefer vertical delta, fall back to horizontal if needed
|
||||
var dy = event.angleDelta.y
|
||||
var dx = event.angleDelta.x
|
||||
var useDy = Math.abs(dy) >= Math.abs(dx)
|
||||
var delta = useDy ? dy : dx
|
||||
// One notch is typically 120
|
||||
root.wheelAccumulatedDelta += delta
|
||||
var step = 120
|
||||
if (Math.abs(root.wheelAccumulatedDelta) >= step) {
|
||||
var direction = root.wheelAccumulatedDelta > 0 ? -1 : 1
|
||||
// For vertical layout, natural mapping: wheel up -> previous, down -> next (already handled by sign)
|
||||
// For horizontal layout, same mapping using vertical wheel
|
||||
root.switchByOffset(direction)
|
||||
root.wheelCooldown = true
|
||||
wheelDebounce.restart()
|
||||
root.wheelAccumulatedDelta = 0
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: workspaceRepeaterDelegate
|
||||
|
||||
@@ -192,7 +262,7 @@ Item {
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
opacity: model.isFocused ? Style.opacityFull : 0.6
|
||||
layer.enabled: widgetSettings.colorizeIcons === true
|
||||
layer.enabled: root.colorizeIcons && !model.isFocused
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
@@ -252,7 +322,7 @@ Item {
|
||||
Item {
|
||||
id: workspaceNumberContainer
|
||||
|
||||
visible: root.showWorkspaceNumbers && (!root.showNumbersOnlyWhenOccupied || container.hasWindows)
|
||||
visible: root.labelMode !== "none" && root.showWorkspaceNumbers && (!root.showNumbersOnlyWhenOccupied || container.hasWindows)
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
@@ -318,7 +388,13 @@ Item {
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
text: workspaceModel.idx.toString()
|
||||
text: {
|
||||
if (root.labelMode === "name" && workspaceModel.name && workspaceModel.name.length > 0) {
|
||||
return workspaceModel.name.substring(0, root.characterCount)
|
||||
} else {
|
||||
return workspaceModel.idx.toString()
|
||||
}
|
||||
}
|
||||
|
||||
family: Settings.data.ui.fontFixed
|
||||
font {
|
||||
|
||||
@@ -396,8 +396,8 @@ Rectangle {
|
||||
density: Settings.data.bar.density
|
||||
baseSize: Style.capsuleHeight
|
||||
applyUiScale: false
|
||||
colorBg: Settings.data.colorSchemes.darkMode ? (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) : Color.mPrimary
|
||||
colorFg: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary
|
||||
colorBg: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
|
||||
colorFg: Color.mOnSurface
|
||||
colorBorder: Color.transparent
|
||||
colorBorderHover: Color.transparent
|
||||
icon: {
|
||||
|
||||
@@ -41,7 +41,7 @@ Item {
|
||||
icon: {
|
||||
try {
|
||||
if (NetworkService.ethernetConnected) {
|
||||
return "ethernet"
|
||||
return NetworkService.internetConnectivity ? "ethernet" : "ethernet-off"
|
||||
}
|
||||
let connected = false
|
||||
let signalStrength = 0
|
||||
@@ -55,7 +55,7 @@ Item {
|
||||
return connected ? NetworkService.signalIcon(signalStrength, true) : "wifi-off"
|
||||
} catch (error) {
|
||||
Logger.e("Wi-Fi", "Error getting icon:", error)
|
||||
return "signal_wifi_bad"
|
||||
return "wifi-off"
|
||||
}
|
||||
}
|
||||
text: {
|
||||
|
||||
@@ -1188,6 +1188,54 @@ Loader {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Settings.data.general.compactLockScreen ? 36 : 48
|
||||
radius: Settings.data.general.compactLockScreen ? 18 : 24
|
||||
color: hibernateButtonArea.containsMouse ? Color.mHover : "transparent"
|
||||
border.color: Color.mOutline
|
||||
border.width: 1
|
||||
|
||||
RowLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: 6
|
||||
|
||||
NIcon {
|
||||
icon: "hibernate"
|
||||
pointSize: Settings.data.general.compactLockScreen ? Style.fontSizeM : Style.fontSizeL
|
||||
color: hibernateButtonArea.containsMouse ? Color.mOnHover : Color.mOnSurfaceVariant
|
||||
}
|
||||
|
||||
NText {
|
||||
text: I18n.tr("session-menu.hibernate")
|
||||
pointSize: Settings.data.general.compactLockScreen ? Style.fontSizeS : Style.fontSizeM
|
||||
color: hibernateButtonArea.containsMouse ? Color.mOnHover : Color.mOnSurfaceVariant
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: hibernateButtonArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: CompositorService.hibernate()
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: Settings.data.general.compactLockScreen ? 36 : 48
|
||||
|
||||
@@ -23,6 +23,8 @@ Item {
|
||||
// Reference to MainScreen (for panel access)
|
||||
required property var windowRoot
|
||||
|
||||
readonly property color panelBackgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
// Wrapper with layer caching for better shadow performance
|
||||
@@ -69,91 +71,91 @@ Item {
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.audioPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Battery
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.batteryPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Bluetooth
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.bluetoothPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Calendar
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.calendarPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Control Center
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.controlCenterPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Launcher
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.launcherPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Notification History
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.notificationHistoryPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Session Menu
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.sessionMenuPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Settings
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.settingsPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Setup Wizard
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.setupWizardPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// TrayDrawer
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.trayDrawerPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// Wallpaper
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.wallpaperPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
|
||||
// WiFi
|
||||
PanelBackground {
|
||||
panel: root.windowRoot.wifiPanelPlaceholder
|
||||
shapeContainer: backgroundsShape
|
||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.ui.panelBackgroundOpacity)
|
||||
backgroundColor: panelBackgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ PanelWindow {
|
||||
|
||||
// Wayland
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
WlrLayershell.namespace: "noctalia-screen-" + (screen?.name || "unknown")
|
||||
WlrLayershell.namespace: "noctalia-background-" + (screen?.name || "unknown")
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore // Don't reserve space - BarExclusionZone handles that
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
|
||||
@@ -15,8 +15,6 @@ import qs.Services.UI
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// PUBLIC API - unchanged for backward compatibility
|
||||
|
||||
// Screen property provided by MainScreen
|
||||
property ShellScreen screen: null
|
||||
|
||||
@@ -63,7 +61,7 @@ Item {
|
||||
// Note: SmartPanelWindow directly calls these functions via panelWrapper reference
|
||||
function onEscapePressed() {}
|
||||
function onTabPressed() {}
|
||||
function onShiftTabPressed() {}
|
||||
function onBackTabPressed() {}
|
||||
function onUpPressed() {}
|
||||
function onDownPressed() {}
|
||||
function onLeftPressed() {}
|
||||
|
||||
@@ -191,12 +191,11 @@ PanelWindow {
|
||||
} else if (event.key === Qt.Key_Right && panelWrapper.onRightPressed) {
|
||||
panelWrapper.onRightPressed()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Tab) {
|
||||
if (event.modifiers & Qt.ShiftModifier && panelWrapper.onShiftTabPressed) {
|
||||
panelWrapper.onShiftTabPressed()
|
||||
} else if (panelWrapper.onTabPressed) {
|
||||
panelWrapper.onTabPressed()
|
||||
}
|
||||
} else if (event.key === Qt.Key_Tab && panelWrapper.onTabPressed) {
|
||||
panelWrapper.onTabPressed()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Backtab && panelWrapper.onBackTabPressed) {
|
||||
panelWrapper.onBackTabPressed()
|
||||
event.accepted = true
|
||||
} else if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && panelWrapper.onReturnPressed) {
|
||||
panelWrapper.onReturnPressed()
|
||||
|
||||
+112
-112
@@ -49,83 +49,83 @@ Variants {
|
||||
function getIcon() {
|
||||
if (currentOSDType === "volume") {
|
||||
if (AudioService.muted) {
|
||||
return "volume-mute";
|
||||
return "volume-mute"
|
||||
}
|
||||
return (AudioService.volume <= Number.EPSILON) ? "volume-zero" : (AudioService.volume <= 0.5) ? "volume-low" : "volume-high";
|
||||
return (AudioService.volume <= Number.EPSILON) ? "volume-zero" : (AudioService.volume <= 0.5) ? "volume-low" : "volume-high"
|
||||
} else if (currentOSDType === "inputVolume") {
|
||||
if (AudioService.inputMuted) {
|
||||
return "microphone-off";
|
||||
return "microphone-off"
|
||||
}
|
||||
return "microphone";
|
||||
return "microphone"
|
||||
} else if (currentOSDType === "brightness") {
|
||||
return currentBrightness <= 0.5 ? "brightness-low" : "brightness-high";
|
||||
return currentBrightness <= 0.5 ? "brightness-low" : "brightness-high"
|
||||
}
|
||||
return "";
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get current value (0-1 range)
|
||||
function getCurrentValue() {
|
||||
if (currentOSDType === "volume") {
|
||||
return isMuted ? 0 : currentVolume;
|
||||
return isMuted ? 0 : currentVolume
|
||||
} else if (currentOSDType === "inputVolume") {
|
||||
return isInputMuted ? 0 : currentInputVolume;
|
||||
return isInputMuted ? 0 : currentInputVolume
|
||||
} else if (currentOSDType === "brightness") {
|
||||
return currentBrightness;
|
||||
return currentBrightness
|
||||
}
|
||||
return 0;
|
||||
return 0
|
||||
}
|
||||
|
||||
// Get maximum value for current OSD type
|
||||
function getMaxValue() {
|
||||
if (currentOSDType === "volume" || currentOSDType === "inputVolume") {
|
||||
return Settings.data.audio.volumeOverdrive ? 1.5 : 1.0;
|
||||
return Settings.data.audio.volumeOverdrive ? 1.5 : 1.0
|
||||
} else if (currentOSDType === "brightness") {
|
||||
return 1.0;
|
||||
return 1.0
|
||||
}
|
||||
return 1.0;
|
||||
return 1.0
|
||||
}
|
||||
|
||||
// Get display percentage
|
||||
function getDisplayPercentage() {
|
||||
if (currentOSDType === "volume") {
|
||||
if (isMuted)
|
||||
return "0%";
|
||||
const max = getMaxValue();
|
||||
const pct = Math.round(Math.min(max, currentVolume) * 100);
|
||||
return pct + "%";
|
||||
return "0%"
|
||||
const max = getMaxValue()
|
||||
const pct = Math.round(Math.min(max, currentVolume) * 100)
|
||||
return pct + "%"
|
||||
} else if (currentOSDType === "inputVolume") {
|
||||
if (isInputMuted)
|
||||
return "0%";
|
||||
const max = getMaxValue();
|
||||
const pct = Math.round(Math.min(max, currentInputVolume) * 100);
|
||||
return pct + "%";
|
||||
return "0%"
|
||||
const max = getMaxValue()
|
||||
const pct = Math.round(Math.min(max, currentInputVolume) * 100)
|
||||
return pct + "%"
|
||||
} else if (currentOSDType === "brightness") {
|
||||
const pct = Math.round(Math.min(1.0, currentBrightness) * 100);
|
||||
return pct + "%";
|
||||
const pct = Math.round(Math.min(1.0, currentBrightness) * 100)
|
||||
return pct + "%"
|
||||
}
|
||||
return "";
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get progress bar color
|
||||
function getProgressColor() {
|
||||
if (currentOSDType === "volume") {
|
||||
if (isMuted)
|
||||
return Color.mError;
|
||||
return Color.mPrimary;
|
||||
return Color.mError
|
||||
return Color.mPrimary
|
||||
} else if (currentOSDType === "inputVolume") {
|
||||
if (isInputMuted)
|
||||
return Color.mError;
|
||||
return Color.mPrimary;
|
||||
return Color.mError
|
||||
return Color.mPrimary
|
||||
}
|
||||
return Color.mPrimary;
|
||||
return Color.mPrimary
|
||||
}
|
||||
|
||||
// Get icon color
|
||||
function getIconColor() {
|
||||
if ((currentOSDType === "volume" && isMuted) || (currentOSDType === "inputVolume" && isInputMuted)) {
|
||||
return Color.mError;
|
||||
return Color.mError
|
||||
}
|
||||
return Color.mOnSurface;
|
||||
return Color.mOnSurface
|
||||
}
|
||||
|
||||
sourceComponent: PanelWindow {
|
||||
@@ -146,8 +146,8 @@ Variants {
|
||||
|
||||
// Ensure an even width to keep the vertical bar perfectly centered
|
||||
readonly property int barThickness: {
|
||||
const base = Math.max(8, Math.round(8 * Style.uiScaleRatio));
|
||||
return (base % 2 === 0) ? base : base + 1;
|
||||
const base = Math.max(8, Math.round(8 * Style.uiScaleRatio))
|
||||
return (base % 2 === 0) ? base : base + 1
|
||||
}
|
||||
|
||||
// Anchor selection based on location (window edges)
|
||||
@@ -159,46 +159,46 @@ Variants {
|
||||
// Margins depending on bar position and chosen location
|
||||
margins.top: {
|
||||
if (!(anchors.top))
|
||||
return 0;
|
||||
var base = Style.marginM;
|
||||
return 0
|
||||
var base = Style.marginM
|
||||
if (Settings.data.bar.position === "top") {
|
||||
var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0;
|
||||
return Style.barHeight + base + floatExtraV;
|
||||
var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0
|
||||
return Style.barHeight + base + floatExtraV
|
||||
}
|
||||
return base;
|
||||
return base
|
||||
}
|
||||
|
||||
margins.bottom: {
|
||||
if (!(anchors.bottom))
|
||||
return 0;
|
||||
var base = Style.marginM;
|
||||
return 0
|
||||
var base = Style.marginM
|
||||
if (Settings.data.bar.position === "bottom") {
|
||||
var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0;
|
||||
return Style.barHeight + base + floatExtraV;
|
||||
var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0
|
||||
return Style.barHeight + base + floatExtraV
|
||||
}
|
||||
return base;
|
||||
return base
|
||||
}
|
||||
|
||||
margins.left: {
|
||||
if (!(anchors.left))
|
||||
return 0;
|
||||
var base = Style.marginM;
|
||||
return 0
|
||||
var base = Style.marginM
|
||||
if (Settings.data.bar.position === "left") {
|
||||
var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0;
|
||||
return Style.barHeight + base + floatExtraH;
|
||||
var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
|
||||
return Style.barHeight + base + floatExtraH
|
||||
}
|
||||
return base;
|
||||
return base
|
||||
}
|
||||
|
||||
margins.right: {
|
||||
if (!(anchors.right))
|
||||
return 0;
|
||||
var base = Style.marginM;
|
||||
return 0
|
||||
var base = Style.marginM
|
||||
if (Settings.data.bar.position === "right") {
|
||||
var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0;
|
||||
return Style.barHeight + base + floatExtraH;
|
||||
var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
|
||||
return Style.barHeight + base + floatExtraH
|
||||
}
|
||||
return base;
|
||||
return base
|
||||
}
|
||||
|
||||
implicitWidth: verticalMode ? vWidth : hWidth
|
||||
@@ -249,10 +249,10 @@ Variants {
|
||||
id: visibilityTimer
|
||||
interval: Style.animationNormal + 50 // Add small buffer
|
||||
onTriggered: {
|
||||
osdItem.visible = false;
|
||||
root.currentOSDType = "";
|
||||
osdItem.visible = false
|
||||
root.currentOSDType = ""
|
||||
// Deactivate the loader when done
|
||||
root.active = false;
|
||||
root.active = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,8 +265,8 @@ Variants {
|
||||
color: Qt.alpha(Color.mSurface, Settings.data.osd.backgroundOpacity || 1.0)
|
||||
border.color: Qt.alpha(Color.mOutline, Settings.data.osd.backgroundOpacity || 1.0)
|
||||
border.width: {
|
||||
const bw = Math.max(2, Style.borderM);
|
||||
return (bw % 2 === 0) ? bw : bw + 1;
|
||||
const bw = Math.max(2, Style.borderM)
|
||||
return (bw % 2 === 0) ? bw : bw + 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -365,9 +365,9 @@ Variants {
|
||||
ColumnLayout {
|
||||
// Ensure inner padding respects the rounded corners; avoid clipping the icon/text
|
||||
property int vMargin: {
|
||||
const styleMargin = Style.marginL;
|
||||
const cornerGuard = Math.round(osdItem.radius);
|
||||
return Math.max(styleMargin, cornerGuard);
|
||||
const styleMargin = Style.marginL
|
||||
const cornerGuard = Math.round(osdItem.radius)
|
||||
return Math.max(styleMargin, cornerGuard)
|
||||
}
|
||||
property int vMarginTop: Math.round(Math.max(osdItem.radius, Style.marginS))
|
||||
property int balanceDelta: Style.marginS
|
||||
@@ -449,46 +449,46 @@ Variants {
|
||||
|
||||
function show() {
|
||||
// Cancel any pending hide operations
|
||||
hideTimer.stop();
|
||||
visibilityTimer.stop();
|
||||
hideTimer.stop()
|
||||
visibilityTimer.stop()
|
||||
|
||||
// Make visible and animate in
|
||||
osdItem.visible = true;
|
||||
osdItem.visible = true
|
||||
// Use Qt.callLater to ensure the visible change is processed before animation
|
||||
Qt.callLater(() => {
|
||||
osdItem.opacity = 1;
|
||||
osdItem.scale = 1.0;
|
||||
});
|
||||
osdItem.opacity = 1
|
||||
osdItem.scale = 1.0
|
||||
})
|
||||
|
||||
// Start the auto-hide timer
|
||||
hideTimer.start();
|
||||
hideTimer.start()
|
||||
}
|
||||
|
||||
function hide() {
|
||||
hideTimer.stop();
|
||||
visibilityTimer.stop();
|
||||
hideTimer.stop()
|
||||
visibilityTimer.stop()
|
||||
|
||||
// Start fade out animation
|
||||
osdItem.opacity = 0;
|
||||
osdItem.scale = 0.85; // Less dramatic scale change for smoother effect
|
||||
osdItem.opacity = 0
|
||||
osdItem.scale = 0.85 // Less dramatic scale change for smoother effect
|
||||
|
||||
// Delay hiding the element until after animation completes
|
||||
visibilityTimer.start();
|
||||
visibilityTimer.start()
|
||||
}
|
||||
|
||||
function hideImmediately() {
|
||||
hideTimer.stop();
|
||||
visibilityTimer.stop();
|
||||
osdItem.opacity = 0;
|
||||
osdItem.scale = 0.85;
|
||||
osdItem.visible = false;
|
||||
root.currentOSDType = "";
|
||||
root.active = false;
|
||||
hideTimer.stop()
|
||||
visibilityTimer.stop()
|
||||
osdItem.opacity = 0
|
||||
osdItem.scale = 0.85
|
||||
osdItem.visible = false
|
||||
root.currentOSDType = ""
|
||||
root.active = false
|
||||
}
|
||||
}
|
||||
|
||||
function showOSD() {
|
||||
osdItem.show();
|
||||
osdItem.show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,34 +498,34 @@ Variants {
|
||||
|
||||
function onVolumeChanged() {
|
||||
if (volumeInitialized) {
|
||||
showOSD("volume");
|
||||
showOSD("volume")
|
||||
}
|
||||
}
|
||||
|
||||
function onMutedChanged() {
|
||||
if (muteInitialized) {
|
||||
showOSD("volume");
|
||||
showOSD("volume")
|
||||
}
|
||||
}
|
||||
|
||||
function onInputVolumeChanged() {
|
||||
if (!inputAudioInitialized) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (!AudioService.hasInput) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
showOSD("inputVolume");
|
||||
showOSD("inputVolume")
|
||||
}
|
||||
|
||||
function onInputMutedChanged() {
|
||||
if (!inputAudioInitialized) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (!AudioService.hasInput) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
showOSD("inputVolume");
|
||||
showOSD("inputVolume")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,11 +535,11 @@ Variants {
|
||||
interval: 500
|
||||
running: true
|
||||
onTriggered: {
|
||||
volumeInitialized = true;
|
||||
muteInitialized = true;
|
||||
inputAudioInitialized = true;
|
||||
volumeInitialized = true
|
||||
muteInitialized = true
|
||||
inputAudioInitialized = true
|
||||
// Brightness initializes on first change to avoid showing OSD on startup
|
||||
connectBrightnessMonitors();
|
||||
connectBrightnessMonitors()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -548,65 +548,65 @@ Variants {
|
||||
target: BrightnessService
|
||||
|
||||
function onMonitorsChanged() {
|
||||
connectBrightnessMonitors();
|
||||
connectBrightnessMonitors()
|
||||
}
|
||||
}
|
||||
|
||||
function disconnectBrightnessMonitors() {
|
||||
for (var i = 0; i < BrightnessService.monitors.length; i++) {
|
||||
let monitor = BrightnessService.monitors[i];
|
||||
monitor.brightnessUpdated.disconnect(onBrightnessChanged);
|
||||
let monitor = BrightnessService.monitors[i]
|
||||
monitor.brightnessUpdated.disconnect(onBrightnessChanged)
|
||||
}
|
||||
}
|
||||
|
||||
function connectBrightnessMonitors() {
|
||||
for (var i = 0; i < BrightnessService.monitors.length; i++) {
|
||||
let monitor = BrightnessService.monitors[i];
|
||||
let monitor = BrightnessService.monitors[i]
|
||||
// Disconnect first to avoid duplicate connections
|
||||
monitor.brightnessUpdated.disconnect(onBrightnessChanged);
|
||||
monitor.brightnessUpdated.connect(onBrightnessChanged);
|
||||
monitor.brightnessUpdated.disconnect(onBrightnessChanged)
|
||||
monitor.brightnessUpdated.connect(onBrightnessChanged)
|
||||
}
|
||||
}
|
||||
|
||||
function onBrightnessChanged(newBrightness) {
|
||||
root.lastUpdatedBrightness = newBrightness;
|
||||
root.lastUpdatedBrightness = newBrightness
|
||||
|
||||
if (!brightnessInitialized) {
|
||||
brightnessInitialized = true;
|
||||
return;
|
||||
brightnessInitialized = true
|
||||
return
|
||||
}
|
||||
|
||||
showOSD("brightness");
|
||||
showOSD("brightness")
|
||||
}
|
||||
|
||||
function showOSD(type) {
|
||||
// Update the current OSD type
|
||||
currentOSDType = type;
|
||||
currentOSDType = type
|
||||
|
||||
// Activate the loader if not already active
|
||||
if (!root.active) {
|
||||
root.active = true;
|
||||
root.active = true
|
||||
}
|
||||
|
||||
// Show the OSD (may need to wait for loader to create the item)
|
||||
if (root.item) {
|
||||
root.item.showOSD();
|
||||
root.item.showOSD()
|
||||
} else {
|
||||
// If item not ready yet, wait for it
|
||||
Qt.callLater(() => {
|
||||
if (root.item) {
|
||||
root.item.showOSD();
|
||||
}
|
||||
});
|
||||
if (root.item) {
|
||||
root.item.showOSD()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function hideOSD() {
|
||||
if (root.item && root.item.osdItem) {
|
||||
root.item.osdItem.hideImmediately();
|
||||
root.item.osdItem.hideImmediately()
|
||||
} else if (root.active) {
|
||||
// If loader is active but item isn't ready, just deactivate
|
||||
root.active = false;
|
||||
root.active = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ NIconButtonHot {
|
||||
icon: {
|
||||
try {
|
||||
if (NetworkService.ethernetConnected) {
|
||||
return "ethernet"
|
||||
return NetworkService.internetConnectivity ? "ethernet" : "ethernet-off"
|
||||
}
|
||||
let connected = false
|
||||
let signalStrength = 0
|
||||
@@ -25,7 +25,7 @@ NIconButtonHot {
|
||||
return connected ? NetworkService.signalIcon(signalStrength, true) : "wifi-off"
|
||||
} catch (error) {
|
||||
Logger.e("Wi-Fi", "Error getting icon:", error)
|
||||
return "signal_wifi_bad"
|
||||
return "wifi-off"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,12 +50,15 @@ SmartPanel {
|
||||
readonly property int badgeSize: Math.round(Style.baseWidgetSize * 1.6)
|
||||
readonly property int entryHeight: Math.round(badgeSize + Style.marginM * 2)
|
||||
|
||||
// Override keyboard handlers from SmartPanel for navigation
|
||||
// Override keyboard handlers from SmartPanel for navigation.
|
||||
// Launcher specific: onTabPressed() and onBackTabPressed() are special here.
|
||||
// They are not coming from SmartPanelWindow as they are consumed by the search field before reaching the panel.
|
||||
// They are instead being forwared from the search field NTextInput below.
|
||||
function onTabPressed() {
|
||||
selectNextWrapped()
|
||||
}
|
||||
|
||||
function onShiftTabPressed() {
|
||||
function onBackTabPressed() {
|
||||
selectPreviousWrapped()
|
||||
}
|
||||
|
||||
@@ -346,6 +349,16 @@ SmartPanel {
|
||||
Component.onCompleted: {
|
||||
if (searchInput.inputItem) {
|
||||
searchInput.inputItem.forceActiveFocus()
|
||||
// Intercept Tab keys before TextField handles them
|
||||
searchInput.inputItem.Keys.onPressed.connect(function (event) {
|
||||
if (event.key === Qt.Key_Tab) {
|
||||
root.onTabPressed()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Backtab) {
|
||||
root.onBackTabPressed()
|
||||
event.accepted = true
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,11 @@ SmartPanel {
|
||||
"title": I18n.tr("session-menu.suspend"),
|
||||
"isShutdown": false
|
||||
},
|
||||
"hibernate": {
|
||||
"icon": "hibernate",
|
||||
"title": I18n.tr("session-menu.hibernate"),
|
||||
"isShutdown": false
|
||||
},
|
||||
"reboot": {
|
||||
"icon": "reboot",
|
||||
"title": I18n.tr("session-menu.reboot"),
|
||||
@@ -159,6 +164,9 @@ SmartPanel {
|
||||
CompositorService.suspend()
|
||||
}
|
||||
break
|
||||
case "hibernate":
|
||||
CompositorService.hibernate()
|
||||
break
|
||||
case "reboot":
|
||||
CompositorService.reboot()
|
||||
break
|
||||
@@ -220,7 +228,7 @@ SmartPanel {
|
||||
selectNextWrapped()
|
||||
}
|
||||
|
||||
function onShiftTabPressed() {
|
||||
function onBackTabPressed() {
|
||||
selectPreviousWrapped()
|
||||
}
|
||||
|
||||
|
||||
@@ -12,16 +12,56 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
property bool valueShowWorkspaceNumbers: widgetData.showWorkspaceNumbers !== undefined ? widgetData.showWorkspaceNumbers : widgetMetadata.showWorkspaceNumbers
|
||||
property bool valueShowNumbersOnlyWhenOccupied: widgetData.showNumbersOnlyWhenOccupied !== undefined ? widgetData.showNumbersOnlyWhenOccupied : widgetMetadata.showNumbersOnlyWhenOccupied
|
||||
property string valueLabelMode: widgetData.labelMode !== undefined ? widgetData.labelMode : (widgetMetadata ? widgetMetadata.labelMode : "index")
|
||||
property bool valueHideUnoccupied: widgetData.hideUnoccupied !== undefined ? widgetData.hideUnoccupied : (widgetMetadata ? widgetMetadata.hideUnoccupied : false)
|
||||
property bool valueShowWorkspaceNumbers: widgetData.showWorkspaceNumbers !== undefined ? widgetData.showWorkspaceNumbers : (widgetMetadata ? widgetMetadata.showWorkspaceNumbers : true)
|
||||
property bool valueShowNumbersOnlyWhenOccupied: widgetData.showNumbersOnlyWhenOccupied !== undefined ? widgetData.showNumbersOnlyWhenOccupied : (widgetMetadata ? widgetMetadata.showNumbersOnlyWhenOccupied : true)
|
||||
property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : (widgetMetadata ? widgetMetadata.colorizeIcons : false)
|
||||
|
||||
function saveSettings() {
|
||||
var settings = Object.assign({}, widgetData || {})
|
||||
settings.labelMode = valueLabelMode
|
||||
settings.hideUnoccupied = valueHideUnoccupied
|
||||
settings.showWorkspaceNumbers = valueShowWorkspaceNumbers
|
||||
settings.showNumbersOnlyWhenOccupied = valueShowNumbersOnlyWhenOccupied
|
||||
settings.colorizeIcons = valueColorizeIcons
|
||||
return settings
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
id: labelModeCombo
|
||||
label: I18n.tr("bar.widget-settings.workspace.label-mode.label")
|
||||
description: I18n.tr("bar.widget-settings.workspace.label-mode.description")
|
||||
model: [{
|
||||
"key": "none",
|
||||
"name": I18n.tr("options.workspace-labels.none")
|
||||
}, {
|
||||
"key": "index",
|
||||
"name": I18n.tr("options.workspace-labels.index")
|
||||
}, {
|
||||
"key": "name",
|
||||
"name": I18n.tr("options.workspace-labels.name")
|
||||
}]
|
||||
currentKey: widgetData.labelMode || widgetMetadata.labelMode
|
||||
onSelected: key => valueLabelMode = key
|
||||
minimumWidth: 200
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.widget-settings.workspace.hide-unoccupied.label")
|
||||
description: I18n.tr("bar.widget-settings.workspace.hide-unoccupied.description")
|
||||
checked: valueHideUnoccupied
|
||||
onToggled: checked => valueHideUnoccupied = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.widget-settings.active-window.colorize-icons.label")
|
||||
description: I18n.tr("bar.widget-settings.active-window.colorize-icons.description")
|
||||
checked: root.valueColorizeIcons
|
||||
onToggled: checked => root.valueColorizeIcons = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.widget-settings.taskbar-grouped.show-workspace-numbers.label")
|
||||
|
||||
@@ -77,6 +77,7 @@ SmartPanel {
|
||||
Notifications,
|
||||
ScreenRecorder,
|
||||
SessionMenu,
|
||||
SystemMonitor,
|
||||
UserInterface,
|
||||
Wallpaper
|
||||
}
|
||||
@@ -166,6 +167,10 @@ SmartPanel {
|
||||
id: sessionMenuTab
|
||||
SessionMenuTab {}
|
||||
}
|
||||
Component {
|
||||
id: systemMonitorTab
|
||||
SystemMonitorTab {}
|
||||
}
|
||||
|
||||
// Order *DOES* matter
|
||||
function updateTabsModel() {
|
||||
@@ -179,31 +184,56 @@ SmartPanel {
|
||||
"label": "settings.user-interface.title",
|
||||
"icon": "settings-user-interface",
|
||||
"source": userInterfaceTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.ColorScheme,
|
||||
"label": "settings.color-scheme.title",
|
||||
"icon": "settings-color-scheme",
|
||||
"source": colorSchemeTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.Wallpaper,
|
||||
"label": "settings.wallpaper.title",
|
||||
"icon": "settings-wallpaper",
|
||||
"source": wallpaperTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.Bar,
|
||||
"label": "settings.bar.title",
|
||||
"icon": "settings-bar",
|
||||
"source": barTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.ControlCenter,
|
||||
"label": "settings.control-center.title",
|
||||
"icon": "settings-control-center",
|
||||
"source": controlCenterTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.Dock,
|
||||
"label": "settings.dock.title",
|
||||
"icon": "settings-dock",
|
||||
"source": dockTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.ControlCenter,
|
||||
"label": "settings.control-center.title",
|
||||
"icon": "settings-control-center",
|
||||
"source": controlCenterTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.Launcher,
|
||||
"label": "settings.launcher.title",
|
||||
"icon": "settings-launcher",
|
||||
"source": launcherTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.Notifications,
|
||||
"label": "settings.notifications.title",
|
||||
"icon": "settings-notifications",
|
||||
"source": notificationsTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.OSD,
|
||||
"label": "settings.osd.title",
|
||||
"icon": "settings-osd",
|
||||
"source": osdTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.LockScreen,
|
||||
"label": "settings.lock-screen.title",
|
||||
"icon": "settings-lock-screen",
|
||||
"source": lockScreenTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.SessionMenu,
|
||||
"label": "settings.session-menu.title",
|
||||
"icon": "settings-session-menu",
|
||||
"source": sessionMenuTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.Audio,
|
||||
"label": "settings.audio.title",
|
||||
@@ -214,16 +244,6 @@ SmartPanel {
|
||||
"label": "settings.display.title",
|
||||
"icon": "settings-display",
|
||||
"source": displayTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.OSD,
|
||||
"label": "settings.osd.title",
|
||||
"icon": "settings-osd",
|
||||
"source": osdTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.Notifications,
|
||||
"label": "settings.notifications.title",
|
||||
"icon": "settings-notifications",
|
||||
"source": notificationsTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.Network,
|
||||
"label": "settings.network.title",
|
||||
@@ -234,31 +254,27 @@ SmartPanel {
|
||||
"label": "settings.location.title",
|
||||
"icon": "settings-location",
|
||||
"source": locationTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.ColorScheme,
|
||||
"label": "settings.color-scheme.title",
|
||||
"icon": "settings-color-scheme",
|
||||
"source": colorSchemeTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.Wallpaper,
|
||||
"label": "settings.wallpaper.title",
|
||||
"icon": "settings-wallpaper",
|
||||
"source": wallpaperTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.ScreenRecorder,
|
||||
"label": "settings.screen-recorder.title",
|
||||
"icon": "settings-screen-recorder",
|
||||
"source": screenRecorderTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.Hooks,
|
||||
"label": "settings.hooks.title",
|
||||
"icon": "settings-hooks",
|
||||
"source": hooksTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.SessionMenu,
|
||||
"label": "settings.session-menu.title",
|
||||
"icon": "settings-session-menu",
|
||||
"source": sessionMenuTab
|
||||
}, // {
|
||||
// "id": SettingsPanel.Tab.SystemMonitor,
|
||||
// "label": "settings.system-monitor.title",
|
||||
// "icon": "settings-system-monitor",
|
||||
// "source": systemMonitorTab
|
||||
// },
|
||||
{
|
||||
"id": SettingsPanel.Tab.Hooks,
|
||||
"label": "settings.hooks.title",
|
||||
"icon": "settings-hooks",
|
||||
"source": hooksTab
|
||||
}, {
|
||||
"id": SettingsPanel.Tab.About,
|
||||
"label": "settings.about.title",
|
||||
@@ -340,7 +356,7 @@ SmartPanel {
|
||||
selectNextTab()
|
||||
}
|
||||
|
||||
function onShiftTabPressed() {
|
||||
function onBackTabPressed() {
|
||||
selectPreviousTab()
|
||||
}
|
||||
|
||||
@@ -401,14 +417,14 @@ SmartPanel {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginS
|
||||
model: root.tabsModel
|
||||
spacing: Style.marginXS
|
||||
spacing: Style.marginXXS
|
||||
currentIndex: root.currentTabIndex
|
||||
verticalPolicy: ScrollBar.AsNeeded
|
||||
|
||||
delegate: Rectangle {
|
||||
id: tabItem
|
||||
width: sidebarList.verticalScrollBarActive ? sidebarList.width - sidebarList.scrollBarWidth - Style.marginXS : sidebarList.width
|
||||
height: tabEntryRow.implicitHeight + Style.marginM * 2
|
||||
height: tabEntryRow.implicitHeight + Style.marginS * 2
|
||||
radius: Style.radiusS
|
||||
color: selected ? Color.mPrimary : (tabItem.hovering ? Color.mHover : Color.transparent)
|
||||
readonly property bool selected: index === root.currentTabIndex
|
||||
|
||||
@@ -24,22 +24,6 @@ ColumnLayout {
|
||||
})
|
||||
}
|
||||
|
||||
// Handler for drag start - disables panel background clicks
|
||||
function handleDragStart() {
|
||||
var panel = PanelService.getPanel("settingsPanel", screen)
|
||||
if (panel && panel.disableBackgroundClick) {
|
||||
panel.disableBackgroundClick()
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for drag end - re-enables panel background clicks
|
||||
function handleDragEnd() {
|
||||
var panel = PanelService.getPanel("settingsPanel", screen)
|
||||
if (panel && panel.enableBackgroundClick) {
|
||||
panel.enableBackgroundClick()
|
||||
}
|
||||
}
|
||||
|
||||
NHeader {
|
||||
label: I18n.tr("settings.bar.appearance.section.label")
|
||||
description: I18n.tr("settings.bar.appearance.section.description")
|
||||
@@ -234,8 +218,6 @@ ColumnLayout {
|
||||
onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex)
|
||||
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings)
|
||||
onMoveWidget: (fromSection, index, toSection) => _moveWidgetBetweenSections(fromSection, index, toSection)
|
||||
onDragPotentialStarted: root.handleDragStart()
|
||||
onDragPotentialEnded: root.handleDragEnd()
|
||||
}
|
||||
|
||||
// Center Section
|
||||
@@ -251,8 +233,6 @@ ColumnLayout {
|
||||
onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex)
|
||||
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings)
|
||||
onMoveWidget: (fromSection, index, toSection) => _moveWidgetBetweenSections(fromSection, index, toSection)
|
||||
onDragPotentialStarted: root.handleDragStart()
|
||||
onDragPotentialEnded: root.handleDragEnd()
|
||||
}
|
||||
|
||||
// Right Section
|
||||
@@ -268,8 +248,6 @@ ColumnLayout {
|
||||
onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex)
|
||||
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings)
|
||||
onMoveWidget: (fromSection, index, toSection) => _moveWidgetBetweenSections(fromSection, index, toSection)
|
||||
onDragPotentialStarted: root.handleDragStart()
|
||||
onDragPotentialEnded: root.handleDragEnd()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -677,6 +677,8 @@ ColumnLayout {
|
||||
enabled: ProgramCheckerService.availableDiscordClients.length > 0
|
||||
opacity: ProgramCheckerService.availableDiscordClients.length > 0 ? 1.0 : 0.6
|
||||
onToggled: checked => {
|
||||
// Set unified discord property
|
||||
Settings.data.templates.discord = checked
|
||||
// Enable/disable all detected Discord clients
|
||||
for (var i = 0; i < ProgramCheckerService.availableDiscordClients.length; i++) {
|
||||
var client = ProgramCheckerService.availableDiscordClients[i]
|
||||
@@ -740,19 +742,50 @@ ColumnLayout {
|
||||
}
|
||||
}
|
||||
|
||||
// Code clients - single toggle with dynamic description
|
||||
NCheckbox {
|
||||
id: codeToggle
|
||||
label: "Code"
|
||||
description: ProgramCheckerService.codeAvailable ? I18n.tr("settings.color-scheme.templates.programs.code.description", {
|
||||
"filepath": "~/.vscode/extensions/hyprluna.hyprluna-theme-1.0.2/themes/hyprluna.json"
|
||||
}) : I18n.tr("settings.color-scheme.templates.programs.code.description-missing", {
|
||||
"app": "code"
|
||||
})
|
||||
checked: Settings.data.templates.code
|
||||
enabled: ProgramCheckerService.codeAvailable
|
||||
opacity: ProgramCheckerService.codeAvailable ? 1.0 : 0.6
|
||||
description: {
|
||||
if (ProgramCheckerService.availableCodeClients.length === 0) {
|
||||
return I18n.tr("settings.color-scheme.templates.programs.code.description-missing")
|
||||
} else {
|
||||
// Show detected clients
|
||||
var clientInfo = []
|
||||
for (var i = 0; i < ProgramCheckerService.availableCodeClients.length; i++) {
|
||||
var client = ProgramCheckerService.availableCodeClients[i]
|
||||
// Capitalize first letter and format nicely
|
||||
var clientName = client.name === "code" ? "VSCode" : "VSCodium"
|
||||
clientInfo.push(clientName)
|
||||
}
|
||||
return "Detected: " + clientInfo.join(", ")
|
||||
}
|
||||
}
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: -1
|
||||
checked: {
|
||||
// Check if any Code client template is enabled
|
||||
var anyEnabled = false
|
||||
for (var i = 0; i < ProgramCheckerService.availableCodeClients.length; i++) {
|
||||
var client = ProgramCheckerService.availableCodeClients[i]
|
||||
if (Settings.data.templates["code_" + client.name]) {
|
||||
anyEnabled = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return anyEnabled
|
||||
}
|
||||
enabled: ProgramCheckerService.availableCodeClients.length > 0
|
||||
opacity: ProgramCheckerService.availableCodeClients.length > 0 ? 1.0 : 0.6
|
||||
onToggled: checked => {
|
||||
if (ProgramCheckerService.codeAvailable) {
|
||||
Settings.data.templates.code = checked
|
||||
// Set unified code property
|
||||
Settings.data.templates.code = checked
|
||||
// Enable/disable all detected Code clients
|
||||
for (var i = 0; i < ProgramCheckerService.availableCodeClients.length; i++) {
|
||||
var client = ProgramCheckerService.availableCodeClients[i]
|
||||
Settings.data.templates["code_" + client.name] = checked
|
||||
}
|
||||
if (ProgramCheckerService.availableCodeClients.length > 0) {
|
||||
AppThemeService.generate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,22 +38,6 @@ ColumnLayout {
|
||||
"required": false
|
||||
}]
|
||||
|
||||
// Handler for drag start - disables panel background clicks
|
||||
function handleDragStart() {
|
||||
var panel = PanelService.getPanel("settingsPanel", screen)
|
||||
if (panel && panel.disableBackgroundClick) {
|
||||
panel.disableBackgroundClick()
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for drag end - re-enables panel background clicks
|
||||
function handleDragEnd() {
|
||||
var panel = PanelService.getPanel("settingsPanel", screen)
|
||||
if (panel && panel.enableBackgroundClick) {
|
||||
panel.enableBackgroundClick()
|
||||
}
|
||||
}
|
||||
|
||||
function saveCards() {
|
||||
var toSave = []
|
||||
for (var i = 0; i < cardsModel.length; i++) {
|
||||
@@ -202,12 +186,6 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
model: cardsModel
|
||||
disabledIds: Settings.data.location.weatherEnabled ? [] : ["weather-card"]
|
||||
onDragPotentialStarted: {
|
||||
root.handleDragStart()
|
||||
}
|
||||
onDragPotentialEnded: {
|
||||
root.handleDragEnd()
|
||||
}
|
||||
onItemToggled: function (index, enabled) {
|
||||
//Logger.i("ControlCenterTab", "Item", index, "toggled to", enabled)
|
||||
var newModel = cardsModel.slice()
|
||||
@@ -266,8 +244,6 @@ ColumnLayout {
|
||||
onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex)
|
||||
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings)
|
||||
onMoveWidget: (fromSection, index, toSection) => _moveWidgetBetweenSections(fromSection, index, toSection)
|
||||
onDragPotentialStarted: root.handleDragStart()
|
||||
onDragPotentialEnded: root.handleDragEnd()
|
||||
}
|
||||
|
||||
// Right
|
||||
@@ -285,8 +261,6 @@ ColumnLayout {
|
||||
onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex)
|
||||
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings)
|
||||
onMoveWidget: (fromSection, index, toSection) => _moveWidgetBetweenSections(fromSection, index, toSection)
|
||||
onDragPotentialStarted: root.handleDragStart()
|
||||
onDragPotentialEnded: root.handleDragEnd()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ ColumnLayout {
|
||||
}
|
||||
|
||||
NButton {
|
||||
visible: !DistroService.isNixOS
|
||||
visible: !HostService.isNixOS
|
||||
text: I18n.tr("settings.general.launch-setup-wizard")
|
||||
onClicked: {
|
||||
var targetScreen = PanelService.openedPanel ? PanelService.openedPanel.screen : (Quickshell.screens.length > 0 ? Quickshell.screens[0] : null)
|
||||
|
||||
@@ -11,15 +11,15 @@ ColumnLayout {
|
||||
|
||||
// Helper functions to update arrays immutably
|
||||
function addMonitor(list, name) {
|
||||
const arr = (list || []).slice();
|
||||
const arr = (list || []).slice()
|
||||
if (!arr.includes(name))
|
||||
arr.push(name);
|
||||
return arr;
|
||||
arr.push(name)
|
||||
return arr
|
||||
}
|
||||
function removeMonitor(list, name) {
|
||||
return (list || []).filter(function (n) {
|
||||
return n !== name;
|
||||
});
|
||||
return n !== name
|
||||
})
|
||||
}
|
||||
|
||||
// Display
|
||||
@@ -30,40 +30,31 @@ ColumnLayout {
|
||||
NComboBox {
|
||||
label: I18n.tr("settings.osd.location.label")
|
||||
description: I18n.tr("settings.osd.location.description")
|
||||
model: [
|
||||
{
|
||||
model: [{
|
||||
"key": "top",
|
||||
"name": I18n.tr("options.osd.position.top_center")
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"key": "top_left",
|
||||
"name": I18n.tr("options.osd.position.top_left")
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"key": "top_right",
|
||||
"name": I18n.tr("options.osd.position.top_right")
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"key": "bottom",
|
||||
"name": I18n.tr("options.osd.position.bottom_center")
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"key": "bottom_left",
|
||||
"name": I18n.tr("options.osd.position.bottom_left")
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"key": "bottom_right",
|
||||
"name": I18n.tr("options.osd.position.bottom_right")
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"key": "left",
|
||||
"name": I18n.tr("options.osd.position.center_left")
|
||||
},
|
||||
{
|
||||
}, {
|
||||
"key": "right",
|
||||
"name": I18n.tr("options.osd.position.center_right")
|
||||
}
|
||||
]
|
||||
}]
|
||||
currentKey: Settings.data.osd.location || "top_right"
|
||||
onSelected: key => Settings.data.osd.location = key
|
||||
}
|
||||
@@ -152,22 +143,22 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
label: modelData.name || I18n.tr("system.unknown")
|
||||
description: {
|
||||
const compositorScale = CompositorService.getDisplayScale(modelData.name);
|
||||
const compositorScale = CompositorService.getDisplayScale(modelData.name)
|
||||
I18n.tr("system.monitor-description", {
|
||||
"model": modelData.model,
|
||||
"width": modelData.width * compositorScale,
|
||||
"height": modelData.height * compositorScale,
|
||||
"scale": compositorScale
|
||||
});
|
||||
"model": modelData.model,
|
||||
"width": modelData.width * compositorScale,
|
||||
"height": modelData.height * compositorScale,
|
||||
"scale": compositorScale
|
||||
})
|
||||
}
|
||||
checked: (Settings.data.osd.monitors || []).indexOf(modelData.name) !== -1
|
||||
onToggled: checked => {
|
||||
if (checked) {
|
||||
Settings.data.osd.monitors = addMonitor(Settings.data.osd.monitors, modelData.name);
|
||||
} else {
|
||||
Settings.data.osd.monitors = removeMonitor(Settings.data.osd.monitors, modelData.name);
|
||||
}
|
||||
}
|
||||
if (checked) {
|
||||
Settings.data.osd.monitors = addMonitor(Settings.data.osd.monitors, modelData.name)
|
||||
} else {
|
||||
Settings.data.osd.monitors = removeMonitor(Settings.data.osd.monitors, modelData.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,11 @@ ColumnLayout {
|
||||
"text": I18n.tr("session-menu.suspend"),
|
||||
"enabled": true,
|
||||
"required": false
|
||||
}, {
|
||||
"id": "hibernate",
|
||||
"text": I18n.tr("session-menu.hibernate"),
|
||||
"enabled": true,
|
||||
"required": false
|
||||
}, {
|
||||
"id": "reboot",
|
||||
"text": I18n.tr("session-menu.reboot"),
|
||||
@@ -39,28 +44,6 @@ ColumnLayout {
|
||||
"required": false
|
||||
}]
|
||||
|
||||
// Handler for drag start - disables panel background clicks
|
||||
function handleDragStart() {
|
||||
var currentScreen = Quickshell.screens && Quickshell.screens.length > 0 ? Quickshell.screens[0] : null
|
||||
if (currentScreen) {
|
||||
var panel = PanelService.getPanel("settingsPanel", currentScreen)
|
||||
if (panel && panel.disableBackgroundClick) {
|
||||
panel.disableBackgroundClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handler for drag end - re-enables panel background clicks
|
||||
function handleDragEnd() {
|
||||
var currentScreen = Quickshell.screens && Quickshell.screens.length > 0 ? Quickshell.screens[0] : null
|
||||
if (currentScreen) {
|
||||
var panel = PanelService.getPanel("settingsPanel", currentScreen)
|
||||
if (panel && panel.enableBackgroundClick) {
|
||||
panel.enableBackgroundClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function saveEntries() {
|
||||
var toSave = []
|
||||
for (var i = 0; i < entriesModel.length; i++) {
|
||||
@@ -201,12 +184,6 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
model: entriesModel
|
||||
disabledIds: []
|
||||
onDragPotentialStarted: {
|
||||
root.handleDragStart()
|
||||
}
|
||||
onDragPotentialEnded: {
|
||||
root.handleDragEnd()
|
||||
}
|
||||
onItemToggled: function (index, enabled) {
|
||||
var newModel = entriesModel.slice()
|
||||
newModel[index] = Object.assign({}, newModel[index], {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
spacing: Style.marginL
|
||||
|
||||
Component.onCompleted: {
|
||||
|
||||
}
|
||||
|
||||
NHeader {
|
||||
label: I18n.tr("settings.system-monitor.general.section.label")
|
||||
description: I18n.tr("settings.system-monitor.general.section.description")
|
||||
}
|
||||
}
|
||||
@@ -368,6 +368,11 @@ Singleton {
|
||||
Quickshell.execDetached(["sh", "-c", "systemctl suspend || loginctl suspend"])
|
||||
}
|
||||
|
||||
function hibernate() {
|
||||
Logger.i("Compositor", "Hibernate requested")
|
||||
Quickshell.execDetached(["sh", "-c", "systemctl hibernate || loginctl hibernate"])
|
||||
}
|
||||
|
||||
function lockAndSuspend() {
|
||||
Logger.i("Compositor", "Lock and suspend requested")
|
||||
try {
|
||||
|
||||
@@ -16,7 +16,7 @@ Singleton {
|
||||
* - LockScreen is opened
|
||||
* - A control center is open
|
||||
*/
|
||||
property bool shouldRun: BarService.hasAudioVisualizer || PanelService.lockScreen?.active || (PanelService.openedPanel && PanelService.openedPanel.objectName.startsWith("controlCenterPanel"))
|
||||
property bool shouldRun: BarService.hasAudioVisualizer || PanelService.lockScreen?.active || (PanelService.openedPanel && PanelService.openedPanel.panelWrapper.objectName.startsWith("controlCenterPanel"))
|
||||
|
||||
property var values: Array(barsCount).fill(0)
|
||||
property int barsCount: 32
|
||||
|
||||
@@ -18,6 +18,8 @@ Singleton {
|
||||
property bool ethernetConnected: false
|
||||
property string disconnectingFrom: ""
|
||||
property string forgettingNetwork: ""
|
||||
property string networkConnectivity: "unknown"
|
||||
property bool internetConnectivity: true
|
||||
property bool ignoreScanResults: false
|
||||
property bool scanPending: false
|
||||
|
||||
@@ -98,6 +100,16 @@ Singleton {
|
||||
onTriggered: ethernetStateProcess.running = true
|
||||
}
|
||||
|
||||
// Internet connectivity check timer
|
||||
// Always running every 15s
|
||||
Timer {
|
||||
id: connectivityCheckTimer
|
||||
interval: 15000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: connectivityCheckProcess.running = true
|
||||
}
|
||||
|
||||
// Core functions
|
||||
function syncWifiState() {
|
||||
wifiStateProcess.running = true
|
||||
@@ -211,6 +223,8 @@ Singleton {
|
||||
|
||||
// Helper functions
|
||||
function signalIcon(signal, isConnected = false) {
|
||||
if (isConnected && !root.internetConnectivity)
|
||||
return "world-off"
|
||||
if (signal >= 80)
|
||||
return "wifi"
|
||||
if (signal >= 50)
|
||||
@@ -285,6 +299,75 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
// Process to check the internet connectivity of the connected network
|
||||
Process {
|
||||
id: connectivityCheckProcess
|
||||
running: false
|
||||
command: ["nmcli", "networking", "connectivity", "check"]
|
||||
|
||||
property int failedChecks: 0
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const result = text.trim()
|
||||
if (!result) {
|
||||
return
|
||||
}
|
||||
|
||||
if (result === "none" && root.networkConnectivity !== result) {
|
||||
root.networkConnectivity = result
|
||||
connectivityCheckProcess.failedChecks = 0
|
||||
root.scan()
|
||||
}
|
||||
|
||||
if (result === "full" && root.networkConnectivity !== result) {
|
||||
root.networkConnectivity = result
|
||||
root.internetConnectivity = true
|
||||
connectivityCheckProcess.failedChecks = 0
|
||||
root.scan()
|
||||
}
|
||||
|
||||
if ((result === "limited" || result === "portal") && root.networkConnectivity !== result) {
|
||||
connectivityCheckProcess.failedChecks++
|
||||
if (connectivityCheckProcess.failedChecks === 3) {
|
||||
root.networkConnectivity = result
|
||||
pingCheckProcess.running = true
|
||||
}
|
||||
}
|
||||
|
||||
if (result === "unknown" && root.networkConnectivity !== result) {
|
||||
root.networkConnectivity = result
|
||||
connectivityCheckProcess.failedChecks = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stderr: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text.trim()) {
|
||||
Logger.w("Network", "Connectivity check error: " + text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: pingCheckProcess
|
||||
command: ["sh", "-c", "ping -c1 -W2 ping.archlinux.org >/dev/null 2>&1 || " + "ping -c1 -W2 1.1.1.1 >/dev/null 2>&1 || " + "curl -fsI --max-time 5 https://cloudflare.com/cdn-cgi/trace >/dev/null 2>&1"]
|
||||
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
if (exitCode === 0) {
|
||||
connectivityCheckProcess.failedChecks = 0
|
||||
} else {
|
||||
root.internetConnectivity = false
|
||||
Logger.i("Network", "No internet connectivity")
|
||||
ToastService.showWarning(root.cachedLastConnected, I18n.tr("toast.internet.limited"))
|
||||
connectivityCheckProcess.failedChecks = 0
|
||||
}
|
||||
root.scan()
|
||||
}
|
||||
}
|
||||
|
||||
// Helper process to get existing profiles
|
||||
Process {
|
||||
id: profileCheckProcess
|
||||
|
||||
@@ -15,7 +15,7 @@ Singleton {
|
||||
property bool isReady: false
|
||||
|
||||
function init() {
|
||||
Logger.i("DistroService", "Service started")
|
||||
Logger.i("HostService", "Service started")
|
||||
}
|
||||
|
||||
// Internal helpers
|
||||
@@ -81,7 +81,7 @@ Singleton {
|
||||
return l ? l.split("=")[1].replace(/"/g, "") : ""
|
||||
}
|
||||
root.osPretty = val("PRETTY_NAME") || val("NAME")
|
||||
Logger.i("DistroService", root.osPretty)
|
||||
Logger.i("HostService", root.osPretty)
|
||||
|
||||
const osId = (val("ID") || "").toLowerCase()
|
||||
root.isNixOS = osId === "nixos" || (root.osPretty || "").toLowerCase().includes("nixos")
|
||||
@@ -91,7 +91,7 @@ Singleton {
|
||||
}
|
||||
root.isReady = true
|
||||
} catch (e) {
|
||||
Logger.w("DistroService", "failed to read os-release", e)
|
||||
Logger.w("HostService", "failed to read os-release", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,10 +102,10 @@ Singleton {
|
||||
const p = String(stdout.text || "").trim()
|
||||
if (code === 0 && p) {
|
||||
root.osLogo = `file://${p}`
|
||||
Logger.i("DistroService", "found", root.osLogo)
|
||||
Logger.i("HostService", "found", root.osLogo)
|
||||
} else {
|
||||
root.osLogo = ""
|
||||
Logger.w("DistroService", "none found")
|
||||
Logger.w("HostService", "none found")
|
||||
}
|
||||
}
|
||||
stdout: StdioCollector {}
|
||||
@@ -31,6 +31,9 @@ Singleton {
|
||||
// Discord client auto-detection
|
||||
property var availableDiscordClients: []
|
||||
|
||||
// Code client auto-detection
|
||||
property var availableCodeClients: []
|
||||
|
||||
// Signal emitted when all checks are complete
|
||||
signal checksCompleted
|
||||
|
||||
@@ -42,12 +45,16 @@ Singleton {
|
||||
for (var i = 0; i < TemplateRegistry.discordClients.length; i++) {
|
||||
var client = TemplateRegistry.discordClients[i]
|
||||
var clientName = client.name
|
||||
var configPath = client.configPath
|
||||
|
||||
// Use the actual config path from the client, removing ~ prefix
|
||||
var checkPath = configPath.startsWith("~") ? configPath.substring(2) : configPath.substring(1)
|
||||
|
||||
// Check if this client requires themes folder to exist
|
||||
if (client.requiresThemesFolder) {
|
||||
scriptParts.push("if [ -d \"$HOME/.config/" + clientName + "/themes\" ]; then available_clients=\"$available_clients " + clientName + "\"; fi;")
|
||||
scriptParts.push("if [ -d \"$HOME/" + checkPath + "/themes\" ]; then available_clients=\"$available_clients " + clientName + "\"; fi;")
|
||||
} else {
|
||||
scriptParts.push("if [ -d \"$HOME/.config/" + clientName + "\" ]; then available_clients=\"$available_clients " + clientName + "\"; fi;")
|
||||
scriptParts.push("if [ -d \"$HOME/" + checkPath + "\" ]; then available_clients=\"$available_clients " + clientName + "\"; fi;")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +104,66 @@ Singleton {
|
||||
stderr: StdioCollector {}
|
||||
}
|
||||
|
||||
// Function to detect Code client by checking config directories
|
||||
function detectCodeClient() {
|
||||
// Build shell script to check each client
|
||||
var scriptParts = ["available_clients=\"\";"]
|
||||
|
||||
for (var i = 0; i < TemplateRegistry.codeClients.length; i++) {
|
||||
var client = TemplateRegistry.codeClients[i]
|
||||
var clientName = client.name
|
||||
var configPath = client.configPath
|
||||
|
||||
// Check if the config directory exists
|
||||
scriptParts.push("if [ -d \"$HOME" + configPath.substring(1) + "\" ]; then available_clients=\"$available_clients " + clientName + "\"; fi;")
|
||||
}
|
||||
|
||||
scriptParts.push("echo \"$available_clients\"")
|
||||
|
||||
// Use a Process to check directory existence for all clients
|
||||
codeDetector.command = ["sh", "-c", scriptParts.join(" ")]
|
||||
codeDetector.running = true
|
||||
}
|
||||
|
||||
// Process to detect Code client directories
|
||||
Process {
|
||||
id: codeDetector
|
||||
running: false
|
||||
|
||||
onExited: function (exitCode) {
|
||||
availableCodeClients = []
|
||||
|
||||
if (exitCode === 0) {
|
||||
var detectedClients = stdout.text.trim().split(/\s+/).filter(function (client) {
|
||||
return client.length > 0
|
||||
})
|
||||
|
||||
if (detectedClients.length > 0) {
|
||||
// Build list of available clients
|
||||
for (var i = 0; i < detectedClients.length; i++) {
|
||||
var clientName = detectedClients[i]
|
||||
for (var j = 0; j < TemplateRegistry.codeClients.length; j++) {
|
||||
var client = TemplateRegistry.codeClients[j]
|
||||
if (client.name === clientName) {
|
||||
availableCodeClients.push(client)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Logger.i("ProgramChecker", "Detected Code clients:", detectedClients.join(", "))
|
||||
}
|
||||
}
|
||||
|
||||
if (availableCodeClients.length === 0) {
|
||||
Logger.d("ProgramChecker", "No Code clients detected")
|
||||
}
|
||||
}
|
||||
|
||||
stdout: StdioCollector {}
|
||||
stderr: StdioCollector {}
|
||||
}
|
||||
|
||||
// Programs to check - maps property names to commands
|
||||
readonly property var programsToCheck: ({
|
||||
"matugenAvailable": ["which", "matugen"],
|
||||
@@ -140,8 +207,9 @@ Singleton {
|
||||
|
||||
// Check next program or emit completion signal
|
||||
if (root.completedChecks >= root.totalChecks) {
|
||||
// Run Discord client detection after all checks are complete
|
||||
// Run Discord and Code client detection after all checks are complete
|
||||
root.detectDiscordClient()
|
||||
root.detectCodeClient()
|
||||
root.checksCompleted()
|
||||
} else {
|
||||
root.checkNextProgram()
|
||||
|
||||
@@ -114,6 +114,18 @@ Singleton {
|
||||
}
|
||||
})
|
||||
}
|
||||
} else if (app.id === "code") {
|
||||
// Handle Code clients specially
|
||||
if (Settings.data.templates.code) {
|
||||
app.clients.forEach(client => {
|
||||
// Check if this specific client is detected
|
||||
if (isCodeClientEnabled(client.name)) {
|
||||
lines.push(`\n[templates.code_${client.name}]`)
|
||||
lines.push(`input_path = "${Quickshell.shellDir}/Assets/MatugenTemplates/${app.input}"`)
|
||||
lines.push(`output_path = "${client.path}"`)
|
||||
}
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// Handle regular apps
|
||||
if (Settings.data.templates[app.id]) {
|
||||
@@ -140,6 +152,16 @@ Singleton {
|
||||
return false
|
||||
}
|
||||
|
||||
function isCodeClientEnabled(clientName) {
|
||||
// Check ProgramCheckerService to see if client is detected
|
||||
for (var i = 0; i < ProgramCheckerService.availableCodeClients.length; i++) {
|
||||
if (ProgramCheckerService.availableCodeClients[i].name === clientName) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function buildMatugenScript(content, wallpaper, mode) {
|
||||
const delimiter = "MATUGEN_CONFIG_EOF_" + Math.random().toString(36).substr(2, 9)
|
||||
const pathEsc = dynamicConfigPath.replace(/'/g, "'\\''")
|
||||
@@ -163,6 +185,10 @@ Singleton {
|
||||
if (Settings.data.templates.discord) {
|
||||
script += processDiscordClients(app, colors, mode, homeDir)
|
||||
}
|
||||
} else if (app.id === "code") {
|
||||
if (Settings.data.templates.code) {
|
||||
script += processCodeClients(app, colors, mode, homeDir)
|
||||
}
|
||||
} else {
|
||||
if (Settings.data.templates[app.id]) {
|
||||
script += processTemplate(app, colors, mode, homeDir)
|
||||
@@ -198,6 +224,39 @@ Singleton {
|
||||
return script
|
||||
}
|
||||
|
||||
function processCodeClients(codeApp, colors, mode, homeDir) {
|
||||
let script = ""
|
||||
const palette = ColorPaletteGenerator.generatePalette(colors, Settings.data.colorSchemes.darkMode, false)
|
||||
|
||||
codeApp.clients.forEach(client => {
|
||||
if (!isCodeClientEnabled(client.name))
|
||||
return
|
||||
|
||||
const templatePath = `${Quickshell.shellDir}/Assets/MatugenTemplates/${codeApp.input}`
|
||||
const outputPath = client.path.replace("~", homeDir)
|
||||
const outputDir = outputPath.substring(0, outputPath.lastIndexOf('/'))
|
||||
|
||||
// Extract base config directory for checking
|
||||
var baseConfigDir = ""
|
||||
if (client.name === "code") {
|
||||
baseConfigDir = "~/.vscode".replace("~", homeDir)
|
||||
} else if (client.name === "codium") {
|
||||
baseConfigDir = "~/.vscode-oss".replace("~", homeDir)
|
||||
}
|
||||
|
||||
script += `\n`
|
||||
script += `if [ -d "${baseConfigDir}" ]; then\n`
|
||||
script += ` mkdir -p ${outputDir}\n`
|
||||
script += ` cp '${templatePath}' '${outputPath}'\n`
|
||||
script += ` ${replaceColorsInFile(outputPath, palette)}`
|
||||
script += `else\n`
|
||||
script += ` echo "Code client ${client.name} not found at ${baseConfigDir}, skipping"\n`
|
||||
script += `fi\n`
|
||||
})
|
||||
|
||||
return script
|
||||
}
|
||||
|
||||
function processTemplate(app, colors, mode, homeDir) {
|
||||
const palette = ColorPaletteGenerator.generatePalette(colors, Settings.data.colorSchemes.darkMode, app.strict || false)
|
||||
let script = ""
|
||||
|
||||
@@ -139,17 +139,21 @@ Singleton {
|
||||
"requiresThemesFolder": false
|
||||
}, {
|
||||
"name": "vencord",
|
||||
"path": "~/.config/discord",
|
||||
"requiresThemesFolder": true
|
||||
"path": "~/.config/Vencord",
|
||||
"requiresThemesFolder": false
|
||||
}]
|
||||
}, // VSCode with hardcoded path (requirement #5)
|
||||
},
|
||||
{
|
||||
"id": "code",
|
||||
"name": "VSCode",
|
||||
"category": "applications",
|
||||
"input": "code.json",
|
||||
"outputs": [{
|
||||
"clients": [{
|
||||
"name": "code",
|
||||
"path": "~/.vscode/extensions/hyprluna.hyprluna-theme-1.0.2/themes/hyprluna.json"
|
||||
}, {
|
||||
"name": "codium",
|
||||
"path": "~/.vscode-oss/extensions/hyprluna.hyprluna-theme-1.0.2/themes/hyprluna.json"
|
||||
}]
|
||||
}, {
|
||||
"id": "spicetify",
|
||||
@@ -179,6 +183,33 @@ Singleton {
|
||||
return clients
|
||||
}
|
||||
|
||||
// Extract Code clients for ProgramCheckerService compatibility
|
||||
readonly property var codeClients: {
|
||||
var clients = []
|
||||
var codeApp = applications.find(app => app.id === "code")
|
||||
if (codeApp && codeApp.clients) {
|
||||
codeApp.clients.forEach(client => {
|
||||
// Extract base config directory from theme path
|
||||
var themePath = client.path
|
||||
var baseConfigDir = ""
|
||||
if (client.name === "code") {
|
||||
// For VSCode: ~/.vscode/extensions/... -> ~/.vscode
|
||||
baseConfigDir = "~/.vscode"
|
||||
} else if (client.name === "codium") {
|
||||
// For VSCodium: ~/.vscode-oss/extensions/... -> ~/.vscode-oss
|
||||
baseConfigDir = "~/.vscode-oss"
|
||||
}
|
||||
clients.push({
|
||||
"name": client.name,
|
||||
"configPath": baseConfigDir,
|
||||
"themePath": themePath,
|
||||
"requiresThemesFolder": false
|
||||
})
|
||||
})
|
||||
}
|
||||
return clients
|
||||
}
|
||||
|
||||
// Build user templates TOML content
|
||||
function buildUserTemplatesToml() {
|
||||
var lines = []
|
||||
|
||||
@@ -162,7 +162,11 @@ Singleton {
|
||||
"TaskbarGrouped": {
|
||||
"allowUserSettings": true,
|
||||
"showWorkspaceNumbers": true,
|
||||
"showNumbersOnlyWhenOccupied": true
|
||||
"showNumbersOnlyWhenOccupied": true,
|
||||
"labelMode": "index",
|
||||
"hideUnoccupied": false,
|
||||
"characterCount": 2,
|
||||
"colorizeIcons": false
|
||||
},
|
||||
"Tray": {
|
||||
"allowUserSettings": true,
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ ColumnLayout {
|
||||
NText {
|
||||
text: root.label
|
||||
pointSize: Style.fontSizeXL
|
||||
font.weight: Style.fontWeightBold
|
||||
font.weight: Style.fontWeightSemiBold
|
||||
color: Color.mSecondary
|
||||
visible: root.label !== ""
|
||||
}
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ ColumnLayout {
|
||||
NText {
|
||||
text: label
|
||||
pointSize: Style.fontSizeL
|
||||
font.weight: Style.fontWeightBold
|
||||
font.weight: Style.fontWeightSemiBold
|
||||
color: labelColor
|
||||
visible: label !== ""
|
||||
Layout.fillWidth: true
|
||||
|
||||
@@ -81,7 +81,7 @@ ShellRoot {
|
||||
BatteryService.init()
|
||||
IdleInhibitorService.init()
|
||||
PowerProfileService.init()
|
||||
DistroService.init()
|
||||
HostService.init()
|
||||
FontService.init()
|
||||
|
||||
// Only open the setup wizard for new users
|
||||
@@ -128,13 +128,13 @@ ShellRoot {
|
||||
|
||||
function checkSetupWizard() {
|
||||
// Wait for distro service
|
||||
if (!DistroService.isReady) {
|
||||
if (!HostService.isReady) {
|
||||
Qt.callLater(checkSetupWizard)
|
||||
return
|
||||
}
|
||||
|
||||
// No setup wizard on NixOS
|
||||
if (DistroService.isNixOS) {
|
||||
if (HostService.isNixOS) {
|
||||
Settings.data.setupCompleted = true
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user