diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json
index 71475b772..306cc0de9 100644
--- a/Assets/Translations/de.json
+++ b/Assets/Translations/de.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Die Richtung des Arbeitsflächenwechsels beim Scrollen umkehren.",
"reverse-scrolling-label": "Scrollen umkehren",
"show-applications-description": "Anwendungssymbole in jeder Arbeitsfläche anzeigen.",
+ "show-applications-hover-description": "Anwendungssymbole in jedem Arbeitsbereich anzeigen, wenn der Arbeitsbereich überfahren wird.",
+ "show-applications-hover-label": "Anwendungen beim Hovern anzeigen",
"show-applications-label": "Anwendungen anzeigen",
"show-badge-description": "Zeige die Arbeitsflächennummer als Abzeichen im gruppierten Modus an.",
"show-badge-label": "Arbeitsflächen-Abzeichen anzeigen",
diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json
index fe1ab5f28..701772826 100644
--- a/Assets/Translations/en.json
+++ b/Assets/Translations/en.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Reverse the direction of workspace switching when scrolling.",
"reverse-scrolling-label": "Reverse scrolling",
"show-applications-description": "Display application icons inside each workspace.",
+ "show-applications-hover-description": "Display application icons inside each workspace when the workspace is hovered.",
+ "show-applications-hover-label": "Show applications when hovered",
"show-applications-label": "Show applications",
"show-badge-description": "Show the workspace number badge in grouped mode.",
"show-badge-label": "Show workspace badge",
diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json
index ae374c781..770ac5472 100644
--- a/Assets/Translations/es.json
+++ b/Assets/Translations/es.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Invertir la dirección del cambio de espacios de trabajo al desplazarse.",
"reverse-scrolling-label": "Desplazamiento inverso",
"show-applications-description": "Mostrar los iconos de las aplicaciones dentro de cada espacio de trabajo.",
+ "show-applications-hover-description": "Mostrar iconos de aplicación dentro de cada espacio de trabajo cuando se pasa el ratón por encima.",
+ "show-applications-hover-label": "Mostrar aplicaciones al pasar el ratón",
"show-applications-label": "Mostrar aplicaciones",
"show-badge-description": "Mostrar la insignia del número de espacio de trabajo en modo agrupado.",
"show-badge-label": "Mostrar insignia del espacio de trabajo",
diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json
index cc15f4f27..e9f21c3be 100644
--- a/Assets/Translations/fr.json
+++ b/Assets/Translations/fr.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Inverser la direction du changement d'espace de travail lors du défilement.",
"reverse-scrolling-label": "Défilement inversé",
"show-applications-description": "Afficher les icônes des applications dans chaque espace de travail.",
+ "show-applications-hover-description": "Afficher les icônes d'application dans chaque espace de travail lorsque celui-ci est survolé.",
+ "show-applications-hover-label": "Afficher les applications au survol",
"show-applications-label": "Afficher les applications",
"show-badge-description": "Afficher le badge du numéro d'espace de travail en mode groupé.",
"show-badge-label": "Afficher le badge de l'espace de travail",
diff --git a/Assets/Translations/hu.json b/Assets/Translations/hu.json
index 8136d287b..d8a363e79 100644
--- a/Assets/Translations/hu.json
+++ b/Assets/Translations/hu.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Görgetéskor fordított irányba váltson a munkaterületek között.",
"reverse-scrolling-label": "Görgetés megfordítása",
"show-applications-description": "Alkalmazásikonok megjelenítése minden munkaterületen belül.",
+ "show-applications-hover-description": "Alkalmazásikonok megjelenítése minden munkaterületen belül, amikor a munkaterület fölé viszi az egeret.",
+ "show-applications-hover-label": "Alkalmazások megjelenítése rámutatáskor",
"show-applications-label": "Alkalmazások megjelenítése",
"show-badge-description": "Munkaterület számának jelzése csoportosított módban.",
"show-badge-label": "Munkafelület jelvény megjelenítése",
diff --git a/Assets/Translations/it.json b/Assets/Translations/it.json
index fc99560c3..3c06fc326 100644
--- a/Assets/Translations/it.json
+++ b/Assets/Translations/it.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Inverti direzione del cambio workspace quando scorri.",
"reverse-scrolling-label": "Inverti scorrimento",
"show-applications-description": "Mostra icone applicazioni dentro ogni workspace.",
+ "show-applications-hover-description": "Mostra le icone delle applicazioni all'interno di ogni spazio di lavoro quando lo spazio di lavoro viene sorvolato.",
+ "show-applications-hover-label": "Mostra applicazioni al passaggio del mouse",
"show-applications-label": "Mostra applicazioni",
"show-badge-description": "Mostra badge numero workspace in modalità raggruppata.",
"show-badge-label": "Mostra badge workspace",
diff --git a/Assets/Translations/ja.json b/Assets/Translations/ja.json
index 63bf6758d..ada5e4440 100644
--- a/Assets/Translations/ja.json
+++ b/Assets/Translations/ja.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "スクロール時のワークスペース切り替え方向を反転する。",
"reverse-scrolling-label": "スクロール方向を反転",
"show-applications-description": "各ワークスペース内にアプリアイコンを表示します。",
+ "show-applications-hover-description": "ワークスペースにカーソルを合わせたときに、各ワークスペース内にアプリケーションアイコンを表示します。",
+ "show-applications-hover-label": "ホバー時にアプリケーションを表示",
"show-applications-label": "アプリアイコンを表示",
"show-badge-description": "グループ化モードでワークスペース番号バッジを表示します。",
"show-badge-label": "ワークスペースバッジを表示",
diff --git a/Assets/Translations/ko-KR.json b/Assets/Translations/ko-KR.json
index 7c57dbd75..4db96102b 100644
--- a/Assets/Translations/ko-KR.json
+++ b/Assets/Translations/ko-KR.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "스크롤할 때 작업 공간 전환 방향을 반대로 합니다.",
"reverse-scrolling-label": "스크롤 반전",
"show-applications-description": "각 작업 공간 내부에 애플리케이션 아이콘을 표시합니다.",
+ "show-applications-hover-description": "작업 공간에 마우스를 올렸을 때 각 작업 공간 내에 애플리케이션 아이콘을 표시합니다.",
+ "show-applications-hover-label": "마우스 오버 시 애플리케이션 표시",
"show-applications-label": "애플리케이션 표시",
"show-badge-description": "그룹화 모드에서 작업 공간 번호 배지를 표시합니다.",
"show-badge-label": "작업 공간 배지 표시",
diff --git a/Assets/Translations/nl.json b/Assets/Translations/nl.json
index a4d41d6cf..6e18d183d 100644
--- a/Assets/Translations/nl.json
+++ b/Assets/Translations/nl.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Keer de richting van het wisselen van werkruimtes om bij het scrollen.",
"reverse-scrolling-label": "Omgekeerd scrollen",
"show-applications-description": "Toon applicatiepictogrammen in elke werkruimte.",
+ "show-applications-hover-description": "Toon applicatiepictogrammen in elke werkruimte wanneer de werkruimte wordt aangewezen.",
+ "show-applications-hover-label": "Toon applicaties bij hoveren",
"show-applications-label": "Toon applicaties",
"show-badge-description": "Toon de werkomgevingnummerbadge in gegroepeerde modus.",
"show-badge-label": "Werkruimtebadge weergeven",
diff --git a/Assets/Translations/nn-NO.json b/Assets/Translations/nn-NO.json
index 84f9fe1e9..f5fb1a46f 100644
--- a/Assets/Translations/nn-NO.json
+++ b/Assets/Translations/nn-NO.json
@@ -8,6 +8,7 @@
"disable-dnd": "Slå av Ikkje forstyrr",
"disable-wifi": "Slå av Wi-Fi",
"disconnect-vpn": "Kopla frå {name}",
+ "dock-settings": "Festepunktinstillingar",
"enable-bluetooth": "Slå på Bluetooth",
"enable-dnd": "Slå på Ikkje forstyrr",
"enable-wifi": "Slå på Wi-Fi",
@@ -40,6 +41,7 @@
"audio-visualizer": {
"color-name-description": "Vel farge for visualiseraren.",
"color-name-label": "Fyll farge",
+ "height-description": "Eigendefinert komponentbreidd",
"hide-when-idle-description": "Når dette er på, gøymer visualiseraren seg med mindre noko aktivt spelar.",
"hide-when-idle-label": "Gøym når ingenting spelar av",
"width-description": "Eigendefinert komponentbreidd."
@@ -144,11 +146,13 @@
"text-stream-description": "Strøymde linjer frå kommandoen viser seg som tekst på knappen.",
"text-stream-label": "Strøym",
"wheel-description": "Kommando som køyrer når ein brukar rullehjulet.
Bruk $delta for rullehjulsdeltaen i kommandoen.",
+ "wheel-down": "Rull nedetter",
"wheel-down-description": "Kommando som køyrer når ein rullar ned på rullehjulet.",
"wheel-down-label": "Hjul ned-kommando",
"wheel-label": "Rullehjul",
"wheel-mode-separate-description": "Slår på åtskilde kommandoar for når ein rullar opp eller ned.",
"wheel-mode-separate-label": "Skilde hjulekommandoar",
+ "wheel-up": "Rull oppetter",
"wheel-up-description": "Kommando som køyrer når ein rullar opp på rullehjulet.",
"wheel-up-label": "Hjul opp-kommando",
"wheel-update-text": "Oppdater vist tekst på rulling"
@@ -209,6 +213,8 @@
"system-monitor": {
"compact-mode-description": "Viser statistikk som småe stolpediagram heller enn tekst. Stoggar oppsettet frå å skifta.",
"compact-mode-label": "Tettmodus",
+ "cpu-cores-description": "Syn prosessorkjernebruk åtskilde.",
+ "cpu-cores-label": "Prosessorkjerner",
"cpu-frequency-description": "Vis prosessorklokkefrekvens no i GHz",
"cpu-frequency-label": "Vis prosessorfrekvens",
"cpu-temperature-description": "Viser temperaturmålingar frå prosessoren om mogeleg.",
@@ -288,6 +294,8 @@
"focused-color-label": "Fokusert arbeidsområde-farge",
"follow-focused-screen-description": "Viser arbeidsrom frå den aktive skjermen, heller enn skjermen der panelet finn seg.",
"follow-focused-screen-label": "Fylg aktiv skjerm",
+ "font-weight-description": "Fastset synleg tyngd for tekst innan arbeidsrom.",
+ "font-weight-label": "Skrifttyngd",
"grouped-border-opacity-description": "Fastset kor ugjennomsynlege grensene på arbeidsromrammene er.",
"grouped-border-opacity-label": "Ugjennomsynlege grenser",
"hide-unoccupied-description": "Viser ikkje arbeidsrom utan vindaugo.",
@@ -311,6 +319,7 @@
}
},
"battery": {
+ "all-batteries": "Alle batteria (i sum)",
"battery-health": "Batterihelse",
"battery-level": "Batterinivå",
"capacity-level": "Kapasitet: {level}",
@@ -367,13 +376,16 @@
},
"common": {
"actions": "Handlingar",
+ "active": "Aktiv",
"add": "Legg til",
"appearance": "Utsjånad",
"apply": "Bruk",
+ "auto-connect": "Kopla til automatisk",
"automation": "Automatisering",
"available": "Tilgjengelege",
"back": "Attende",
"battery": "Batteri",
+ "behavior": "Åtferd",
"bluetooth": "Bluetooth",
"brightness": "Ljosstyrke",
"browse": "Blad",
@@ -396,6 +408,7 @@
"contributors": "Medverkarar",
"copied-to-clipboard": "Kopiert til utklippstavla",
"countdown": "Nedteljing",
+ "customize": "Måta til",
"date": "Dato",
"default": "Standard",
"delete": "Slett",
@@ -406,6 +419,7 @@
"disconnected": "Kopla frå",
"disconnecting": "Koplar frå...",
"display-mode": "Visingsmodus",
+ "documentation": "Dokumentasjon",
"download": "Last ned",
"duration": "Varing",
"dysfunctional": "I uorden",
@@ -417,6 +431,11 @@
"execute": "Utfør",
"faithful": "Tru",
"focus": "Fokus",
+ "font-weight-bold": "Feit",
+ "font-weight-light": "Tynn",
+ "font-weight-medium": "Mellomstor",
+ "font-weight-regular": "Vanleg",
+ "font-weight-semibold": "Halvfeit",
"frequency": "Frekvens",
"gateway": "Port",
"general": "Generell",
@@ -462,6 +481,7 @@
"panels": "Panel",
"password": "Passord",
"pause": "Pause",
+ "performance": "Yting",
"pin": "Fest",
"play": "Spel",
"polling": "Spørjing",
@@ -483,6 +503,8 @@
"scanning": "Leitar...",
"screen-corners": "Skjermhyrne",
"search": "Søk",
+ "second": "{count} sekund",
+ "second-plural": "{count} sekund",
"secondary": "Sekundær",
"security": "Trygging",
"select": "Vel",
@@ -512,6 +534,7 @@
"unpin": "Fest av",
"update": "Oppdater",
"upload": "Lasta opp",
+ "userspace-reboot": "Start brukarromet å nyo",
"version": "Versjon",
"vibrant": "Livleg",
"visualizer": "Visualiserar",
@@ -692,16 +715,20 @@
"about": {
"become-supporter": "Vert med og støtt",
"changelog": "Sjå endringar",
+ "changelog-on-startup": "Syn endringshistorikk etter oppdatering",
+ "changelog-on-startup-desc": "Syn endringshistorikken automatisk når Noctalia er oppdatert",
"contributors-description": "Takk og ære til den {count} framifrå medverkaren vår!",
"contributors-description-plural": "Takk og ære til alle dei {count} framifrå medverkarane våre!",
"copy-info": "Kopier info",
"debug-disabled": "Feilsøking av",
"debug-enabled": "Feilsøking på",
"info-copied": "Info kopiert til utklippstavla",
+ "noctalia-available": "Tilgjengeleg:",
"noctalia-desc": "Eit lettfram og minimalistisk skrivebordsskal skapa med omhug for Wayland, bygt med Quickshell.",
"noctalia-git-commit": "Git commit:",
"noctalia-installed-version": "Installert versjon:",
"noctalia-latest-version": "Nyaste versjon:",
+ "noctalia-qs-version": "Noctalia QS versjon:",
"noctalia-title": "Noctaliaskal",
"privacy-policy": "Personvernfråsegn",
"support": "Støtt oss",
@@ -709,6 +736,7 @@
"supporters-desc": "Ein stor takk til alle framifrå støttarar!",
"supporters-desc-plural": "Ein stor takk til alle {count} framifrå støttarar!",
"supporters-loading": "Lastar inn støttarar...",
+ "system-board": "Brett:",
"system-cpu": "Prosessor:",
"system-disk": "Disk:",
"system-gpu": "Skjermkort:",
@@ -765,6 +793,9 @@
"visualizer-type-description": "Vel visualiseringstypen når ein spelar av media.",
"visualizer-type-label": "Visualiseringstype",
"volumes-desc": "Endrar kontrollane for ljodstyrke og ljodnivå",
+ "volumes-feedback-sound-file-description": "Bane til ljoden som spelar av når du endrar ljodstyrke.",
+ "volumes-feedback-sound-file-label": "Ljodstyrkeendring ljodfil",
+ "volumes-feedback-sound-file-select-title": "Vel ljodfila som spelar av med ljodstyrkeendring",
"volumes-input-volume-description": "Mikrofon inn-nivå",
"volumes-mute-input-description": "Demp standard ljodinneining (mikrofon).",
"volumes-mute-input-label": "Demp ljodinndata",
@@ -790,12 +821,18 @@
"appearance-capsule-color-label": "Ilåtsfarge",
"appearance-capsule-opacity-description": "Set kor ugjennomsynlege bakgrunnen er for miniprogram når ilåtet er på skjermen.",
"appearance-capsule-opacity-label": "Ugjennomsynleg ilåt",
+ "appearance-content-padding-description": "Måta til utfyllinga mellom panelrender og miniprogram.",
+ "appearance-content-padding-label": "Innhaldsutfylling",
"appearance-density-description": "Fastset utfylling på lina for å gjera henne tett eller romsleg.",
"appearance-density-label": "Tettleik på oppgåvelina",
"appearance-desc": "Måtar til kor oppgåvelina ser ut og kvar ho er.",
"appearance-display-mode-description": "Vel når baren er synleg.",
+ "appearance-enable-exclusion-zone-inset-description": "Minska ekskluderingsona med 1 fysisk piksel slik at vindaugo som er kant-i-kant bløder saman.",
+ "appearance-enable-exclusion-zone-inset-label": "Innrykt ekskluderingssone",
"appearance-floating-description": "Viser oppgåvelina som flytande 'pille'.",
"appearance-floating-label": "Flytande oppgåvelina",
+ "appearance-font-scale-description": "Måta til skala for skriftstorleik for skrift på panelen.",
+ "appearance-font-scale-label": "Skriftskala",
"appearance-frame-radius": "Innradius",
"appearance-frame-settings-description": "Endrar rammetjukn og innradius på hyrnet",
"appearance-frame-settings-label": "Innstillingar for ramma",
diff --git a/Assets/Translations/pl.json b/Assets/Translations/pl.json
index 3f10b9cc7..eb667ed46 100644
--- a/Assets/Translations/pl.json
+++ b/Assets/Translations/pl.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Odwróć kierunek przełączania obszarów roboczych podczas przewijania.",
"reverse-scrolling-label": "Odwróć przewijanie",
"show-applications-description": "Wyświetl ikony aplikacji wewnątrz każdego obszaru roboczego.",
+ "show-applications-hover-description": "Wyświetl ikony aplikacji w każdym obszarze roboczym po najechaniu na obszar roboczy.",
+ "show-applications-hover-label": "Pokaż aplikacje po najechaniu kursorem",
"show-applications-label": "Pokaż aplikacje",
"show-badge-description": "Pokaż plakietkę z numerem obszaru roboczego w trybie grupowym.",
"show-badge-label": "Pokaż odznakę obszaru roboczego",
diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json
index 56b97347a..8fcbcf0ea 100644
--- a/Assets/Translations/pt.json
+++ b/Assets/Translations/pt.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Inverter a direção da troca de áreas de trabalho ao rolar.",
"reverse-scrolling-label": "Rolagem invertida",
"show-applications-description": "Exibir ícones de aplicativos dentro de cada espaço de trabalho.",
+ "show-applications-hover-description": "Exibir ícones de aplicativos dentro de cada área de trabalho quando a área de trabalho é sobreposta.",
+ "show-applications-hover-label": "Mostrar aplicativos ao passar o mouse",
"show-applications-label": "Mostrar aplicativos",
"show-badge-description": "Mostrar o selo do número da área de trabalho no modo agrupado.",
"show-badge-label": "Mostrar selo da área de trabalho",
diff --git a/Assets/Translations/ru.json b/Assets/Translations/ru.json
index 96b9dcdf8..b35e6665b 100644
--- a/Assets/Translations/ru.json
+++ b/Assets/Translations/ru.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Изменить направление переключения рабочих пространств при прокрутке.",
"reverse-scrolling-label": "Обратная прокрутка",
"show-applications-description": "Отображать значки приложений внутри каждого рабочего пространства.",
+ "show-applications-hover-description": "Отображать значки приложений внутри каждого рабочего пространства при наведении на него.",
+ "show-applications-hover-label": "Показывать приложения при наведении",
"show-applications-label": "Показать приложения",
"show-badge-description": "Показывать значок номера рабочего пространства в сгруппированном режиме.",
"show-badge-label": "Показывать значок рабочего стола",
diff --git a/Assets/Translations/sv.json b/Assets/Translations/sv.json
index 15481362b..8a0c38696 100644
--- a/Assets/Translations/sv.json
+++ b/Assets/Translations/sv.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Vänd riktningen för arbetsyteväxling vid rullning.",
"reverse-scrolling-label": "Omvänd rullning",
"show-applications-description": "Visa applikationsikoner i varje arbetsyta.",
+ "show-applications-hover-description": "Visa programikoner i varje arbetsyta när arbetsytan hovras över.",
+ "show-applications-hover-label": "Visa applikationer vid hovring",
"show-applications-label": "Visa applikationer",
"show-badge-description": "Visa arbetsytans nummerskylt i grupperat läge.",
"show-badge-label": "Visa arbetsytans skylt",
diff --git a/Assets/Translations/tr.json b/Assets/Translations/tr.json
index 9f15abad2..a98414138 100644
--- a/Assets/Translations/tr.json
+++ b/Assets/Translations/tr.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Kaydırırken çalışma alanı geçiş yönünü tersine çevir.",
"reverse-scrolling-label": "Ters kaydırma",
"show-applications-description": "Her çalışma alanının içinde uygulama simgelerini görüntüle.",
+ "show-applications-hover-description": "Çalışma alanının üzerine gelindiğinde, her çalışma alanının içinde uygulama simgelerini görüntüle.",
+ "show-applications-hover-label": "Üzerine gelindiğinde uygulamaları göster",
"show-applications-label": "Uygulamaları göster",
"show-badge-description": "Gruplandırılmış modda çalışma alanı numarası işaretini göster.",
"show-badge-label": "Çalışma alanı rozetini göster",
diff --git a/Assets/Translations/uk-UA.json b/Assets/Translations/uk-UA.json
index 1adb21bb7..a63d1c8e6 100644
--- a/Assets/Translations/uk-UA.json
+++ b/Assets/Translations/uk-UA.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "Змінити напрямок перемикання робочих просторів під час прокручування.",
"reverse-scrolling-label": "Зворотне прокручування",
"show-applications-description": "Відображати значки програм у кожному робочому просторі.",
+ "show-applications-hover-description": "Відображати піктограми програм всередині кожного робочого простору при наведенні на нього.",
+ "show-applications-hover-label": "Показувати програми при наведенні",
"show-applications-label": "Показати застосунки",
"show-badge-description": "Показувати значок номера робочого столу в згрупованому режимі.",
"show-badge-label": "Показати значок робочого столу",
diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json
index 9e181b10c..a401eccc9 100644
--- a/Assets/Translations/zh-CN.json
+++ b/Assets/Translations/zh-CN.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "滚动时反转工作区切换方向。",
"reverse-scrolling-label": "反转滚动",
"show-applications-description": "在每个工作区内显示应用程序图标。",
+ "show-applications-hover-description": "当鼠标悬停在工作区上时,在每个工作区内显示应用程序图标。",
+ "show-applications-hover-label": "鼠标悬停时显示应用程序",
"show-applications-label": "显示应用程序",
"show-badge-description": "在分组模式下显示工作区编号徽章。",
"show-badge-label": "显示工作区徽章",
diff --git a/Assets/Translations/zh-TW.json b/Assets/Translations/zh-TW.json
index f948273a5..23fe5d4b2 100644
--- a/Assets/Translations/zh-TW.json
+++ b/Assets/Translations/zh-TW.json
@@ -309,6 +309,8 @@
"reverse-scrolling-description": "捲動時反轉工作區切換方向。",
"reverse-scrolling-label": "反轉捲動",
"show-applications-description": "顯示各個工作區的程式圖示",
+ "show-applications-hover-description": "當滑鼠懸停在工作區上時,在每個工作區內顯示應用程式圖示。",
+ "show-applications-hover-label": "滑鼠懸停時顯示應用程式",
"show-applications-label": "顯示應用程式",
"show-badge-description": "在群組模式下顯示工作區編號徽章。",
"show-badge-label": "顯示工作區標記",
diff --git a/Assets/settings-search-index.json b/Assets/settings-search-index.json
index bf07197e0..03f4885ed 100644
--- a/Assets/settings-search-index.json
+++ b/Assets/settings-search-index.json
@@ -656,6 +656,18 @@
"Settings.data.network.bluetoothRssiPollingEnabled"
]
},
+ {
+ "labelKey": "common.auto-connect",
+ "descriptionKey": null,
+ "widget": "NCheckbox",
+ "tab": 16,
+ "tabLabel": "panels.connections.title",
+ "subTab": 1,
+ "subTabLabel": "common.bluetooth",
+ "visibleWhen": [
+ "Settings.data.network.bluetoothAutoConnect"
+ ]
+ },
{
"labelKey": "toast.airplane-mode.title",
"descriptionKey": null,
diff --git a/Assets/settings-widgets-default.json b/Assets/settings-widgets-default.json
index 61a7239e6..d810117ff 100644
--- a/Assets/settings-widgets-default.json
+++ b/Assets/settings-widgets-default.json
@@ -215,6 +215,7 @@
"hideUnoccupied": false,
"characterCount": 2,
"showApplications": false,
+ "showApplicationsHover": false,
"showLabelsOnlyWhenOccupied": true,
"colorizeIcons": false,
"unfocusedIconsOpacity": 1,
diff --git a/Commons/I18n.qml b/Commons/I18n.qml
index 7cd839350..5cb9335f8 100644
--- a/Commons/I18n.qml
+++ b/Commons/I18n.qml
@@ -187,6 +187,33 @@ Singleton {
};
}
+ // Default date format per language (used by lock screen, etc.)
+ readonly property var dateFormats: ({
+ "de": "dddd, d. MMMM",
+ "en": "dddd, MMMM d",
+ "es": "dddd, d 'de' MMMM",
+ "fr": "dddd d MMMM",
+ "hu": "dddd, MMMM d.",
+ "it": "dddd d MMMM",
+ "ja": "yyyy年M月d日 dddd",
+ "ko": "yyyy년 M월 d일 dddd",
+ "ku": "dddd, dê MMMM",
+ "nl": "dddd d MMMM",
+ "nn": "dddd d. MMMM",
+ "pl": "dddd, d MMMM",
+ "pt": "dddd, d 'de' MMMM",
+ "ru": "dddd, d MMMM",
+ "sv": "dddd d MMMM",
+ "tr": "dddd, d MMMM",
+ "uk": "dddd, d MMMM",
+ "zh": "yyyy年M月d日 dddd"
+ })
+
+ function dateFormat() {
+ var lang = langCode.split("-")[0];
+ return dateFormats[lang] || "dddd, d MMMM";
+ }
+
// -------------------------------------------
function setLanguage(newLangCode, fullLocale) {
if (typeof fullLocale === "undefined") {
diff --git a/Helpers/BluetoothUtils.js b/Helpers/BluetoothUtils.js
index e158bfbd5..879b275c7 100644
--- a/Helpers/BluetoothUtils.js
+++ b/Helpers/BluetoothUtils.js
@@ -85,8 +85,8 @@ var signalIcon = (p) => {
// Icon mapping
var deviceIcon = (name, icon) => {
- var s1 = (name || "").toLowerCase();
- var s2 = (icon || "").toLowerCase();
+ var s1 = String(name || "").toLowerCase();
+ var s2 = String(icon || "").toLowerCase();
// Prefer icon-based hints for display devices first to avoid "audio" catching TVs
var displayHints = ["display", "tv", "monitor", "projector", "screen", "chromecast", "cast"];
diff --git a/Modules/Bar/Widgets/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml
index 68d27434a..df48743af 100644
--- a/Modules/Bar/Widgets/Workspace.qml
+++ b/Modules/Bar/Widgets/Workspace.qml
@@ -69,6 +69,7 @@ Item {
// Grouped mode (show applications) settings
readonly property bool showApplications: (widgetSettings.showApplications !== undefined) ? widgetSettings.showApplications : widgetMetadata.showApplications
+ readonly property bool showApplicationsHover: (widgetSettings.showApplicationsHover !== undefined) ? widgetSettings.showApplicationsHover : widgetMetadata.showApplicationsHover
readonly property bool showLabelsOnlyWhenOccupied: (widgetSettings.showLabelsOnlyWhenOccupied !== undefined) ? widgetSettings.showLabelsOnlyWhenOccupied : widgetMetadata.showLabelsOnlyWhenOccupied
readonly property bool colorizeIcons: (widgetSettings.colorizeIcons !== undefined) ? widgetSettings.colorizeIcons : widgetMetadata.colorizeIcons
readonly property real unfocusedIconsOpacity: (widgetSettings.unfocusedIconsOpacity !== undefined) ? widgetSettings.unfocusedIconsOpacity : widgetMetadata.unfocusedIconsOpacity
@@ -106,7 +107,6 @@ Item {
}
property bool isDestroying: false
- property bool hovered: false
// Revision counter to force icon re-evaluation
property int iconRevision: 0
@@ -128,8 +128,34 @@ Item {
signal workspaceChanged(int workspaceId, color accentColor)
- implicitWidth: showApplications ? (isVertical ? groupedGrid.implicitWidth : Math.round(groupedGrid.implicitWidth + horizontalPadding * hasLabel)) : (isVertical ? barHeight : computeWidth())
- implicitHeight: showApplications ? (isVertical ? Math.round(groupedGrid.implicitHeight + horizontalPadding * 0.6 * hasLabel) : barHeight) : (isVertical ? computeHeight() : barHeight)
+ property bool isHovered: false
+
+ HoverHandler {
+ id: workspaceHoverHandler
+ enabled: showApplications && showApplicationsHover
+ onHoveredChanged: {
+ if (hovered) {
+ hoverEval.stop();
+ isHovered = true;
+ } else {
+ hoverEval.restart();
+ }
+ }
+ }
+
+ Timer {
+ id: hoverEval
+ interval: 150
+ repeat: false
+ onTriggered: {
+ isHovered = workspaceHoverHandler.hovered || contextMenu.visible;
+ }
+ }
+
+ readonly property bool appVisible: showApplications && (!showApplicationsHover || root.isHovered)
+
+ implicitWidth: appVisible ? (isVertical ? groupedGrid.implicitWidth : Math.round(groupedGrid.implicitWidth + horizontalPadding * hasLabel)) : (isVertical ? barHeight : computeWidth())
+ implicitHeight: appVisible ? (isVertical ? Math.round(groupedGrid.implicitHeight + horizontalPadding * 0.6 * hasLabel) : barHeight) : (isVertical ? computeHeight() : barHeight)
function getWorkspaceWidth(ws, activeOverride) {
const d = Math.round(capsuleHeight * root.baseDimensionRatio);
@@ -258,23 +284,27 @@ Item {
onScreenChanged: Qt.callLater(refreshWorkspaces)
onScreenNameChanged: Qt.callLater(refreshWorkspaces)
onHideUnoccupiedChanged: Qt.callLater(refreshWorkspaces)
- onShowApplicationsChanged: Qt.callLater(refreshWorkspaces)
+ onAppVisibleChanged: {
+ if (appVisible) {
+ Qt.callLater(refreshWorkspaces);
+ }
+ }
Connections {
target: CompositorService
function onWorkspacesChanged() {
- refreshWorkspaces();
+ Qt.callLater(refreshWorkspaces);
}
function onWindowListChanged() {
- if (showApplications || showLabelsOnlyWhenOccupied) {
+ if (appVisible || showLabelsOnlyWhenOccupied) {
root.windowRevision++;
- refreshWorkspaces();
+ Qt.callLater(refreshWorkspaces);
}
}
function onActiveWindowChanged() {
- if (showApplications) {
+ if (appVisible) {
root.windowRevision++;
- refreshWorkspaces();
+ Qt.callLater(refreshWorkspaces);
}
}
}
@@ -410,6 +440,15 @@ Item {
NPopupContextMenu {
id: contextMenu
+ onVisibleChanged: {
+ if (visible) {
+ hoverEval.stop();
+ root.isHovered = true;
+ } else {
+ hoverEval.restart();
+ }
+ }
+
model: {
var items = [];
if (root.selectedWindowId) {
@@ -486,7 +525,7 @@ Item {
Rectangle {
id: workspaceBackground
- visible: !showApplications
+ visible: !appVisible
width: isVertical ? capsuleHeight : parent.width
height: isVertical ? parent.height : capsuleHeight
radius: Style.radiusM
@@ -557,7 +596,15 @@ Item {
spacing: spacingBetweenPills
x: horizontalPadding
y: 0
- visible: !isVertical && !showApplications
+ visible: !isVertical && !appVisible
+ scale: visible ? 1.0 : 0.8
+ Behavior on scale {
+ NumberAnimation {
+ duration: Style.animationFast
+ easing.type: Easing.OutBack
+ easing.overshoot: 1.2
+ }
+ }
Repeater {
id: workspaceRepeaterHorizontal
@@ -592,7 +639,15 @@ Item {
spacing: spacingBetweenPills
x: 0
y: horizontalPadding
- visible: isVertical && !showApplications
+ visible: isVertical && !appVisible
+ scale: visible ? 1.0 : 0.8
+ Behavior on scale {
+ NumberAnimation {
+ duration: Style.animationFast
+ easing.type: Easing.OutBack
+ easing.overshoot: 1.2
+ }
+ }
Repeater {
id: workspaceRepeaterVertical
@@ -622,7 +677,7 @@ Item {
}
// ========================================
- // Grouped mode (showApplications = true)
+ // Grouped mode (appVisible = true)
// ========================================
Component {
id: groupedWorkspaceDelegate
@@ -645,21 +700,26 @@ Item {
}
}
- Component.onCompleted: updateWindows()
- onWorkspaceModelChanged: updateWindows()
+ // Deferred to avoid re-entrant incubation: when localWorkspaces.append()
+ Component.onCompleted: Qt.callLater(updateWindows)
+ onWorkspaceModelChanged: Qt.callLater(updateWindows)
Connections {
target: root
function onWindowRevisionChanged() {
- groupedContainer.updateWindows();
+ Qt.callLater(groupedContainer.updateWindows);
}
}
+ HoverHandler {
+ id: groupHoverHandler
+ }
+
width: Style.toOdd((hasWindows ? groupedIconsFlow.implicitWidth : root.iconSize) + (root.isVertical ? (root.baseItemSize - root.iconSize + Style.marginXS) : Style.marginXL))
height: Style.toOdd((hasWindows ? groupedIconsFlow.implicitHeight : root.iconSize) + (root.isVertical ? Style.marginL : (root.baseItemSize - root.iconSize + Style.marginXS)))
color: Style.capsuleColor
radius: Style.radiusS
- border.color: Settings.data.bar.showOutline ? Style.capsuleBorderColor : Qt.alpha((workspaceModel.isFocused ? Color.mPrimary : Color.mOutline), root.groupedBorderOpacity)
+ border.color: Settings.data.bar.showOutline ? Style.capsuleBorderColor : Qt.alpha((workspaceModel.isFocused ? Color.mPrimary : (groupHoverHandler.hovered ? Color.mHover : Color.mOutline)), root.groupedBorderOpacity)
border.width: Style.borderS
Behavior on width {
@@ -712,16 +772,19 @@ Item {
delegate: Item {
id: groupedTaskbarItem
- property bool itemHovered: false
-
width: root.iconSize
height: root.iconSize
+ HoverHandler {
+ id: windowHoverHandler
+ }
+
IconImage {
id: groupedAppIcon
width: parent.width
height: parent.height
+
source: {
root.iconRevision; // Force re-evaluation when revision changes
return ThemeIcons.iconForAppId(modelData.appId?.toLowerCase());
@@ -733,13 +796,13 @@ Item {
Rectangle {
id: groupedFocusIndicator
- visible: modelData.isFocused
+ visible: modelData.isFocused || windowHoverHandler.hovered
anchors.bottomMargin: -2
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
width: Style.toOdd(root.iconSize * 0.25)
height: 4
- color: Color.mPrimary
+ color: modelData.isFocused ? Color.mPrimary : Color.mHover
radius: Math.min(Style.radiusXXS, width / 2)
}
@@ -773,11 +836,9 @@ Item {
}
}
onEntered: {
- groupedTaskbarItem.itemHovered = true;
TooltipService.show(groupedTaskbarItem, modelData.title || modelData.appId || "Unknown app.", BarService.getTooltipDirection(root.screenName));
}
onExited: {
- groupedTaskbarItem.itemHovered = false;
TooltipService.hide();
}
}
@@ -906,7 +967,15 @@ Item {
Flow {
id: groupedGrid
- visible: showApplications
+ visible: appVisible
+ scale: visible ? 1.0 : 0.8
+ Behavior on scale {
+ NumberAnimation {
+ duration: Style.animationFast
+ easing.type: Easing.OutBack
+ easing.overshoot: 1.2
+ }
+ }
x: root.isVertical ? Style.pixelAlignCenter(parent.width, width) : Math.round(horizontalPadding * root.hasLabel)
y: root.isVertical ? Math.round(horizontalPadding * 0.4 * root.hasLabel) : Style.pixelAlignCenter(parent.height, height)
@@ -915,7 +984,7 @@ Item {
flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight
Repeater {
- model: showApplications ? localWorkspaces : null
+ model: appVisible ? localWorkspaces : null
delegate: groupedWorkspaceDelegate
}
}
diff --git a/Modules/LockScreen/LockScreenHeader.qml b/Modules/LockScreen/LockScreenHeader.qml
index d75b37c6c..cc2e71a45 100644
--- a/Modules/LockScreen/LockScreenHeader.qml
+++ b/Modules/LockScreen/LockScreenHeader.qml
@@ -118,24 +118,7 @@ Rectangle {
// Date below
NText {
text: {
- var lang = I18n.locale.name.split("_")[0];
- var formats = {
- "de": "dddd, d. MMMM",
- "en": "dddd, MMMM d",
- "es": "dddd, d 'de' MMMM",
- "fr": "dddd d MMMM",
- "hu": "dddd, MMMM d.",
- "it": "dddd d MMMM",
- "ja": "yyyy年M月d日 dddd",
- "ko": "yyyy년 M월 d일 dddd",
- "ku": "dddd, dê MMMM",
- "nl": "dddd d MMMM",
- "nn": "dddd d. MMMM",
- "pt": "dddd, d 'de' MMMM",
- "sv": "dddd d MMMM",
- "zh": "yyyy年M月d日 dddd"
- };
- var dateString = I18n.locale.toString(root.currentDate, formats[lang] || "dddd, d MMMM");
+ var dateString = I18n.locale.toString(root.currentDate, I18n.dateFormat());
return dateString.charAt(0).toUpperCase() + dateString.slice(1);
}
pointSize: Style.fontSizeXL
diff --git a/Modules/Panels/Launcher/LauncherGridDelegate.qml b/Modules/Panels/Launcher/LauncherGridDelegate.qml
index e6bc3f84c..67317c95e 100644
--- a/Modules/Panels/Launcher/LauncherGridDelegate.qml
+++ b/Modules/Panels/Launcher/LauncherGridDelegate.qml
@@ -57,7 +57,7 @@ Item {
Rectangle {
anchors.fill: parent
radius: Style.radiusM
- color: Color.mSurfaceVariant
+ color: Color.mSurface
visible: Settings.data.appLauncher.showIconBackground && !modelData.isImage
}
diff --git a/Modules/Panels/Launcher/LauncherListDelegate.qml b/Modules/Panels/Launcher/LauncherListDelegate.qml
index 63f1d767f..aba61b5bb 100644
--- a/Modules/Panels/Launcher/LauncherListDelegate.qml
+++ b/Modules/Panels/Launcher/LauncherListDelegate.qml
@@ -57,7 +57,7 @@ NBox {
Rectangle {
anchors.fill: parent
radius: Style.radiusXS
- color: Color.mSurfaceVariant
+ color: Color.mSurface
visible: Settings.data.appLauncher.showIconBackground && !modelData.isImage
}
diff --git a/Modules/Panels/Launcher/Providers/SettingsProvider.qml b/Modules/Panels/Launcher/Providers/SettingsProvider.qml
index 6ebea61b8..8993d2a30 100644
--- a/Modules/Panels/Launcher/Providers/SettingsProvider.qml
+++ b/Modules/Panels/Launcher/Providers/SettingsProvider.qml
@@ -1,6 +1,4 @@
import QtQuick
-import Quickshell
-import Quickshell.Io
import qs.Commons
import qs.Services.UI
@@ -14,23 +12,6 @@ Item {
property string supportedLayouts: "list"
property string iconMode: Settings.data.appLauncher.iconMode
- property var searchIndex: []
-
- FileView {
- id: searchIndexFile
- path: Quickshell.shellDir + "/Assets/settings-search-index.json"
- watchChanges: false
- printErrors: false
-
- onLoaded: {
- try {
- root.searchIndex = JSON.parse(text());
- } catch (e) {
- root.searchIndex = [];
- }
- }
- }
-
function init() {
Logger.d("SettingsProvider", "Initialized");
}
@@ -57,7 +38,7 @@ Item {
}
function getResults(query) {
- if (!query || searchIndex.length === 0)
+ if (!query || SettingsSearchService.searchIndex.length === 0)
return [];
var trimmed = query.trim();
@@ -78,10 +59,12 @@ Item {
return [];
}
- // Build searchable items with resolved translations
+ // Build searchable items with resolved translations, filtering out invisible entries
let items = [];
- for (let j = 0; j < searchIndex.length; j++) {
- const entry = searchIndex[j];
+ for (let j = 0; j < SettingsSearchService.searchIndex.length; j++) {
+ const entry = SettingsSearchService.searchIndex[j];
+ if (!SettingsSearchService.isEntryVisible(entry))
+ continue;
items.push({
"labelKey": entry.labelKey,
"descriptionKey": entry.descriptionKey,
@@ -133,8 +116,10 @@ Item {
function getAllSettings() {
var launcherItems = [];
- for (var j = 0; j < searchIndex.length; j++) {
- var entry = searchIndex[j];
+ for (var j = 0; j < SettingsSearchService.searchIndex.length; j++) {
+ var entry = SettingsSearchService.searchIndex[j];
+ if (!SettingsSearchService.isEntryVisible(entry))
+ continue;
var label = I18n.tr(entry.labelKey);
var tabName = I18n.tr(entry.tabLabel);
var subTabName = entry.subTabLabel ? I18n.tr(entry.subTabLabel) : "";
diff --git a/Modules/Panels/Settings/Bar/WidgetSettings/WorkspaceSettings.qml b/Modules/Panels/Settings/Bar/WidgetSettings/WorkspaceSettings.qml
index 5a3ac254e..5606df081 100644
--- a/Modules/Panels/Settings/Bar/WidgetSettings/WorkspaceSettings.qml
+++ b/Modules/Panels/Settings/Bar/WidgetSettings/WorkspaceSettings.qml
@@ -22,6 +22,7 @@ ColumnLayout {
// Grouped mode settings
property bool valueShowApplications: widgetData.showApplications !== undefined ? widgetData.showApplications : widgetMetadata.showApplications
+ property bool valueShowApplicationsHover: widgetData.showApplicationsHover !== undefined ? widgetData.showApplicationsHover : widgetMetadata.showApplicationsHover
property bool valueShowLabelsOnlyWhenOccupied: widgetData.showLabelsOnlyWhenOccupied !== undefined ? widgetData.showLabelsOnlyWhenOccupied : widgetMetadata.showLabelsOnlyWhenOccupied
property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons
property real valueUnfocusedIconsOpacity: widgetData.unfocusedIconsOpacity !== undefined ? widgetData.unfocusedIconsOpacity : widgetMetadata.unfocusedIconsOpacity
@@ -42,6 +43,7 @@ ColumnLayout {
settings.characterCount = valueCharacterCount;
settings.followFocusedScreen = valueFollowFocusedScreen;
settings.showApplications = valueShowApplications;
+ settings.showApplicationsHover = valueShowApplicationsHover;
settings.showLabelsOnlyWhenOccupied = valueShowLabelsOnlyWhenOccupied;
settings.colorizeIcons = valueColorizeIcons;
settings.unfocusedIconsOpacity = valueUnfocusedIconsOpacity;
@@ -201,6 +203,17 @@ ColumnLayout {
}
}
+ NToggle {
+ label: I18n.tr("bar.workspace.show-applications-hover-label")
+ description: I18n.tr("bar.workspace.show-applications-hover-description")
+ checked: valueShowApplicationsHover
+ onToggled: checked => {
+ valueShowApplicationsHover = checked;
+ saveSettings();
+ }
+ visible: valueShowApplications
+ }
+
NToggle {
label: I18n.tr("bar.workspace.show-badge-label")
description: I18n.tr("bar.workspace.show-badge-description")
diff --git a/Modules/Panels/Settings/SettingsContent.qml b/Modules/Panels/Settings/SettingsContent.qml
index d4c6cf1cd..6b4087bab 100644
--- a/Modules/Panels/Settings/SettingsContent.qml
+++ b/Modules/Panels/Settings/SettingsContent.qml
@@ -2,7 +2,6 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
-import Quickshell.Io
import qs.Commons
import qs.Modules.Panels.Settings.Tabs
import qs.Modules.Panels.Settings.Tabs.About
@@ -53,7 +52,6 @@ Item {
// Search state
property string searchText: ""
- property var searchIndex: []
property var searchResults: []
property int searchSelectedIndex: 0
property string highlightLabelKey: ""
@@ -76,159 +74,6 @@ Item {
// Signal when close button is clicked
signal closeRequested
- // Load search index
- FileView {
- id: searchIndexFile
- path: Quickshell.shellDir + "/Assets/settings-search-index.json"
- watchChanges: false
- printErrors: false
-
- onLoaded: {
- try {
- root.searchIndex = JSON.parse(text());
- } catch (e) {
- root.searchIndex = [];
- }
- }
- }
-
- // Visibility condition evaluation for search filtering.
- // Resolves a dotted property path on a known root object.
- function _resolveValue(path) {
- const roots = {
- "CompositorService": CompositorService,
- "Settings": Settings,
- "Quickshell": Quickshell,
- "IdleService": IdleService,
- "SystemStatService": SystemStatService,
- "SoundService": SoundService
- };
-
- const parts = path.split(".");
- const rootObj = roots[parts[0]];
- if (rootObj === undefined)
- return undefined;
-
- let obj = rootObj;
- for (let i = 1; i < parts.length; i++) {
- if (obj === undefined || obj === null)
- return undefined;
- // Strip optional chaining marker (e.g. "sounds?" -> "sounds")
- let key = parts[i];
- if (key.endsWith("?"))
- key = key.slice(0, -1);
- obj = obj[key];
- }
- return obj;
- }
-
- // Split an expression on top-level && (respecting parentheses).
- function _splitAnd(expr) {
- const parts = [];
- let depth = 0;
- let current = "";
- for (let i = 0; i < expr.length; i++) {
- const ch = expr[i];
- if (ch === "(")
- depth++;
- else if (ch === ")")
- depth--;
- else if (depth === 0 && ch === "&" && i + 1 < expr.length && expr[i + 1] === "&") {
- parts.push(current);
- current = "";
- i++; // skip second &
- continue;
- }
- current += ch;
- }
- parts.push(current);
- return parts;
- }
-
- // Evaluate a single visibility condition expression.
- // Returns true if the condition is met (item should be visible).
- // Falls back to true for unrecognized expressions.
- function _evalCondition(expr) {
- expr = expr.trim();
-
- // Strip outer parentheses
- if (expr.startsWith("(") && expr.endsWith(")")) {
- let depth = 0;
- let allWrapped = true;
- for (let i = 0; i < expr.length - 1; i++) {
- if (expr[i] === "(")
- depth++;
- else if (expr[i] === ")")
- depth--;
- if (depth === 0) {
- allWrapped = false;
- break;
- }
- }
- if (allWrapped)
- return _evalCondition(expr.slice(1, -1));
- }
-
- // AND: all parts must be true
- if (expr.includes("&&")) {
- const parts = _splitAnd(expr);
- if (parts.length > 1) {
- for (let i = 0; i < parts.length; i++) {
- if (!_evalCondition(parts[i]))
- return false;
- }
- return true;
- }
- }
-
- // Negation
- if (expr.startsWith("!"))
- return !_evalCondition(expr.slice(1).trim());
-
- // Literal false
- if (expr === "false")
- return false;
-
- // Strip nullish coalescing fallback (e.g. "expr ?? false")
- const nullishMatch = expr.match(/^(.+?)\s*\?\?\s*(?:false|true)\s*$/);
- if (nullishMatch)
- return _evalCondition(nullishMatch[1]);
-
- // === comparison
- let m = expr.match(/^(.+?)\s*===\s*"([^"]*)"\s*$/);
- if (m)
- return _resolveValue(m[1].trim()) === m[2];
-
- // !== comparison
- m = expr.match(/^(.+?)\s*!==\s*"([^"]*)"\s*$/);
- if (m)
- return _resolveValue(m[1].trim()) !== m[2];
-
- // > comparison
- m = expr.match(/^(.+?)\s*>\s*(\d+)\s*$/);
- if (m)
- return _resolveValue(m[1].trim()) > parseInt(m[2]);
-
- // Simple property path — resolve and return truthiness
- const val = _resolveValue(expr);
- if (val !== undefined)
- return !!val;
-
- // Unrecognized expression — assume visible
- return true;
- }
-
- // Check if a search index entry is currently visible.
- function _isEntryVisible(entry) {
- if (!entry.visibleWhen || entry.visibleWhen.length === 0)
- return true;
- for (let i = 0; i < entry.visibleWhen.length; i++) {
- if (!_evalCondition(entry.visibleWhen[i]))
- return false;
- }
- return true;
- }
-
// Search function
onSearchTextChanged: {
if (searchText.trim() === "") {
@@ -249,14 +94,14 @@ Item {
root.sidebarExpanded = true;
}
- if (searchIndex.length === 0)
+ if (SettingsSearchService.searchIndex.length === 0)
return;
// Build searchable items with resolved translations, filtering out invisible entries
let items = [];
- for (let j = 0; j < searchIndex.length; j++) {
- const entry = searchIndex[j];
- if (!_isEntryVisible(entry))
+ for (let j = 0; j < SettingsSearchService.searchIndex.length; j++) {
+ const entry = SettingsSearchService.searchIndex[j];
+ if (!SettingsSearchService.isEntryVisible(entry))
continue;
items.push({
"labelKey": entry.labelKey,
diff --git a/Modules/Panels/Settings/SettingsPanelWindow.qml b/Modules/Panels/Settings/SettingsPanelWindow.qml
index 3b7e8aed6..279f6a517 100644
--- a/Modules/Panels/Settings/SettingsPanelWindow.qml
+++ b/Modules/Panels/Settings/SettingsPanelWindow.qml
@@ -83,16 +83,32 @@ FloatingWindow {
onActivated: settingsContent.selectPreviousTab()
}
- Shortcut {
- sequence: "Up"
- enabled: !PanelService.isKeybindRecording
- onActivated: settingsContent.scrollUp()
+ Instantiator {
+ model: Settings.data.general.keybinds.keyUp || []
+ Shortcut {
+ sequence: modelData
+ enabled: !PanelService.isKeybindRecording
+ onActivated: {
+ if (settingsContent.searchText.trim() !== "")
+ settingsContent.searchSelectPrevious();
+ else
+ settingsContent.scrollUp();
+ }
+ }
}
- Shortcut {
- sequence: "Down"
- enabled: !PanelService.isKeybindRecording
- onActivated: settingsContent.scrollDown()
+ Instantiator {
+ model: Settings.data.general.keybinds.keyDown || []
+ Shortcut {
+ sequence: modelData
+ enabled: !PanelService.isKeybindRecording
+ onActivated: {
+ if (settingsContent.searchText.trim() !== "")
+ settingsContent.searchSelectNext();
+ else
+ settingsContent.scrollDown();
+ }
+ }
}
// Main content
diff --git a/Modules/Panels/Settings/Tabs/Connections/BluetoothSubTab.qml b/Modules/Panels/Settings/Tabs/Connections/BluetoothSubTab.qml
index 7db8d6319..00142478c 100644
--- a/Modules/Panels/Settings/Tabs/Connections/BluetoothSubTab.qml
+++ b/Modules/Panels/Settings/Tabs/Connections/BluetoothSubTab.qml
@@ -671,24 +671,14 @@ Item {
icon: BluetoothService.getDeviceAutoConnect(modelData.address) ? "repeat" : "repeat-off"
pointSize: Style.fontSizeXS
color: BluetoothService.getDeviceAutoConnect(modelData.address) ? Color.mPrimary : Color.mOnSurface
- Layout.alignment: Qt.AlignVCenter
}
- NText {
- text: I18n.tr("common.auto-connect")
- pointSize: Style.fontSizeXS
- color: BluetoothService.getDeviceAutoConnect(modelData.address) ? Color.mOnSurface : Color.mOnSurfaceVariant
- Layout.fillWidth: true
- Layout.alignment: Qt.AlignVCenter
-
- MouseArea {
- anchors.fill: parent
- hoverEnabled: true
- cursorShape: Qt.PointingHandCursor
- onEntered: TooltipService.show(parent, BluetoothService.getDeviceAutoConnect(modelData.address) ? I18n.tr("tooltips.bluetooth-auto-connect-on") : I18n.tr("tooltips.bluetooth-auto-connect-off"))
- onExited: TooltipService.hide()
- onClicked: BluetoothService.setDeviceAutoConnect(modelData, !BluetoothService.getDeviceAutoConnect(modelData.address))
- }
+ NCheckbox {
+ label: I18n.tr("common.auto-connect")
+ labelSize: Style.fontSizeXS
+ baseSize: Style.baseWidgetSize * 0.6
+ checked: BluetoothService.getDeviceAutoConnect(modelData.address)
+ onToggled: checked => BluetoothService.setDeviceAutoConnect(modelData, checked)
}
}
}
diff --git a/Services/Compositor/CompositorService.qml b/Services/Compositor/CompositorService.qml
index eaff86edc..f9f7427ef 100644
--- a/Services/Compositor/CompositorService.qml
+++ b/Services/Compositor/CompositorService.qml
@@ -211,10 +211,7 @@ Singleton {
});
backend.windowListChanged.connect(() => {
- // Sync windows when they change
syncWindows();
- // Forward the signal
- windowListChanged();
});
// Property bindings - use automatic property change signal
diff --git a/Services/Noctalia/UpdateService.qml b/Services/Noctalia/UpdateService.qml
index 012a4b7bb..0f0473377 100644
--- a/Services/Noctalia/UpdateService.qml
+++ b/Services/Noctalia/UpdateService.qml
@@ -11,7 +11,7 @@ Singleton {
id: root
// Version properties
- readonly property string baseVersion: "4.6.7"
+ readonly property string baseVersion: "4.6.8"
readonly property bool isDevelopment: true
readonly property string developmentSuffix: "-git"
readonly property string currentVersion: `v${!isDevelopment ? baseVersion : baseVersion + developmentSuffix}`
diff --git a/Services/UI/BarWidgetRegistry.qml b/Services/UI/BarWidgetRegistry.qml
index 238d5f281..2c0461da0 100644
--- a/Services/UI/BarWidgetRegistry.qml
+++ b/Services/UI/BarWidgetRegistry.qml
@@ -293,6 +293,7 @@ Singleton {
"hideUnoccupied": false,
"characterCount": 2,
"showApplications": false,
+ "showApplicationsHover": false,
"showLabelsOnlyWhenOccupied": true,
"colorizeIcons": false,
"unfocusedIconsOpacity": 1.0,
diff --git a/Services/UI/SettingsSearchService.qml b/Services/UI/SettingsSearchService.qml
new file mode 100644
index 000000000..50dc7ac56
--- /dev/null
+++ b/Services/UI/SettingsSearchService.qml
@@ -0,0 +1,158 @@
+pragma Singleton
+
+import QtQuick
+import Quickshell
+import Quickshell.Io
+import qs.Commons
+import qs.Services.Compositor
+import qs.Services.Power
+import qs.Services.System
+
+Singleton {
+ id: root
+
+ property var searchIndex: []
+
+ FileView {
+ path: Quickshell.shellDir + "/Assets/settings-search-index.json"
+ watchChanges: false
+ printErrors: false
+
+ onLoaded: {
+ try {
+ root.searchIndex = JSON.parse(text());
+ } catch (e) {
+ root.searchIndex = [];
+ }
+ }
+ }
+
+ readonly property var _roots: ({
+ "CompositorService": CompositorService,
+ "Settings": Settings,
+ "Quickshell": Quickshell,
+ "IdleService": IdleService,
+ "SystemStatService": SystemStatService,
+ "SoundService": SoundService
+ })
+
+ function isEntryVisible(entry) {
+ if (!entry.visibleWhen || entry.visibleWhen.length === 0)
+ return true;
+ for (let i = 0; i < entry.visibleWhen.length; i++) {
+ if (!_evalCondition(entry.visibleWhen[i]))
+ return false;
+ }
+ return true;
+ }
+
+ function _resolveValue(path) {
+ const parts = path.split(".");
+ const rootObj = _roots[parts[0]];
+ if (rootObj === undefined)
+ return undefined;
+
+ let obj = rootObj;
+ for (let i = 1; i < parts.length; i++) {
+ if (obj === undefined || obj === null)
+ return undefined;
+ let key = parts[i];
+ if (key.endsWith("?"))
+ key = key.slice(0, -1);
+ obj = obj[key];
+ }
+ return obj;
+ }
+
+ function _splitAnd(expr) {
+ const parts = [];
+ let depth = 0;
+ let current = "";
+ for (let i = 0; i < expr.length; i++) {
+ const ch = expr[i];
+ if (ch === "(")
+ depth++;
+ else if (ch === ")")
+ depth--;
+ else if (depth === 0 && ch === "&" && i + 1 < expr.length && expr[i + 1] === "&") {
+ parts.push(current);
+ current = "";
+ i++;
+ continue;
+ }
+ current += ch;
+ }
+ parts.push(current);
+ return parts;
+ }
+
+ function _evalCondition(expr) {
+ expr = expr.trim();
+
+ // Strip outer parentheses
+ if (expr.startsWith("(") && expr.endsWith(")")) {
+ let depth = 0;
+ let allWrapped = true;
+ for (let i = 0; i < expr.length - 1; i++) {
+ if (expr[i] === "(")
+ depth++;
+ else if (expr[i] === ")")
+ depth--;
+ if (depth === 0) {
+ allWrapped = false;
+ break;
+ }
+ }
+ if (allWrapped)
+ return _evalCondition(expr.slice(1, -1));
+ }
+
+ // AND: all parts must be true
+ if (expr.includes("&&")) {
+ const parts = _splitAnd(expr);
+ if (parts.length > 1) {
+ for (let i = 0; i < parts.length; i++) {
+ if (!_evalCondition(parts[i]))
+ return false;
+ }
+ return true;
+ }
+ }
+
+ // Negation
+ if (expr.startsWith("!"))
+ return !_evalCondition(expr.slice(1).trim());
+
+ // Literal false
+ if (expr === "false")
+ return false;
+
+ // Strip nullish coalescing fallback
+ const nullishMatch = expr.match(/^(.+?)\s*\?\?\s*(?:false|true)\s*$/);
+ if (nullishMatch)
+ return _evalCondition(nullishMatch[1]);
+
+ // === comparison
+ let m = expr.match(/^(.+?)\s*===\s*"([^"]*)"\s*$/);
+ if (m)
+ return _resolveValue(m[1].trim()) === m[2];
+
+ // !== comparison
+ m = expr.match(/^(.+?)\s*!==\s*"([^"]*)"\s*$/);
+ if (m)
+ return _resolveValue(m[1].trim()) !== m[2];
+
+ // > comparison
+ m = expr.match(/^(.+?)\s*>\s*(\d+)\s*$/);
+ if (m)
+ return _resolveValue(m[1].trim()) > parseInt(m[2]);
+
+ // Simple property path — resolve and return truthiness
+ const val = _resolveValue(expr);
+ if (val !== undefined)
+ return !!val;
+
+ // Unrecognized expression — assume visible
+ return true;
+ }
+}
diff --git a/Widgets/NCheckbox.qml b/Widgets/NCheckbox.qml
index 09ed49f7f..1f363a3b8 100644
--- a/Widgets/NCheckbox.qml
+++ b/Widgets/NCheckbox.qml
@@ -14,6 +14,7 @@ RowLayout {
property color activeColor: Color.mPrimary
property color activeOnColor: Color.mOnPrimary
property int baseSize: Style.baseWidgetSize * 0.7
+ property real labelSize: Style.fontSizeL
signal toggled(bool checked)
signal entered
@@ -24,6 +25,7 @@ RowLayout {
NLabel {
label: root.label
+ labelSize: root.labelSize
description: root.description
visible: root.label !== "" || root.description !== ""
}
diff --git a/Widgets/NLabel.qml b/Widgets/NLabel.qml
index 626a3709e..71073fca7 100644
--- a/Widgets/NLabel.qml
+++ b/Widgets/NLabel.qml
@@ -14,6 +14,7 @@ ColumnLayout {
property color iconColor: Color.mOnSurface
property bool showIndicator: false
property string indicatorTooltip: ""
+ property real labelSize: Style.fontSizeL
opacity: enabled ? 1.0 : 0.6
spacing: Style.marginXXS
@@ -38,7 +39,7 @@ ColumnLayout {
id: labelText
Layout.fillWidth: true
text: root.label
- pointSize: Style.fontSizeL
+ pointSize: root.labelSize
font.weight: Style.fontWeightSemiBold
color: labelColor
wrapMode: Text.WordWrap