Merge branch 'main' into main

This commit is contained in:
Lemmy
2025-12-07 17:37:51 -05:00
committed by GitHub
65 changed files with 2614 additions and 2488 deletions
+2 -1
View File
@@ -1,3 +1,4 @@
.qmlls.ini
.zed
.idea
.idea
.vscode
+36 -36
View File
@@ -1,38 +1,38 @@
{
"dark": {
"mPrimary": "#7aa2f7",
"mOnPrimary": "#16161e",
"mSecondary": "#bb9af7",
"mOnSecondary": "#16161e",
"mTertiary": "#9ece6a",
"mOnTertiary": "#16161e",
"mError": "#f7768e",
"mOnError": "#16161e",
"mSurface": "#1a1b26",
"mOnSurface": "#c0caf5",
"mSurfaceVariant": "#24283b",
"mOnSurfaceVariant": "#9aa5ce",
"mOutline": "#565f89",
"mShadow": "#15161e",
"mHover": "#9ece6a",
"mOnHover": "#16161e"
},
"light": {
"mPrimary": "#2e7de9",
"mOnPrimary": "#e1e2e7",
"mSecondary": "#9854f1",
"mOnSecondary": "#e1e2e7",
"mTertiary": "#587539",
"mOnTertiary": "#e1e2e7",
"mError": "#f52a65",
"mOnError": "#e1e2e7",
"mSurface": "#e1e2e7",
"mOnSurface": "#3760bf",
"mSurfaceVariant": "#d0d5e3",
"mOnSurfaceVariant": "#6172b0",
"mOutline": "#b4b5b9",
"mShadow": "#a8aecb",
"mHover": "#587539",
"mOnHover": "#e1e2e7"
}
"dark": {
"mPrimary": "#7aa2f7",
"mOnPrimary": "#16161e",
"mSecondary": "#bb9af7",
"mOnSecondary": "#16161e",
"mTertiary": "#9ece6a",
"mOnTertiary": "#16161e",
"mError": "#f7768e",
"mOnError": "#16161e",
"mSurface": "#1a1b26",
"mOnSurface": "#c0caf5",
"mSurfaceVariant": "#24283b",
"mOnSurfaceVariant": "#9aa5ce",
"mOutline": "#353D57",
"mShadow": "#15161e",
"mHover": "#9ece6a",
"mOnHover": "#16161e"
},
"light": {
"mPrimary": "#2e7de9",
"mOnPrimary": "#e1e2e7",
"mSecondary": "#9854f1",
"mOnSecondary": "#e1e2e7",
"mTertiary": "#587539",
"mOnTertiary": "#e1e2e7",
"mError": "#f52a65",
"mOnError": "#e1e2e7",
"mSurface": "#e1e2e7",
"mOnSurface": "#3760bf",
"mSurfaceVariant": "#d0d5e3",
"mOnSurfaceVariant": "#6172b0",
"mOutline": "#b4b5b9",
"mShadow": "#a8aecb",
"mHover": "#587539",
"mOnHover": "#e1e2e7"
}
}
+504 -1665
View File
File diff suppressed because it is too large Load Diff
+40 -2
View File
@@ -140,6 +140,13 @@
"stream-description": "Geben Sie einen Befehl ein, der kontinuierlich ausgeführt werden soll."
},
"dynamic-text": "Dynamischer Text",
"hide-mode": {
"alwaysExpanded": "Immer erweitert",
"description": "Steuert die Sichtbarkeit des Widgets, wenn der Befehl keine Ausgabe hat.",
"expandWithOutput": "Mit Ausgabe erweitern",
"label": "Ausblendmodus",
"maxTransparent": "Maximal erweitert aber transparent"
},
"icon": {
"description": "Symbol aus der Bibliothek auswählen.",
"label": "Symbol"
@@ -175,6 +182,10 @@
"label": "Rechtsklick",
"update-text": "Text beim Rechtsklick aktualisieren"
},
"show-icon": {
"description": "Schaltet die Sichtbarkeit des Widget-Symbols um.",
"label": "Symbol anzeigen"
},
"text-stream": {
"description": "Gestreamte Zeilen aus dem Befehl werden als Text auf der Schaltfläche angezeigt.",
"label": "Stream"
@@ -343,6 +354,9 @@
"description": "Breite der Fenstertitel in der Taskleiste festlegen (in Pixel).",
"label": "Titelbreite",
"reset-tooltip": "Titelbreite zurücksetzen"
"show-pinned-apps": {
"description": "Angeheftete Apps aus dem Dock in der Taskleiste anzeigen.",
"label": "Angeheftete Apps anzeigen"
}
},
"taskbar-grouped": {
@@ -359,6 +373,10 @@
"drawer-enabled": {
"description": "Wenn aktiviert, werden nicht angeheftete Tray-Elemente in einem Schubladen-Panel angezeigt. Wenn deaktiviert, werden alle Tray-Elemente inline angezeigt.",
"label": "Schublade aktivieren"
},
"hide-passive": {
"description": "Wenn aktiviert, werden Tray-Elemente mit dem Status \"Passiv\" ausgeblendet.",
"label": "Passive Gegenstände ausblenden"
}
},
"volume": {
@@ -531,11 +549,12 @@
"misc": "Verschiedenes",
"network": "Netzwerk",
"office": "Büro",
"pinned": "Angeheftet",
"system": "System",
"webbrowser": "Webbrowser"
},
"pin": "An das Dock anheften",
"unpin": "Vom Dock lösen"
"pin": "Anheften",
"unpin": "Lösen"
},
"lock-screen": {
"authenticating": "Authentifizierung...",
@@ -736,6 +755,9 @@
"clipboard-loading": "Lade Zwischenablageverlauf...",
"clipboard-loading-description": "Bitte warten",
"clipboard-search-description": "Zwischenablageverlauf durchsuchen",
"command": "Befehl",
"command-description": "Shell-Befehle ausführen",
"command-name": "Befehl",
"emoji": "Emoji-Auswahl",
"emoji-loading": "Lade Emojis...",
"emoji-loading-description": "Bitte warten",
@@ -1337,6 +1359,10 @@
"description": "Theme-Farben auf Dock-App-Symbole anwenden (nur nicht fokussierte Apps).",
"label": "Symbole einfärben"
},
"dead-opacity": {
"description": "Die Deckkraft von App-Symbolen anpassen, die nicht ausgeführt werden.",
"label": "Tote Opazität"
},
"display": {
"always-visible": "Immer sichtbar",
"auto-hide": "Automatisch ausblenden",
@@ -1352,6 +1378,14 @@
"description": "Gesamtgröße des Docks anpassen.",
"label": "Dock-Größe"
},
"inactive-indicators": {
"description": "Anzeige von Indikator-Pillen für alle Apps, nicht nur für die aktuell aktive.",
"label": "Laufende Indikatoren"
},
"pinned-static": {
"description": "Gepinnten App-Symbole immer in statischer Reihenfolge nach links schieben.",
"label": "Statische angeheftete Apps"
},
"section": {
"description": "Verhalten und Erscheinungsbild des Docks anpassen.",
"label": "Erscheinungsbild"
@@ -1513,6 +1547,10 @@
"description": "Verhalten und Erscheinungsbild des Starters anpassen.",
"label": "Erscheinungsbild"
},
"show-categories": {
"description": "Kategorienregisterkarten zum Filtern von Anwendungen anzeigen.",
"label": "Kategorien anzeigen"
},
"sort-by-usage": {
"description": "Wenn aktiviert, erscheinen häufig gestartete Apps zuerst in der Liste.",
"label": "Nach Häufigkeit sortieren"
+40 -2
View File
@@ -140,6 +140,13 @@
"stream-description": "Enter a command to run continuously."
},
"dynamic-text": "Dynamic text",
"hide-mode": {
"alwaysExpanded": "Always expanded",
"description": "Controls widget visibility when the command has no output.",
"expandWithOutput": "Expand when has output",
"label": "Hide mode",
"maxTransparent": "Max expanded but transparent"
},
"icon": {
"description": "Select an icon from the library.",
"label": "Icon"
@@ -175,6 +182,10 @@
"label": "Right click",
"update-text": "Update displayed text on right-click"
},
"show-icon": {
"description": "Toggles the visibility of the widget's icon.",
"label": "Show icon"
},
"text-stream": {
"description": "Streamed lines from the command will be displayed as text on the button.",
"label": "Stream"
@@ -343,6 +354,9 @@
"description": "Set the width of window titles in the taskbar (in pixels).",
"label": "Title width",
"reset-tooltip": "Reset title width"
"show-pinned-apps": {
"description": "Show pinned apps from the dock in the taskbar.",
"label": "Show pinned apps"
}
},
"taskbar-grouped": {
@@ -359,6 +373,10 @@
"drawer-enabled": {
"description": "When enabled, unpinned tray items are shown in a drawer panel. When disabled, all tray items are shown inline.",
"label": "Enable drawer"
},
"hide-passive": {
"description": "When enabled, tray items with Passive status will be hidden.",
"label": "Hide passive items"
}
},
"volume": {
@@ -531,11 +549,12 @@
"misc": "Misc",
"network": "Network",
"office": "Office",
"pinned": "Pinned",
"system": "System",
"webbrowser": "Web Browser"
},
"pin": "Pin to dock",
"unpin": "Unpin from dock"
"pin": "Pin",
"unpin": "Unpin"
},
"lock-screen": {
"authenticating": "Authenticating...",
@@ -736,6 +755,9 @@
"clipboard-loading": "Loading clipboard history...",
"clipboard-loading-description": "Please wait",
"clipboard-search-description": "Search clipboard history",
"command": "Command",
"command-description": "Run shell commands",
"command-name": "Command",
"emoji": "Emoji picker",
"emoji-loading": "Loading emojis...",
"emoji-loading-description": "Please wait",
@@ -1337,6 +1359,10 @@
"description": "Apply theme colors to dock app icons (non-focused apps only).",
"label": "Colorize Icons"
},
"dead-opacity": {
"description": "Adjust the opacity of app icons that are not running.",
"label": "Dead Opacity"
},
"display": {
"always-visible": "Always visible",
"auto-hide": "Auto hide",
@@ -1352,6 +1378,14 @@
"description": "Adjust the overall size of the dock.",
"label": "Dock size"
},
"inactive-indicators": {
"description": "Display indicatator pills for all apps, not just the currently active one.",
"label": "Running Indicators"
},
"pinned-static": {
"description": "Always push pinned app icons to the left in static order.",
"label": "Static Pinned Apps"
},
"section": {
"description": "Customize the dock's behavior and appearance.",
"label": "Appearance"
@@ -1513,6 +1547,10 @@
"description": "Customize the launcher's behavior and appearance.",
"label": "Appearance"
},
"show-categories": {
"description": "Show category tabs for filtering applications.",
"label": "Show categories"
},
"sort-by-usage": {
"description": "When enabled, frequently launched apps appear first in the list.",
"label": "Sort by most used"
+40 -2
View File
@@ -140,6 +140,13 @@
"stream-description": "Introduce un comando para ejecutar continuamente."
},
"dynamic-text": "Texto dinámico",
"hide-mode": {
"alwaysExpanded": "Siempre expandido",
"description": "Controla la visibilidad del widget cuando el comando no tiene salida.",
"expandWithOutput": "Expandir cuando tiene salida",
"label": "Modo de ocultar",
"maxTransparent": "Máximo expandido pero transparente"
},
"icon": {
"description": "Selecciona un icono de la biblioteca.",
"label": "Icono"
@@ -175,6 +182,10 @@
"label": "Clic derecho",
"update-text": "Actualizar el texto mostrado al hacer clic derecho"
},
"show-icon": {
"description": "Alterna la visibilidad del icono del widget.",
"label": "Mostrar icono"
},
"text-stream": {
"description": "Las líneas transmitidas desde el comando se mostrarán como texto en el botón.",
"label": "Transmisión"
@@ -343,6 +354,9 @@
"description": "Establecer el ancho de los títulos de ventanas en la barra de tareas (en píxeles).",
"label": "Ancho del título",
"reset-tooltip": "Restablecer ancho del título"
"show-pinned-apps": {
"description": "Mostrar las aplicaciones ancladas desde el dock en la barra de tareas.",
"label": "Mostrar aplicaciones ancladas"
}
},
"taskbar-grouped": {
@@ -359,6 +373,10 @@
"drawer-enabled": {
"description": "Cuando está habilitado, los elementos de la bandeja no anclados se muestran en un panel cajón. Cuando está deshabilitado, todos los elementos de la bandeja se muestran en línea.",
"label": "Habilitar cajón"
},
"hide-passive": {
"description": "Cuando está activado, los elementos de la bandeja con estado Pasivo se ocultarán.",
"label": "Ocultar objetos pasivos"
}
},
"volume": {
@@ -531,11 +549,12 @@
"misc": "Varios",
"network": "Red",
"office": "Oficina",
"pinned": "Anclado",
"system": "Sistema",
"webbrowser": "Navegador web"
},
"pin": "Anclar al dock",
"unpin": "Desanclar del dock"
"pin": "Anclar",
"unpin": "Desanclar"
},
"lock-screen": {
"authenticating": "Autenticando...",
@@ -736,6 +755,9 @@
"clipboard-loading": "Cargando historial del portapapeles...",
"clipboard-loading-description": "Por favor espera",
"clipboard-search-description": "Buscar en el historial del portapapeles",
"command": "Comando",
"command-description": "Ejecutar comandos de shell",
"command-name": "Comando",
"emoji": "Selector de emojis",
"emoji-loading": "Cargando emojis...",
"emoji-loading-description": "Por favor espera",
@@ -1337,6 +1359,10 @@
"description": "Aplicar colores del tema a los iconos de aplicaciones del dock (solo aplicaciones no enfocadas).",
"label": "Colorear iconos"
},
"dead-opacity": {
"description": "Ajustar la opacidad de los iconos de las aplicaciones que no están en ejecución.",
"label": "Opacidad Muerta"
},
"display": {
"always-visible": "Siempre visible",
"auto-hide": "Ocultar automáticamente",
@@ -1352,6 +1378,14 @@
"description": "Ajusta el tamaño general del Dock.",
"label": "Tamaño del Dock"
},
"inactive-indicators": {
"description": "Mostrar indicadores en forma de pastillas para todas las aplicaciones, no solo para la que está activa actualmente.",
"label": "Indicadores de ejecución"
},
"pinned-static": {
"description": "Siempre empuja los iconos de las aplicaciones ancladas a la izquierda en orden estático.",
"label": "Aplicaciones ancladas estáticas"
},
"section": {
"description": "Personaliza el comportamiento y la apariencia del dock.",
"label": "Apariencia"
@@ -1513,6 +1547,10 @@
"description": "Personaliza el comportamiento y la apariencia del lanzador.",
"label": "Apariencia"
},
"show-categories": {
"description": "Mostrar pestañas de categorías para filtrar aplicaciones.",
"label": "Mostrar categorías"
},
"sort-by-usage": {
"description": "Cuando está activado, las aplicaciones más utilizadas aparecen primero en la lista.",
"label": "Ordenar por más usados"
+40 -2
View File
@@ -140,6 +140,13 @@
"stream-description": "Entrez une commande à exécuter en continu."
},
"dynamic-text": "Texte dynamique",
"hide-mode": {
"alwaysExpanded": "Toujours étendu",
"description": "Contrôle la visibilité du widget quand la commande n'a pas de sortie.",
"expandWithOutput": "Étendre quand il y a une sortie",
"label": "Mode masqué",
"maxTransparent": "Étendu au maximum mais transparent"
},
"icon": {
"description": "Sélectionnez une icône dans la bibliothèque.",
"label": "Icône"
@@ -175,6 +182,10 @@
"label": "Clic droit",
"update-text": "Mettre à jour le texte affiché lors d'un clic droit."
},
"show-icon": {
"description": "Bascule la visibilité de l'icône du widget.",
"label": "Afficher l'icône"
},
"text-stream": {
"description": "Les lignes diffusées depuis la commande seront affichées sous forme de texte sur le bouton.",
"label": "Flux"
@@ -343,6 +354,9 @@
"description": "Définir la largeur des titres de fenêtres dans la barre des tâches (en pixels).",
"label": "Largeur du titre",
"reset-tooltip": "Réinitialiser la largeur du titre"
"show-pinned-apps": {
"description": "Afficher les applications épinglées du dock dans la barre des tâches.",
"label": "Afficher les applications épinglées"
}
},
"taskbar-grouped": {
@@ -359,6 +373,10 @@
"drawer-enabled": {
"description": "Lorsqu'elle est activée, les éléments de la barre système non épinglés sont affichés dans un panneau tiroir. Lorsqu'elle est désactivée, tous les éléments de la barre système sont affichés en ligne.",
"label": "Activer le tiroir"
},
"hide-passive": {
"description": "Lorsque cette option est activée, les éléments de la barre d'état système ayant le statut Passif seront masqués.",
"label": "Masquer les objets passifs"
}
},
"volume": {
@@ -531,11 +549,12 @@
"misc": "Divers",
"network": "Réseau",
"office": "Bureau",
"pinned": "Épinglé",
"system": "Système",
"webbrowser": "Navigateur web"
},
"pin": "Épingler au dock",
"unpin": "Retirer du dock"
"pin": "Épingler",
"unpin": "Détacher"
},
"lock-screen": {
"authenticating": "Authentification...",
@@ -736,6 +755,9 @@
"clipboard-loading": "Chargement de l'historique du presse-papiers...",
"clipboard-loading-description": "Veuillez patienter",
"clipboard-search-description": "Rechercher dans l'historique du presse-papiers",
"command": "Commande",
"command-description": "Exécuter des commandes shell",
"command-name": "Commande",
"emoji": "Sélecteur d'émojis",
"emoji-loading": "Chargement des émojis...",
"emoji-loading-description": "Veuillez patienter",
@@ -1337,6 +1359,10 @@
"description": "Appliquer les couleurs du thème aux icônes d'applications du dock (applications non focalisées uniquement).",
"label": "Coloriser les icônes"
},
"dead-opacity": {
"description": "Ajuster l'opacité des icônes d'applications qui ne sont pas en cours d'exécution.",
"label": "Opacité morte"
},
"display": {
"always-visible": "Toujours visible",
"auto-hide": "Masquer automatiquement",
@@ -1352,6 +1378,14 @@
"description": "Ajuster la taille globale du Dock.",
"label": "Taille du Dock"
},
"inactive-indicators": {
"description": "Afficher les pastilles d'indicateur pour toutes les applications, pas seulement celle qui est active.",
"label": "Indicateurs de fonctionnement"
},
"pinned-static": {
"description": "Toujours pousser les icônes d'applications épinglées vers la gauche dans un ordre statique.",
"label": "Applications épinglées statiques"
},
"section": {
"description": "Personnalisez le comportement et l'apparence du dock.",
"label": "Apparence"
@@ -1513,6 +1547,10 @@
"description": "Personnalisez le comportement et l'apparence du lanceur.",
"label": "Apparence"
},
"show-categories": {
"description": "Afficher les onglets de catégories pour filtrer les applications.",
"label": "Afficher les catégories"
},
"sort-by-usage": {
"description": "Lorsque cette option est activée, les applications fréquemment lancées apparaissent en premier dans la liste.",
"label": "Trier par les plus utilisés"
+40 -2
View File
@@ -140,6 +140,13 @@
"stream-description": "継続的に実行するコマンドを入力します。"
},
"dynamic-text": "動的テキスト",
"hide-mode": {
"alwaysExpanded": "常に展開",
"description": "コマンドが出力を持っていない場合のウィジェットの表示を制御します。",
"expandWithOutput": "出力があるときに展開",
"label": "非表示モード",
"maxTransparent": "最大展開だが透過"
},
"icon": {
"description": "ライブラリからアイコンを選択します。",
"label": "アイコン"
@@ -175,6 +182,10 @@
"label": "右クリック",
"update-text": "右クリック時に表示テキストを更新"
},
"show-icon": {
"description": "ウィジェットのアイコンの表示を切り替えます。",
"label": "アイコンを表示"
},
"text-stream": {
"description": "コマンドからストリーミングされた行を、ボタン上のテキストとして表示します。",
"label": "ストリーム"
@@ -343,6 +354,9 @@
"description": "タスクバーのウィンドウタイトルの幅を設定します(ピクセル単位)。",
"label": "タイトル幅",
"reset-tooltip": "タイトル幅をリセット"
"show-pinned-apps": {
"description": "ドックからピン留めされたアプリをタスクバーに表示する。",
"label": "ピン留めされたアプリを表示"
}
},
"taskbar-grouped": {
@@ -359,6 +373,10 @@
"drawer-enabled": {
"description": "有効にすると、ピン留めされていないトレイ項目をドロワーパネル内に表示します。\n無効にすると、すべての項目をインラインで表示します。",
"label": "ドロワーを有効化"
},
"hide-passive": {
"description": "有効にすると、非アクティブなステータスのトレイアイコンは非表示になります。",
"label": "受動的なアイテムを隠す"
}
},
"volume": {
@@ -531,11 +549,12 @@
"misc": "その他",
"network": "ネットワーク",
"office": "オフィス",
"pinned": "ピン留め",
"system": "システム",
"webbrowser": "ウェブブラウザ"
},
"pin": "ドックにピン留め",
"unpin": "ドックからピン留め解除"
"pin": "ピン留め",
"unpin": "ピン留め解除"
},
"lock-screen": {
"authenticating": "認証中...",
@@ -736,6 +755,9 @@
"clipboard-loading": "クリップボード履歴を読み込み中...",
"clipboard-loading-description": "お待ちください",
"clipboard-search-description": "クリップボード履歴を検索",
"command": "コマンド",
"command-description": "シェルコマンドを実行する",
"command-name": "コマンド",
"emoji": "絵文字選択",
"emoji-loading": "絵文字を読み込み中...",
"emoji-loading-description": "お待ちください",
@@ -1337,6 +1359,10 @@
"description": "ドックのアプリアイコンにテーマカラーを適用します(非フォーカス時のみ)。",
"label": "テーマカラーの適用"
},
"dead-opacity": {
"description": "実行されていないアプリのアイコンの不透明度を調整します。",
"label": "死んだ不透明度"
},
"display": {
"always-visible": "常に表示",
"auto-hide": "自動的に隠す",
@@ -1352,6 +1378,14 @@
"description": "ドック全体のサイズを調整します。",
"label": "ドックのサイズ"
},
"inactive-indicators": {
"description": "現在アクティブなアプリだけでなく、すべてのアプリのインジケーターピルを表示する。",
"label": "実行指標"
},
"pinned-static": {
"description": "ピン留めされたアプリのアイコンは、常に静的な順序で左に寄せてください。",
"label": "固定された静的アプリ"
},
"section": {
"description": "ドックの動作と外観をカスタマイズします。",
"label": "外観"
@@ -1513,6 +1547,10 @@
"description": "ランチャーの挙動と外観をカスタマイズします。",
"label": "外観"
},
"show-categories": {
"description": "アプリケーションをフィルタリングするためのカテゴリタブを表示します。",
"label": "カテゴリを表示"
},
"sort-by-usage": {
"description": "有効にすると、よく使うアプリがリストの上位に表示されます。",
"label": "使用頻度順に並べ替え"
+40 -2
View File
@@ -140,6 +140,13 @@
"stream-description": "Voer een commando in dat continu wordt uitgevoerd."
},
"dynamic-text": "Dynamische tekst",
"hide-mode": {
"alwaysExpanded": "Altijd uitgeklapt",
"description": "Bepaalt de zichtbaarheid van de widget wanneer het commando geen uitvoer heeft.",
"expandWithOutput": "Uitklappen wanneer er uitvoer is",
"label": "Verbergmodus",
"maxTransparent": "Maximaal uitgeklapt maar transparant"
},
"icon": {
"description": "Selecteer een pictogram uit de bibliotheek.",
"label": "Pictogram"
@@ -175,6 +182,10 @@
"label": "Rechtermuisklik",
"update-text": "Tekst bijwerken die wordt weergegeven bij rechtsklikken"
},
"show-icon": {
"description": "Schakelt de zichtbaarheid van het widgetpictogram.",
"label": "Pictogram weergeven"
},
"text-stream": {
"description": "Gestreamde regels uit het commando worden als tekst op de knop weergegeven.",
"label": "Stream"
@@ -343,6 +354,9 @@
"description": "Stel de breedte van venstertitels in de taakbalk in (in pixels).",
"label": "Titelbreedte",
"reset-tooltip": "Titelbreedte resetten"
"show-pinned-apps": {
"description": "Toon vastgemaakte apps van het dock in de taakbalk.",
"label": "Toon vastgemaakte apps"
}
},
"taskbar-grouped": {
@@ -359,6 +373,10 @@
"drawer-enabled": {
"description": "Indien ingeschakeld worden niet-vastgemaakte systeemvakitems in een lade weergegeven. Indien uitgeschakeld worden alle items inline getoond.",
"label": "Lade inschakelen"
},
"hide-passive": {
"description": "Indien ingeschakeld, worden tray-items met de status Passief verborgen.",
"label": "Verberg passieve items"
}
},
"volume": {
@@ -531,11 +549,12 @@
"misc": "Diversen",
"network": "Netwerk",
"office": "Kantoor",
"pinned": "Vastgemaakt",
"system": "Systeem",
"webbrowser": "Webbrowser"
},
"pin": "Aan dock vastmaken",
"unpin": "Van dock losmaken"
"pin": "Vastmaken",
"unpin": "Losmaken"
},
"lock-screen": {
"authenticating": "Bezig met verifiëren...",
@@ -736,6 +755,9 @@
"clipboard-loading": "Klembordgeschiedenis laden...",
"clipboard-loading-description": "Even geduld",
"clipboard-search-description": "Zoek in klembordgeschiedenis",
"command": "Commando",
"command-description": "Shell-opdrachten uitvoeren",
"command-name": "Commando",
"emoji": "Emoji-kiezer",
"emoji-loading": "Emoji's laden...",
"emoji-loading-description": "Even geduld",
@@ -1337,6 +1359,10 @@
"description": "Pas themakleuren toe op dock-pictogrammen (alleen niet-focuste apps).",
"label": "Pictogrammen inkleuren"
},
"dead-opacity": {
"description": "Pas de transparantie aan van app-iconen die niet actief zijn.",
"label": "Dode opaciteit"
},
"display": {
"always-visible": "Altijd zichtbaar",
"auto-hide": "Automatisch verbergen",
@@ -1352,6 +1378,14 @@
"description": "Pas de algehele grootte van de dock aan.",
"label": "Grootte van de dock"
},
"inactive-indicators": {
"description": "Toon indicatorpillen voor alle apps, niet alleen de actieve.",
"label": "Lopende indicatoren"
},
"pinned-static": {
"description": "Zet vastgemaakte app-pictogrammen altijd in statische volgorde aan de linkerkant.",
"label": "Statische vastgezette apps"
},
"section": {
"description": "Pas het gedrag en uiterlijk van de dock aan.",
"label": "Uiterlijk"
@@ -1513,6 +1547,10 @@
"description": "Pas het gedrag en uiterlijk van de launcher aan.",
"label": "Uiterlijk"
},
"show-categories": {
"description": "Categorieën-tabbladen weergeven voor het filteren van applicaties.",
"label": "Categorieën weergeven"
},
"sort-by-usage": {
"description": "Indien ingeschakeld, verschijnen vaak gestarte apps bovenaan in de lijst.",
"label": "Sorteren op meest gebruikt"
+40 -2
View File
@@ -140,6 +140,13 @@
"stream-description": "Insira um comando para executar continuamente."
},
"dynamic-text": "Texto dinâmico",
"hide-mode": {
"alwaysExpanded": "Sempre expandido",
"description": "Controla a visibilidade do widget quando o comando não tem saída.",
"expandWithOutput": "Expandir quando tem saída",
"label": "Modo de ocultação",
"maxTransparent": "Totalmente expandido mas transparente"
},
"icon": {
"description": "Selecione um ícone da biblioteca.",
"label": "Ícone"
@@ -175,6 +182,10 @@
"label": "Clique direito",
"update-text": "Atualizar o texto exibido ao clicar com o botão direito."
},
"show-icon": {
"description": "Alterna a visibilidade do ícone do widget.",
"label": "Mostrar ícone"
},
"text-stream": {
"description": "As linhas transmitidas do comando serão exibidas como texto no botão.",
"label": "Transmissão"
@@ -343,6 +354,9 @@
"description": "Definir a largura dos títulos de janelas na barra de tarefas (em pixels).",
"label": "Largura do título",
"reset-tooltip": "Redefinir largura do título"
"show-pinned-apps": {
"description": "Mostrar aplicativos fixados do Dock na barra de tarefas.",
"label": "Mostrar aplicativos fixados"
}
},
"taskbar-grouped": {
@@ -359,6 +373,10 @@
"drawer-enabled": {
"description": "Quando habilitado, os itens da bandeja não fixados são exibidos em um painel gaveta. Quando desabilitado, todos os itens da bandeja são exibidos inline.",
"label": "Habilitar gaveta"
},
"hide-passive": {
"description": "Quando ativado, os itens da bandeja com status Passivo serão ocultados.",
"label": "Ocultar itens passivos"
}
},
"volume": {
@@ -531,11 +549,12 @@
"misc": "Diversos",
"network": "Rede",
"office": "Escritório",
"pinned": "Fixado",
"system": "Sistema",
"webbrowser": "Navegador web"
},
"pin": "Fixar no dock",
"unpin": "Desafixar do dock"
"pin": "Fixar",
"unpin": "Desafixar"
},
"lock-screen": {
"authenticating": "Autenticando...",
@@ -736,6 +755,9 @@
"clipboard-loading": "Carregando histórico da área de transferência...",
"clipboard-loading-description": "Por favor, aguarde",
"clipboard-search-description": "Pesquisar no histórico da área de transferência",
"command": "Comando",
"command-description": "Executar comandos shell",
"command-name": "Comando",
"emoji": "Seletor de emojis",
"emoji-loading": "Carregando emojis...",
"emoji-loading-description": "Por favor, aguarde",
@@ -1337,6 +1359,10 @@
"description": "Aplicar cores do tema aos ícones de aplicativos da dock (apenas aplicativos não focados).",
"label": "Colorir ícones"
},
"dead-opacity": {
"description": "Ajustar a opacidade dos ícones de aplicativos que não estão em execução.",
"label": "Opacidade Morta"
},
"display": {
"always-visible": "Sempre visível",
"auto-hide": "Ocultar automaticamente",
@@ -1352,6 +1378,14 @@
"description": "Ajustar o tamanho geral do Dock.",
"label": "Tamanho do Dock"
},
"inactive-indicators": {
"description": "Exibir indicadores de pílula para todos os aplicativos, não apenas para o aplicativo ativo no momento.",
"label": "Indicadores de execução"
},
"pinned-static": {
"description": "Sempre posicione os ícones de aplicativos fixados à esquerda em ordem estática.",
"label": "Aplicativos Fixados Estaticamente"
},
"section": {
"description": "Personalize o comportamento e a aparência da dock.",
"label": "Aparência"
@@ -1513,6 +1547,10 @@
"description": "Personalize o comportamento e a aparência do lançador.",
"label": "Aparência"
},
"show-categories": {
"description": "Mostrar abas de categorias para filtrar aplicativos.",
"label": "Mostrar categorias"
},
"sort-by-usage": {
"description": "Quando ativado, os aplicativos mais usados aparecem primeiro na lista.",
"label": "Ordenar por mais usados"
+40 -2
View File
@@ -140,6 +140,13 @@
"stream-description": "Введите команду для непрерывного выполнения."
},
"dynamic-text": "Динамический текст",
"hide-mode": {
"alwaysExpanded": "Всегда раскрыт",
"description": "Управляет видимостью виджета, когда команда не имеет вывода.",
"expandWithOutput": "Раскрывать при наличии вывода",
"label": "Режим скрытия",
"maxTransparent": "Максимально раскрыт, но прозрачный"
},
"icon": {
"description": "Выберите иконку из библиотеки.",
"label": "Иконка"
@@ -175,6 +182,10 @@
"label": "Клик правой кнопкой",
"update-text": "Обновить отображаемый текст по правому клику"
},
"show-icon": {
"description": "Переключает видимость иконки виджета.",
"label": "Показать иконку"
},
"text-stream": {
"description": "Потоковые строки из команды будут отображаться как текст на кнопке.",
"label": "Поток"
@@ -343,6 +354,9 @@
"description": "Установить ширину заголовков окон на панели задач (в пикселях).",
"label": "Ширина заголовка",
"reset-tooltip": "Сбросить ширину заголовка"
"show-pinned-apps": {
"description": "Показывать закреплённые приложения из Dock на панели задач.",
"label": "Показать закреплённые приложения"
}
},
"taskbar-grouped": {
@@ -359,6 +373,10 @@
"drawer-enabled": {
"description": "Если включено, незакрепленные элементы трея отображаются во всплывающей панели. Если отключено, все элементы трея отображаются в строку.",
"label": "Включить всплывающую панель"
},
"hide-passive": {
"description": "Если включено, элементы в трее со статусом \"Пассивный\" будут скрыты.",
"label": "Скрыть пассивные предметы"
}
},
"volume": {
@@ -531,11 +549,12 @@
"misc": "Разное",
"network": "Сеть",
"office": "Офис",
"pinned": "Закреплено",
"system": "Система",
"webbrowser": "Веб-браузер"
},
"pin": "Закрепить на панели",
"unpin": "Открепить от панели"
"pin": "Закрепить",
"unpin": "Открепить"
},
"lock-screen": {
"authenticating": "Аутентификация...",
@@ -736,6 +755,9 @@
"clipboard-loading": "Загрузка истории буфера обмена...",
"clipboard-loading-description": "Пожалуйста, подождите",
"clipboard-search-description": "Поиск в истории буфера обмена",
"command": "Команда",
"command-description": "Выполнять команды оболочки",
"command-name": "Команда",
"emoji": "Выбор эмодзи",
"emoji-loading": "Загрузка эмодзи...",
"emoji-loading-description": "Пожалуйста, подождите",
@@ -1337,6 +1359,10 @@
"description": "Применить цвета темы к иконкам приложений на панели (только для нефокусированных приложений).",
"label": "Раскрасить иконки"
},
"dead-opacity": {
"description": "Настройте прозрачность значков неактивных приложений.",
"label": "Мёртвая непрозрачность"
},
"display": {
"always-visible": "Всегда видимая",
"auto-hide": "Автоматически скрывать",
@@ -1352,6 +1378,14 @@
"description": "Настройка общего размера панели приложений.",
"label": "Размер панели"
},
"inactive-indicators": {
"description": "Отображать индикаторы для всех приложений, а не только для активного.",
"label": "Бегущие индикаторы"
},
"pinned-static": {
"description": "Всегда перемещайте закреплённые значки приложений влево в статичном порядке.",
"label": "Закреплённые статические приложения"
},
"section": {
"description": "Настройка поведения и внешнего вида панели приложений.",
"label": "Внешний вид"
@@ -1513,6 +1547,10 @@
"description": "Настройка поведения и внешнего вида запуска.",
"label": "Внешний вид"
},
"show-categories": {
"description": "Показывать вкладки категорий для фильтрации приложений.",
"label": "Показывать категории"
},
"sort-by-usage": {
"description": "Если включено, часто запускаемые приложения появляются в списке первыми.",
"label": "Сортировать по частоте использования"
+185 -147
View File
@@ -7,27 +7,27 @@
"widget-settings": {
"active-window": {
"colorize-icons": {
"description": "Aktif pencere ikonuna tema renklerini uygula.",
"label": "İkonları Renklendir"
"description": "Aktif pencere simgelerine tema renklerini uygula.",
"label": "Simgeleri Renklendir"
},
"hide-mode": {
"description": "Pencere aktif değilken widget'in nasıl davrandığını kontrol eder.",
"description": "Pencere aktif değilken araç takımlarının nasıl davrandığını kontrol eder.",
"label": "Gizleme modu"
},
"max-width": {
"description": "Widget'in maksimum yatay boyutunu ayarlar. Widget daha kısa içerik için küçülecektir.",
"label": "Maksimum Genişlik"
"description": "Araç takımının en fazla yatay boyutunu ayarlar. Araç takımı daha kısa içerik için küçülecektir.",
"label": "En Fazla Genişlik"
},
"scrolling-mode": {
"description": "Uzun pencere başlıkları için metin kaydırmanın ne zaman etkinleştirileceğini kontrol et.",
"label": "Kaydırma modu"
},
"show-app-icon": {
"description": "Pencere başlığı yanında uygulama ikonunu göster.",
"label": "Uygulama ikonunu göster"
"description": "Pencere başlığı yanında uygulama simgesini göster.",
"label": "Uygulama simgesini göster"
},
"use-fixed-width": {
"description": "Etkinleştirildiğinde, widget dinamik olarak içeriğe göre ayarlamak yerine her zaman maksimum genişliği kullanır.",
"description": "Etkinleştirildiğinde, araç takımı hareketli olarak içeriğe göre ayarlanmak yerine her zaman en fazla genişliği kullanır.",
"label": "Sabit Genişlik Kullan"
}
},
@@ -119,19 +119,19 @@
"label": "Renklendirmeyi Etkinleştir"
},
"icon": {
"description": "Kütüphaneden veya özel bir dosyadan bir ikon seçin.",
"label": "İkon"
"description": "Kütüphaneden veya özel bir dosyadan bir simge seçin.",
"label": "Simge"
},
"select-custom-icon": "Özel bir ikon seç",
"select-custom-icon": "Özel bir simge seç",
"use-distro-logo": {
"description": "Özel ikon yerine dağıtımınızın logosunu kullanın.",
"label": "Dağıtım logosunu ikon yerine kullan"
"description": "Özel simge yerine dağıtımınızın logosunu kullanın.",
"label": "Dağıtım logosunu simge yerine kullan"
}
},
"custom-button": {
"browse": "Göz At",
"collapse-condition": {
"description": "Çıktı metni bu değerle eşleşirse buton daralacak.",
"description": "Çıktı metni bu değerle eşleşirse düğme daralacak.",
"label": "Daralma durumu"
},
"display-command-output": {
@@ -139,31 +139,38 @@
"label": "Komut Çıktısını Göster",
"stream-description": "Sürekli çalıştırılacak bir komut girin."
},
"dynamic-text": "Dinamik metin",
"dynamic-text": "Hareketli metin",
"hide-mode": {
"alwaysExpanded": "Her zaman geniş",
"description": "Komutun çıktı vermemesi durumunda gerecin görünürlüğünü kontrol eder.",
"expandWithOutput": "Çıktı olduğunda genişlet",
"label": "Gizleme modu",
"maxTransparent": "En büyük genişlik ama saydam"
},
"icon": {
"description": "Kütüphaneden bir ikon seçin.",
"label": "İkon"
"description": "Kütüphaneden bir simge seçin.",
"label": "Simge"
},
"left-click": {
"description": "Butona sol tıklandığında yürütülecek komut.",
"description": "Düğmeye sol tıklandığında yürütülecek komut.",
"label": "Sol tıklama",
"update-text": "Sol tıklamayla görüntülenen metni güncelle"
},
"max-text-length-horizontal": {
"description": "Yatay çubukta gösterilecek maksimum karakter sayısı (metni gizlemek için 0)",
"label": "Maks. metin uzunluğu (yatay)"
"description": "Yatay çubukta gösterilecek en fazla karakter sayısı (metni gizlemek için 0)",
"label": "En uzun metin uzunluğu (yatay)"
},
"max-text-length-vertical": {
"description": "Dikey çubukta gösterilecek maksimum karakter sayısı (metni gizlemek için 0)",
"label": "Maks. metin uzunluğu (dikey)"
"description": "Dikey çubukta gösterilecek en fazla karakter sayısı (metni gizlemek için 0)",
"label": "En uzun metin uzunluğu (dikey)"
},
"middle-click": {
"description": "Butona orta tıklandığında yürütülecek komut.",
"description": "Orta düğmeye tıklandığında yürütülecek komut.",
"label": "Orta tıklama",
"update-text": "Orta tıklamayla görüntülenen metni güncelle"
},
"parse-json": {
"description": "Komut çıktısını metin ve ikon dinamik olarak ayarlamak için bir JSON nesnesi olarak ayrıştırın.",
"description": "Komut çıktısını hareketli metin ve simge olarak ayarlamak için bir JSON nesnesi olarak ayrıştırın.",
"label": "Çıktıyı JSON olarak ayrıştır"
},
"refresh-interval": {
@@ -171,12 +178,16 @@
"label": "Yenileme aralığı"
},
"right-click": {
"description": "Butona sağ tıklandığında yürütülecek komut.",
"description": "Sağ düğmeye tıklandığında yürütülecek komut.",
"label": "Sağ tıklama",
"update-text": "Sağ tıklamada görüntülenen metni güncelle"
},
"show-icon": {
"description": "Takım aracının simgesinin görünürlüğünü değiştirir.",
"label": "Simgeyi göster"
},
"text-stream": {
"description": "Komuttan gelen akış satırları butonda metin olarak gösterilecektir.",
"description": "Komuttan gelen akış satırları düğmede metin olarak gösterilecektir.",
"label": "Akış"
},
"wheel": {
@@ -210,26 +221,26 @@
"lock-keys": {
"browse": "Göz at",
"show-caps-lock": {
"description": "Caps Lock durumunu göster.",
"label": "Caps Lock"
"description": "Büyük Harf Kilidi düğmesi durumunu göster.",
"label": "Büyük Harf Kilidi"
},
"show-num-lock": {
"description": "Num Lock durumunu göster.",
"label": "Num Lock"
"description": "Sayı Kilidi durumunu göster.",
"label": "Sayı Kilidi"
},
"show-scroll-lock": {
"description": "Scroll Lock durumunu göster.",
"label": "Scroll Lock"
"description": "Kaydırma Kilidi durumunu göster.",
"label": "Kaydırma Kilidi"
}
},
"media-mini": {
"hide-mode": {
"description": "Medya çalınmadığında widget'in nasıl davrandığını kontrol eder.",
"description": "Ortam çalınmadığında araç takımının nasıl davrandığını kontrol eder.",
"label": "Gizleme modu"
},
"max-width": {
"description": "Widget'in maksimum yatay boyutunu ayarlar. Widget daha kısa içerik için küçülecektir.",
"label": "Maksimum Genişlik"
"description": "Araç takımının en fazla yatay boyutunu ayarlar. Araç takımı daha kısa içerik için küçülecektir.",
"label": "En Fazla Genişlik"
},
"no-active-player": "Etkin çalar yok",
"scrolling-mode": {
@@ -237,7 +248,7 @@
"label": "Kaydırma modu"
},
"show-album-art": {
"description": "Şu anda çalan parçanın albüm kapak sanatını göster.",
"description": "Şu anda çalan parçanın albüm kapağını göster.",
"label": "Albüm kapağını göster"
},
"show-artist-first": {
@@ -253,11 +264,11 @@
"label": "Görselleştiriciyi göster"
},
"use-fixed-width": {
"description": "Etkinleştirildiğinde, widget dinamik olarak içerik göre ayarlamak yerine her zaman maksimum genişliği kullanır.",
"description": "Etkinleştirildiğinde, araç takımını hareketli olarak içeriğe göre ayarlamak yerine her zaman en fazla genişliği kullanır.",
"label": "Sabit Genişlik Kullan"
},
"visualizer-type": {
"description": "Gösterilecek ses görselleştirici stilini seçin.",
"description": "Gösterilecek ses görselleştirici biçemini seçin.",
"label": "Görselleştirici türü"
}
},
@@ -278,8 +289,8 @@
}
},
"section-editor": {
"placeholder": "Eklenecek bir widget seçin...",
"search-placeholder": "Widget ara..."
"placeholder": "Eklenecek bir araç takımı seçin...",
"search-placeholder": "Araç takımı ara..."
},
"spacer": {
"width": {
@@ -289,12 +300,12 @@
},
"system-monitor": {
"cpu-temperature": {
"description": "Mevcut CPU sıcaklık okumalarını gösterir.",
"label": "CPU sıcaklığı"
"description": "Mevcut işlemci sıcaklık okumalarını gösterir.",
"label": "İşlemci sıcaklığı"
},
"cpu-usage": {
"description": "Mevcut CPU kullanım yüzdesini göster.",
"label": "CPU kullanımı"
"description": "Mevcut işlemci kullanım yüzdesini göster.",
"label": "İşlemci kullanımı"
},
"disk-path": {
"description": "İzlenecek disk bağlama noktasını seçin.",
@@ -305,7 +316,7 @@
"label": "Bellek yüzde olarak"
},
"memory-usage": {
"description": "Mevcut RAM kullanım bilgilerini göster.",
"description": "Mevcut bellek kullanım bilgilerini göster.",
"label": "Bellek kullanımı"
},
"network-traffic": {
@@ -319,11 +330,11 @@
},
"taskbar": {
"colorize-icons": {
"description": "Görev çubuğu ikonlarına tema renklerini uygula.",
"label": "İkonları Renklendir"
"description": "Görev çubuğu simgelerine tema renklerini uygula.",
"label": "Simgeleri Renklendir"
},
"hide-mode": {
"description": "Eşleşen pencere olmadığında widget'in nasıl davrandığını kontrol eder.",
"description": "Eşleşen pencere olmadığında araç takımının nasıl davrandığını kontrol eder.",
"label": "Gizleme modu"
},
"only-active-workspaces": {
@@ -343,6 +354,9 @@
"description": "Görev çubuğundaki pencere başlıklarının genişliğini ayarla (piksel olarak).",
"label": "Başlık genişliği",
"reset-tooltip": "Başlık genişliğini sıfırla"
"show-pinned-apps": {
"description": "Dock'taki sabitlenmiş uygulamaları görev çubuğunda göster.",
"label": "Sabitlenmiş uygulamaları göster"
}
},
"taskbar-grouped": {
@@ -353,12 +367,16 @@
},
"tray": {
"colorize-icons": {
"description": "Tepsi ikonlarına tema renklerini uygula.",
"label": "İkonları Renklendir"
"description": "Tepsi simgelerine tema renklerini uygula.",
"label": "Simgeleri Renklendir"
},
"drawer-enabled": {
"description": "Etkinleştirildiğinde, sabitlenmemiş tepsi öğeleri bir çekmece panelinde gösterilir. Devre dışı bırakıldığında, tüm tepsi öğeleri satır içi gösterilir.",
"label": "Çekmeceyi Etkinleştir"
},
"hide-passive": {
"description": "Etkinleştirildiğinde, Pasif durumdaki tepsi öğeleri gizlenir.",
"label": "Pasif öğeleri gizle"
}
},
"volume": {
@@ -429,8 +447,8 @@
"timer": {
"countdown": "Geri sayım",
"duration": "Süre",
"hours": "h",
"minutes": "m",
"hours": "S",
"minutes": "d",
"pause": "Duraklat",
"reset": "Sıfırla",
"seconds": "s",
@@ -488,23 +506,23 @@
"cycle-visualizer": "Döngü görselleştirici",
"disable-bluetooth": "Bluetooth'u kapat",
"disable-dnd": "Rahatsız Etmeyin'i Kapat",
"disable-wifi": "Wi-Fi'ı kapat",
"disable-wifi": "Kablosuz Bağlantıyı kapat",
"disconnect-vpn": "{name} bağlantısını kes",
"enable-bluetooth": "Bluetooth'u etkinleştir",
"enable-dnd": "Rahatsız Etmeyin'i Etkinleştir",
"enable-wifi": "Wi-Fi'ı etkinleştir",
"enable-wifi": "Kablosuz Bağlantıyı etkinleştir",
"next": "Sonraki",
"open-calendar": "Takvimi aç",
"open-display-settings": "Ekran ayarları",
"open-launcher": "Başlatıcıyı aç",
"open-mixer": "Ses mikseri",
"open-mixer": "Ses Karıştırıcısı",
"open-settings": "Ayarları aç",
"pause": "Duraklat",
"play": "Oynat",
"previous": "Önceki",
"random-wallpaper": "Rastgele duvar kağıdı",
"toggle-mute": "Sesi kapat/aç",
"widget-settings": "Araç ayarları"
"widget-settings": "Araç takımı ayarları"
},
"dock": {
"menu": {
@@ -522,7 +540,7 @@
"launcher": {
"categories": {
"all": "Tümü",
"audiovideo": "Ses ve Video",
"audiovideo": "Ses ve Görüntü",
"chat": "Sohbet",
"development": "Geliştirme",
"education": "Eğitim",
@@ -531,11 +549,12 @@
"misc": "Çeşitli",
"network": "Ağ",
"office": "Ofis",
"pinned": "Sabitlendi",
"system": "Sistem",
"webbrowser": "Web tarayıcı"
"webbrowser": "Tarayıcı"
},
"pin": "Dock'a sabitle",
"unpin": "Dock'dan sabitlemeyi kaldır"
"pin": "Sabitle",
"unpin": "Sabitlemeyi kaldır"
},
"lock-screen": {
"authenticating": "Doğrulanıyor...",
@@ -575,7 +594,7 @@
"comfortable": "Rahat",
"compact": "Sıkı",
"default": "Varsayılan",
"mini": "Mini"
"mini": "Ufak"
},
"position": {
"bottom": "Alt",
@@ -663,7 +682,7 @@
"quality": {
"high": "Yüksek",
"medium": "Orta",
"ultra": "Ultra",
"ultra": "Aşırı",
"very-high": "Çok yüksek"
},
"sources": {
@@ -672,7 +691,7 @@
}
},
"scrolling-modes": {
"always": "Her Kaydır",
"always": "Her Zaman Kaydır",
"hover": "Üzerine Gelince Kaydır",
"never": "Asla Kaydırma"
},
@@ -736,6 +755,9 @@
"clipboard-loading": "Panoya geçmişi yükleniyor...",
"clipboard-loading-description": "Lütfen bekleyin",
"clipboard-search-description": "Panoya geçmişini ara",
"command": "Komut",
"command-description": "Kabuk komutlarını çalıştır",
"command-name": "Komut",
"emoji": "Emoji seçici",
"emoji-loading": "Emojiler yükleniyor...",
"emoji-loading-description": "Lütfen bekleyin",
@@ -805,17 +827,17 @@
},
"wifi": {
"label": {
"disconnected": "Wi-Fi Bağlantısı Kesik",
"disconnected": "Kablosuz Bağlantı Kesik",
"ethernet": "Ethernet",
"wifi": "Wi-Fi"
"wifi": "Kablosuz Bağlantı"
},
"tooltip": {
"action": "Wi-Fi"
"action": "Kablosuz Bağlantı"
}
}
},
"session-menu": {
"action-in-seconds": "{action} in {seconds} seconds...",
"action-in-seconds": "{seconds} saniyede {action}...",
"hibernate": "Hazırda Bekletme",
"lock": "Kilitle",
"lock-and-suspend": "Kilitle ve Askıya Al",
@@ -864,8 +886,8 @@
}
},
"external-mixer": {
"description": "Harici ses mikseri özelliği etkinleştirilirken başlatılacak komutu veya uygulama yolunu girin.",
"label": "Harici Ses Mikseri Komutu",
"description": "Harici ses karıştırıcısı özelliği etkinleştirilirken başlatılacak komutu veya uygulama yolunu girin.",
"label": "Harici Ses Karıştırıcısı Komutu",
"placeholder": "pwvucontrol || pavucontrol"
},
"media": {
@@ -888,19 +910,19 @@
"label": "Kaydırma hızı"
},
"scrolling-title": {
"description": "Uzun medya başlıkları için sürekli kaydırmayı etkinleştirin",
"description": "Uzun ortam başlıkları için sürekli kaydırmayı etkinleştirin",
"label": "Kayan başlık"
},
"section": {
"description": "Tercih ettiğiniz ve yoksayacağınız medya uygulamalarını ayarlayın.",
"label": "Medya oynatıcılar"
"description": "Tercih ettiğiniz ve yoksayacağınız ortam uygulamalarını ayarlayın.",
"label": "Ortam oynatıcıları"
},
"visualizer-quality": {
"description": "Yüksek kalite daha fazla GPU kaynağı kullanır.",
"description": "Yüksek kalite ekran kartını daha fazla kullanır.",
"label": "Görselleştirme kalitesi"
},
"visualizer-type": {
"description": "Medya oynatımı için bir görselleştirme türü seçin",
"description": "Ortam oynatımı için bir görselleştirme türü seçin",
"label": "Görselleştirme türü"
}
},
@@ -939,23 +961,23 @@
"bar": {
"appearance": {
"background-opacity": {
"description": "Barın arka plan opaklığını ayarlayın.",
"description": "Araç çubuğu arka plan opaklığını ayarlayın.",
"label": "Arka plan opaklığı"
},
"capsule-opacity": {
"description": "Kapsül gösterildiğinde widget arka planlarının saydamlık seviyesini ayarla.",
"description": "Kapsül gösterildiğinde araç takımı arka planlarının saydamlık seviyesini ayarla.",
"label": "Kapsül saydamlığı"
},
"density": {
"description": "Sıkı veya geniş bir görünüm için barın dolgusunu ayarlayın.",
"label": "Bar yoğunluğu"
"description": "Sıkı veya geniş bir görünüm için araç çubuğu dolgusunu ayarlayın.",
"label": "Araç Çubuğu yoğunluğu"
},
"floating": {
"description": "Barı yüzen bir 'hap' olarak görüntüler. Not: Bu, ekran köşelerini kenarlara taşıyacaktır.",
"label": "Yüzen bar"
"description": "Araç çubuğunu yüzen bir 'kapsül' olarak görüntüler. Not: Bu, ekran köşelerini kenarlara taşıyacaktır.",
"label": "Yüzen Araç Çubuğu"
},
"margins": {
"description": "Yüzen barın etrafındaki kenar boşluklarını ayarlayın.",
"description": "Yüzen araç çubuğunun etrafındaki kenar boşluklarını ayarlayın.",
"horizontal": "Yatay",
"label": "Kenar boşlukları",
"vertical": "Dikey"
@@ -965,25 +987,25 @@
"label": "Dış köşeler"
},
"position": {
"description": "Barı ekranda nereye yerleştireceğinizi seçin.",
"label": "Bar konumu"
"description": "Araç çubuğunu ekranda nereye yerleştireceğinizi seçin.",
"label": "Araç Çubuğu konumu"
},
"section": {
"description": "Barın görünümünü ve konumunu özelleştirin.",
"description": "Araç çubuğunun görünümünü ve konumunu özelleştirin.",
"label": "Görünüm"
},
"show-capsule": {
"description": "Widget arka planlarını göster.",
"description": "Araç takımı arka planlarını göster.",
"label": "Kapsülü göster"
}
},
"monitors": {
"section": {
"description": "Barı belirli ekranlarda gösterin. Hiçbiri seçilmezse varsayılan olarak tümünde gösterilir.",
"description": "Araç çubuğunu belirli ekranlarda gösterin. Hiçbiri seçilmezse varsayılan olarak tümünde gösterilir.",
"label": "Ekran görüntüsü"
}
},
"title": "Bar",
"title": "Araç Çubuğu",
"tray": {
"back": "Geri",
"blacklist": {
@@ -996,8 +1018,8 @@
},
"widgets": {
"section": {
"description": "Widget'ları sıralarını değiştirmek için sürükleyin. Widget'ları bölümler arasında aktarmak veya kaldırmak için sağ tıklama menüsünü kullanın.",
"label": "Widget konumlandırma"
"description": "Araç takımları sıralarını değiştirmek için sürükleyin. Araç takımlarını bölümler arasında aktarmak veya kaldırmak için sağ tıklama menüsünü kullanın.",
"label": "Araç takımlarını konumlandırma"
}
}
},
@@ -1030,7 +1052,7 @@
"description": "Işık ve koyu mod arasında otomatik geçişi etkinleştirir.",
"label": "Koyu mod zamanlaması",
"location": "Konum",
"manual": "Manuel",
"manual": "El ile",
"off": "Kapalı"
},
"switch": {
@@ -1169,7 +1191,7 @@
}
},
"ui": {
"description": "Masaüstü ortamı ve UI araç seti temalandırma.",
"description": "Masaüstü ortamı ve kullanıcı arabilirimi araç seti temalandırma.",
"gtk": {
"description": "{filepath} dosyasına yaz"
},
@@ -1187,16 +1209,16 @@
"control-center": {
"cards": {
"section": {
"description": "Kontrol Merkezi'nde hangi kontrollerin ve hangi sırada görüneceğini özelleştirin.",
"description": "Kontrol merkezinde hangi kontrollerin ve hangi sırada görüneceğini özelleştirin.",
"label": "Kartlar"
}
},
"position": {
"description": "Kontrol Merkezi paneli açıldığında nerede görüneceğini seçin.",
"description": "Kontrol merkezi paneli açıldığında nerede görüneceğini seçin.",
"label": "Konum"
},
"section": {
"description": "Kontrol Merkezi paneli konumunu ve davranışını yapılandırın.",
"description": "Kontrol merkezi paneli konumunu ve davranışını yapılandırın.",
"label": "Görünüm"
},
"shortcuts": {
@@ -1219,15 +1241,15 @@
"label": "Simge"
},
"on-clicked": {
"description": "Düğmeye sol tıklandığında yürütülecek komut.",
"description": "Farenin sol tuşuna tıklandığında yürütülecek komut.",
"label": "Sol Tık Komutu"
},
"on-middle-clicked": {
"description": "Orta tuşa tıklandığında çalıştırılacak komut.",
"description": "Farenin orta tuşuna tıklandığında çalıştırılacak komut.",
"label": "Orta Tıklama Komutu"
},
"on-right-clicked": {
"description": "Düğmeye sağ tıklandığında çalıştırılacak komut.",
"description": "Farenin sağ tuşuna tıklandığında çalıştırılacak komut.",
"label": "Sağ Tık Komutu"
},
"on-state-command": {
@@ -1255,8 +1277,8 @@
"cancel": "İptal"
},
"section": {
"description": "Widget'ları sürükleyerek sıralarını değiştirebilirsiniz. Widget'ları bölümler arasında aktarmak veya kaldırmak için sağ tıklama menüsünü kullanın.",
"label": "Kısayol widget'ları"
"description": "Araç takımlarını sürükleyerek sıralarını değiştirebilirsiniz. Araç takımlarını bölümler arasında aktarmak veya kaldırmak için sağ tıklama menüsünü kullanın.",
"label": "Kısayol Araç Takımları"
},
"sectionLeft": "Sol",
"sectionRight": "Sağ"
@@ -1326,52 +1348,64 @@
"dock": {
"appearance": {
"background-opacity": {
"description": "Dock'un arka plan opaklığını ayarlayın.",
"description": "Rıhtımın arka plan opaklığını ayarlayın.",
"label": "Arka plan opaklığı"
},
"border-radius": {
"description": "Dock'un kenar yarıçapını ayarla.",
"description": "Rıhtımın kenar yarıçapını ayarla.",
"label": "Kenar yarıçapı"
},
"colorize-icons": {
"description": "Dock uygulama simgelerine tema renklerini uygulayın (sadece odaklanılmamış uygulamalar).",
"description": "Rıhtım uygulama simgelerine tema renklerini uygulayın (sadece odaklanılmamış uygulamalar).",
"label": "Simgeleri Renklendir"
},
"dead-opacity": {
"description": "Çalışmayan uygulama simgelerinin opaklığını ayarlayın.",
"label": "Ölü Opaklık"
},
"display": {
"always-visible": "Her zaman görünür",
"auto-hide": "Otomatik gizle",
"description": "Dock'un nasıl davranacağını seçin.",
"description": "Rıhtımın nasıl davranacağını seçin.",
"exclusive": "Özel",
"label": "Görüntüleme"
},
"floating-distance": {
"description": "Dock ile ekran kenarı arasındaki mesafeyi ayarlayın.",
"label": "Dock yüzen mesafesi"
"description": "Rıhtım ile ekran kenarı arasındaki mesafeyi ayarlayın.",
"label": "Rıhtım yüzen mesafesi"
},
"icon-size": {
"description": "Dock'un genel boyutunu ayarlayın.",
"label": "Dock boyutu"
"description": "Rıhtımın genel boyutunu ayarlayın.",
"label": "Rıhtım boyutu"
},
"inactive-indicators": {
"description": "Tüm uygulamalar için, sadece etkin olan için değil, gösterge haplarını göster.",
"label": "Çalışan Göstergeler"
},
"pinned-static": {
"description": "Sabit sırada, sabitlenmiş uygulama simgelerini her zaman sola itin.",
"label": "Sabitlenmiş Statik Uygulamalar"
},
"section": {
"description": "Dock'un davranışını ve görünümünü özelleştirin.",
"description": "Rıhtımın davranışını ve görünümünü özelleştirin.",
"label": "Görünüm"
}
},
"enabled": {
"description": "Dock'u tamamen gösterin veya gizleyin",
"label": "Dock'u etkinleştir"
"description": "Rıhtımı tamamen gösterin veya gizleyin",
"label": "Rıhtımı etkinleştir"
},
"monitors": {
"only-same-output": {
"description": "Sadece dock'un bulunduğu çıktıdaki uygulamaları gösterin.",
"description": "Sadece rıhtımın bulunduğu çıktıdaki uygulamaları gösterin.",
"label": "Sadece aynı çıktıdaki uygulamalar"
},
"section": {
"description": "Dock'u belirli ekranlarda gösterin. Hiçbiri seçilmezse varsayılan olarak tümünde gösterilir.",
"description": "Rıhtımı belirli ekranlarda gösterin. Hiçbiri seçilmezse varsayılan olarak tümünde gösterilir.",
"label": "Ekran görüntüsü"
}
},
"title": "Dock"
"title": "Rıhtım"
},
"general": {
"fonts": {
@@ -1440,7 +1474,7 @@
"label": "Ekran köşelerini göster"
},
"solid-black": {
"description": "Bar arka plan rengi yerine tam siyah kullan.",
"description": "Araç çubuğu arka plan rengi yerine tam siyah kullan.",
"label": "Siyah köşeler"
}
},
@@ -1513,6 +1547,10 @@
"description": "Başlatıcının davranışını ve görünümünü özelleştirin.",
"label": "Görünüm"
},
"show-categories": {
"description": "Uygulamaları filtrelemek için kategori sekmelerini göster.",
"label": "Kategorileri göster"
},
"sort-by-usage": {
"description": "Etkinleştirildiğinde, sıkça başlatılan uygulamalar listede ilk olarak görünür.",
"label": "En çok kullanılana göre sırala"
@@ -1545,7 +1583,7 @@
},
"date-time": {
"12hour-format": {
"description": "Zamanı kilit ekranında ve takvimde 12 saatlik formatta gösterir. Çubuk saatinin kendi ayarları vardır.",
"description": "Zamanı kilit ekranında ve takvimde 12 saatlik formatta gösterir. Araç çubuğu saatinin kendi ayarları vardır.",
"label": "12 saatlik zaman formatını kullan"
},
"first-day-of-week": {
@@ -1558,7 +1596,7 @@
"label": "Tarih & Saat"
},
"show-events": {
"description": "Takvim panelinde etkinlikleri göster.",
"description": "Takvim panelindeki etkinlikleri göster.",
"label": "Takvim etkinliklerini göster"
},
"use-analog": {
@@ -1588,8 +1626,8 @@
"label": "Hava durumunu etkinleştir"
},
"fahrenheit": {
"description": "Sıcaklığı Celsius yerine Fahrenheit cinsinden gösterin.",
"label": "Sıcaklığı Fahrenheit (°F) cinsinden göster"
"description": "Sıcaklığı santigrat yerine fahrenhayt cinsinden gösterin.",
"label": "Sıcaklığı fahrenhayt (°F) cinsinden göster"
},
"section": {
"description": "Tercih ettiğiniz sıcaklık birimini seçin.",
@@ -1607,7 +1645,7 @@
},
"lock-screen": {
"compact-lockscreen": {
"description": "Sadece giriş girdisini ve sistem kontrollerini göster, hava durumu ve ortam medya widget'larını gizle.",
"description": "Sadece giriş girdisini ve sistem kontrollerini göster, hava durumu ve ortam araç takımlarını gizle.",
"label": "Kompakt ekran kilidi"
},
"lock-on-suspend": {
@@ -1625,11 +1663,11 @@
"label": "Bluetooth'u Etkinleştir"
},
"section": {
"description": "Wi-Fi ve Bluetooth bağlantılarını yönetin."
"description": "Kablosuz ve Bluetooth bağlantılarını yönetin."
},
"title": "Ağ",
"wifi": {
"label": "Wi-Fi'yi Etkinleştir"
"label": "Kablosuz Bağlantıyı Etkinleştir"
}
},
"notifications": {
@@ -1755,7 +1793,7 @@
"label": "Giriş sesi"
},
"lockkey": {
"description": "Caps Lock, Num Lock veya Scroll Lock değiştirildiğinde OSD'yi göster.",
"description": "Büyük Harf Kilidi, Sayı Kilidi veya Kaydırma Kilidi değiştirildiğinde OSD'yi göster.",
"label": "Kilit tuşları"
},
"section": {
@@ -1841,7 +1879,7 @@
"audio": {
"audio-codec": {
"description": "En iyi performans ve en küçük ses boyutu için Opus önerilir.",
"label": "Ses codec"
"label": "Ses çözücüsü"
},
"audio-source": {
"description": "Kayıt sırasında yakalanacak ses kaynağı.",
@@ -1864,7 +1902,7 @@
},
"select-output-folder": "Çıktı klasörünü seç",
"show-cursor": {
"description": "Video fare imlecini kaydedin.",
"description": "Görüntü fare imlecini kaydedin.",
"label": "İmleci göster"
}
},
@@ -1879,20 +1917,20 @@
"label": "Kare hızı"
},
"section": {
"description": "Video kaydı seçeneklerini yapılandırın.",
"label": "Video ayarları"
"description": "Görüntü kaydı seçeneklerini yapılandırın.",
"label": "Görüntü ayarları"
},
"video-codec": {
"description": "h264 en yaygın codec'tir.",
"label": "Video codec"
"description": "h264 en yaygın çözücüdür.",
"label": "Görüntü çözücüsü"
},
"video-quality": {
"description": "Daha yüksek kalite daha büyük dosya boyutları ile sonuçlanır.",
"label": "Video kalitesi"
"label": "Görüntü kalitesi"
},
"video-source": {
"description": "Portal önerilir, eğer artefaktlar alırsanız Ekranı deneyin.",
"label": "Video kaynağı"
"label": "Görüntü kaynağı"
}
}
},
@@ -1949,7 +1987,7 @@
"label": "Kritik Eşiği"
},
"cpu-section": {
"label": "CPU Kullanımı"
"label": "İşlemci Kullanımı"
},
"cpu-warning-threshold": {
"label": "Uyarı Eşiği"
@@ -2000,10 +2038,10 @@
"label": "Uyarı Eşiği"
},
"temperature-section": {
"label": "CPU Sıcaklığı"
"label": "İşlemci Sıcaklığı"
},
"thresholds-section": {
"description": "Her sistem metriği için uyarı/kritik eşiklerini ve yoklama aralıklarını ayarlayın.",
"description": "Her sistem ölçüsü için uyarı/kritik eşiklerini ve yoklama aralıklarını ayarlayın.",
"label": "Eşikler"
},
"title": "Sistem İzleme",
@@ -2022,7 +2060,7 @@
},
"animation-disable": {
"description": "Daha hızlı ve daha duyarlı bir deneyim için tüm animasyonları devre dışı bırakın.",
"label": "UI Animasyonlarını Devre Dışı Bırak"
"label": "Kullanıcı Arayüzü Animasyonlarını Devre Dışı Bırak"
},
"animation-speed": {
"description": "Genel animasyon hızını ayarlar.",
@@ -2049,7 +2087,7 @@
"reset": "Karartılmış masaüstü opaklığını sıfırla"
},
"panel-background-opacity": {
"description": "Tüm paneller için arka plan opaklığını ayarlayın (Launcher, Control Center, Ayarlar vb.).",
"description": "Tüm paneller için arka plan opaklığını ayarlayın (Başlatıcı, Kontrol Merkezi, Ayarlar vb.).",
"label": "Panel arka plan opaklığı"
},
"panels-attached-to-bar": {
@@ -2183,7 +2221,7 @@
},
"customize": {
"header": "Deneyiminizi özelleştirin",
"subheader": "Bar konumunu, yoğunluğunu, ölçeğini ve daha fazlasını ayarlayın."
"subheader": "Araç çubuğu konumunu, yoğunluğunu, ölçeğini ve daha fazlasını ayarlayın."
},
"wallpaper": {
"choose-dir": "Duvar kağıdı görüntülerinizi içeren bir dizin seçin",
@@ -2269,8 +2307,8 @@
"opened": "Ko-fi sayfası tarayıcınızda açıldı"
},
"missing-control-center": {
"description": "Kontrol Merkezi widget'ı çubuktan kaldırıldı. Çubuktan tekrar erişmek için widget'ı yeniden eklemeniz gerekecek. Çubuğa sağ tıklayarak da açabilirsiniz.",
"label": "Son Kontrol Merkezi widget'ı kaldırıldı"
"description": "Kontrol Merkezi araç takımı araç çubuğundan kaldırıldı. Araç çubuğundan tekrar erişmek için araç takımını yeniden eklemeniz gerekecek. Araç çubuğuna sağ tıklayarak da açabilirsiniz.",
"label": "Son Kontrol Merkezi araç takımı kaldırıldı"
},
"night-light": {
"disabled": "Devre dışı",
@@ -2323,7 +2361,7 @@
}
},
"tooltips": {
"add-widget": "Widget ekle",
"add-widget": "Araç takımı ekle",
"bluetooth-devices": "Bluetooth cihazları",
"brightness-at": "Parlaklık: %{brightness}",
"cancel-timer": "Zamanlayıcı",
@@ -2347,7 +2385,7 @@
"keyboard-layout": "{layout} klavye düzeni",
"list-view": "Liste görünümü",
"manage-vpn": "VPN bağlantıları",
"manage-wifi": "Wi-Fi",
"manage-wifi": "Kablosuz Bağlantı",
"microphone-volume-at": "Mikrofon sesi: %{volume}",
"move-to-center-section": "Orta bölüm",
"move-to-left-section": "Sol bölüm",
@@ -2376,7 +2414,7 @@
"refresh-devices": "Cihazları yenile",
"refresh-wallhaven": "Wallhaven sonuçlarını yenile",
"refresh-wallpaper-list": "Duvar kağıdı listesini yenile",
"remove-widget": "Widget kaldır",
"remove-widget": "Araç takımını kaldır",
"screen-recorder-not-installed": "Ekran kaydedici (yüklü değil)",
"search": "Ara",
"search-close": "Aramayı kapat",
@@ -2389,7 +2427,7 @@
"up": "Üst dizin",
"volume-at": "Çıkış sesi: %{volume}",
"wallpaper-selector": "Duvar kağıdı seçici",
"widget-settings": "Widget ayarları"
"widget-settings": "Araç takımı ayarları"
},
"wallpaper": {
"configure-directory": "Resimler içeren duvar kağıdı dizininizi yapılandırın.",
@@ -2566,21 +2604,21 @@
"available-networks": "Kullanılabilir Ağlar",
"connect": "Bağlan",
"connected": "Bağlı",
"disabled": "Wi-Fi devre dışı",
"disabled": "Kablosuz Bağlantı devre dışı",
"disconnect": "Bağlantıyı kes",
"disconnecting": "Bağlantı kesiliyor...",
"enable-message": "Mevcut ağları görmek için Wi-Fi'yi etkinleştirin.",
"enter-password": "Şifre girin...",
"enable-message": "Mevcut ağları görmek için kablosuz bağlantıyı etkinleştirin.",
"enter-password": "Parola girin...",
"forget": "Unut",
"forget-network": "Bu ağı unut?",
"forgetting": "Unutuluyor...",
"known-networks": "Bilinen Ağlar",
"no-networks": "Ağ bulunamadı",
"password": "Şifre",
"password": "Parola",
"saved": "Kaydedildi",
"scan-again": "Yeniden tara",
"searching": "Yakındaki ağlar aranıyor...",
"title": "Wi-Fi"
"title": "Kablosuz Bağlantı"
}
}
}
+40 -2
View File
@@ -140,6 +140,13 @@
"stream-description": "Введіть команду для безперервного запуску."
},
"dynamic-text": "Динамічний текст",
"hide-mode": {
"alwaysExpanded": "Завжди розширено",
"description": "Контролює видимість віджета, коли команда не має виведення.",
"expandWithOutput": "Розширити, якщо є виведення",
"label": "Режим приховування",
"maxTransparent": "Максимально розширено, але прозоро"
},
"icon": {
"description": "Вибрати значок з бібліотеки.",
"label": "Значок"
@@ -175,6 +182,10 @@
"label": "Правий клік",
"update-text": "Оновити текст, що відображається, при натисканні правою кнопкою миші"
},
"show-icon": {
"description": "Перемикає видимість значка віджета.",
"label": "Показати значок"
},
"text-stream": {
"description": "Потокові рядки з команди відображатимуться як текст на кнопці.",
"label": "Потік"
@@ -343,6 +354,9 @@
"description": "Встановити ширину заголовків вікон на панелі завдань (у пікселях).",
"label": "Ширина заголовка",
"reset-tooltip": "Скинути ширину заголовка"
"show-pinned-apps": {
"description": "Показувати закріплені програми з док-панелі на панелі завдань.",
"label": "Показати закріплені програми"
}
},
"taskbar-grouped": {
@@ -359,6 +373,10 @@
"drawer-enabled": {
"description": "Коли увімкнено, не закріплені елементи трея відображаються на панелі ящика. Коли вимкнено, всі елементи трея відображаються в рядку.",
"label": "Увімкнути висувну панель"
},
"hide-passive": {
"description": "Якщо ввімкнено, елементи в треї зі статусом \"Пасивний\" будуть приховані.",
"label": "Приховати пасивні предмети"
}
},
"volume": {
@@ -531,11 +549,12 @@
"misc": "Різне",
"network": "Мережа",
"office": "Офіс",
"pinned": "Закріплено",
"system": "Система",
"webbrowser": "Веб-браузер"
},
"pin": "Закріпити в доці",
"unpin": "Відкріпити з доку"
"pin": "Закріпити",
"unpin": "Відкріпити"
},
"lock-screen": {
"authenticating": "Автентифікація...",
@@ -736,6 +755,9 @@
"clipboard-loading": "Завантаження історії буфера обміну...",
"clipboard-loading-description": "Зачекайте, будь ласка",
"clipboard-search-description": "Пошук в історії буфера обміну",
"command": "Команда",
"command-description": "Виконати команди оболонки",
"command-name": "Команда",
"emoji": "Обрати емодзі",
"emoji-loading": "Завантаження емодзі...",
"emoji-loading-description": "Зачекайте, будь ласка",
@@ -1337,6 +1359,10 @@
"description": "Застосувати кольори теми до значків застосункiв у доці (тільки неактивні застосунки).",
"label": "Розфарбувати значки"
},
"dead-opacity": {
"description": "Відрегулюйте прозорість іконок програм, які не запущені.",
"label": "Мертва непрозорість"
},
"display": {
"always-visible": "Завжди видимий",
"auto-hide": "Автоприховування",
@@ -1352,6 +1378,14 @@
"description": "Налаштуйте загальний розмір дока.",
"label": "Розмір дока"
},
"inactive-indicators": {
"description": "Відображати індикатори-пігулки для всіх програм, а не лише для поточної активної.",
"label": "Індикатори бігу"
},
"pinned-static": {
"description": "Завжди закріплюйте значки програм ліворуч у статичному порядку.",
"label": "Статично закріплені програми"
},
"section": {
"description": "Налаштуйте поведінку та зовнішній вигляд дока.",
"label": "Зовнішній вигляд"
@@ -1513,6 +1547,10 @@
"description": "Налаштуйте поведінку та зовнішній вигляд лаунчера.",
"label": "Зовнішній вигляд"
},
"show-categories": {
"description": "Показувати вкладки категорій для фільтрації додатків.",
"label": "Показувати категорії"
},
"sort-by-usage": {
"description": "Коли увімкнено, часто використовувані застосунки з'являються першими в списку.",
"label": "Сортувати за використанням"
+40 -2
View File
@@ -140,6 +140,13 @@
"stream-description": "输入一个要持续运行的命令。"
},
"dynamic-text": "动态文本",
"hide-mode": {
"alwaysExpanded": "始终展开",
"description": "控制命令无输出时小部件的可见性。",
"expandWithOutput": "有输出时展开",
"label": "隐藏模式",
"maxTransparent": "最大展开但透明"
},
"icon": {
"description": "从库中选择图标。",
"label": "图标"
@@ -175,6 +182,10 @@
"label": "右键点击",
"update-text": "右键单击时更新显示的文本"
},
"show-icon": {
"description": "切换小部件图标的可见性。",
"label": "显示图标"
},
"text-stream": {
"description": "来自命令的流式输出行将作为文本显示在按钮上。",
"label": "流"
@@ -343,6 +354,9 @@
"description": "设置任务栏中窗口标题的宽度(以像素为单位)。",
"label": "标题宽度",
"reset-tooltip": "重置标题宽度"
"show-pinned-apps": {
"description": "在任务栏中显示 Dock 上固定的应用。",
"label": "显示已置顶的应用"
}
},
"taskbar-grouped": {
@@ -359,6 +373,10 @@
"drawer-enabled": {
"description": "启用时,未固定的托盘项显示在抽屉面板中。禁用时,所有托盘项都内联显示。",
"label": "启用抽屉"
},
"hide-passive": {
"description": "启用后,将隐藏状态为“被动”的托盘图标。",
"label": "隐藏被动物品"
}
},
"volume": {
@@ -531,11 +549,12 @@
"misc": "杂项",
"network": "网络",
"office": "办公室",
"pinned": "已固定",
"system": "系统",
"webbrowser": "网页浏览器"
},
"pin": "固定到 Dock",
"unpin": "从 Dock 取消固定"
"pin": "固定",
"unpin": "取消固定"
},
"lock-screen": {
"authenticating": "正在验证...",
@@ -736,6 +755,9 @@
"clipboard-loading": "正在加载剪贴板历史记录...",
"clipboard-loading-description": "请稍候",
"clipboard-search-description": "搜索剪贴板历史记录",
"command": "命令",
"command-description": "运行 shell 命令",
"command-name": "命令",
"emoji": "表情符号选择器",
"emoji-loading": "正在加载表情符号...",
"emoji-loading-description": "请稍候",
@@ -1337,6 +1359,10 @@
"description": "将主题颜色应用到 Dock 应用图标(仅限非聚焦应用)。",
"label": "着色图标"
},
"dead-opacity": {
"description": "调整未运行的应用程序图标的不透明度。",
"label": "死亡不透明度"
},
"display": {
"always-visible": "始终可见",
"auto-hide": "自动隐藏",
@@ -1352,6 +1378,14 @@
"description": "调整 Dock 的整体大小。",
"label": "Dock 大小"
},
"inactive-indicators": {
"description": "为所有应用显示指示器小药丸,而不仅仅是当前活跃的应用。",
"label": "运行指标"
},
"pinned-static": {
"description": "始终将固定的应用图标按静态顺序推到左侧。",
"label": "静态固定应用"
},
"section": {
"description": "自定义 Dock 的行为和外观。",
"label": "外观"
@@ -1513,6 +1547,10 @@
"description": "自定义启动器的行为和外观。",
"label": "外观"
},
"show-categories": {
"description": "显示用于筛选应用程序的类别标签。",
"label": "显示类别"
},
"sort-by-usage": {
"description": "启用后,经常启动的应用程序将显示在列表首位。",
"label": "按使用频率排序"
+2 -4
View File
@@ -175,7 +175,8 @@
"terminalCommand": "xterm -e",
"customLaunchPrefixEnabled": false,
"customLaunchPrefix": "",
"viewMode": "list"
"viewMode": "list",
"showCategories": true
},
"controlCenter": {
"position": "close_to_bar_button",
@@ -377,9 +378,6 @@
"manualSunrise": "06:30",
"manualSunset": "18:30"
},
"changelog": {
"lastSeenVersion": ""
},
"hooks": {
"enabled": false,
"wallpaperChange": "",
+4
View File
@@ -129,6 +129,10 @@ Singleton {
"settings-system-monitor": "activity",
"bluetooth": "bluetooth",
"bt-device-generic": "bluetooth",
"bt-device-gamepad": "device-gamepad-2",
"bt-device-microphone": "microphone",
"bt-device-headset": "headset",
"bt-device-earbuds": "device-airpods",
"bt-device-headphones": "headphones",
"bt-device-mouse": "mouse-2",
"bt-device-keyboard": "bluetooth",
+5 -4
View File
@@ -346,6 +346,7 @@ Singleton {
property string customLaunchPrefix: ""
// View mode: "list" or "grid"
property string viewMode: "list"
property bool showCategories: true
}
// control center
@@ -439,6 +440,10 @@ Singleton {
// Desktop entry IDs pinned to the dock (e.g., "org.kde.konsole", "firefox.desktop")
property list<string> pinnedApps: []
property bool colorizeIcons: false
property bool pinnedStatic: false
property bool inactiveIndicators: false
property double deadOpacity: 0.6
}
// network
@@ -570,10 +575,6 @@ Singleton {
property string manualSunset: "18:30"
}
property JsonObject changelog: JsonObject {
property string lastSeenVersion: ""
}
// hooks
property JsonObject hooks: JsonObject {
property bool enabled: false
+18 -4
View File
@@ -27,6 +27,7 @@ Item {
// Effective shown state (true if hovered/animated open or forced)
readonly property bool revealed: !forceClose && (forceOpen || showPill)
readonly property bool hasIcon: root.icon !== ""
signal shown
signal hidden
@@ -68,7 +69,14 @@ Item {
}
}
width: collapseToIcon ? pillHeight : pillHeight + Math.max(0, pill.width - pillOverlap)
width: {
if (collapseToIcon) {
return hasIcon ? pillHeight : 0;
}
var overlap = hasIcon ? pillOverlap : 0;
var baseWidth = hasIcon ? pillHeight : 0;
return baseWidth + Math.max(0, pill.width - overlap);
}
height: pillHeight
Connections {
@@ -103,8 +111,11 @@ Item {
width: revealed ? pillMaxWidth : 1
height: pillHeight
x: oppositeDirection ? (iconCircle.x + iconCircle.width / 2) : // Opens right
(iconCircle.x + iconCircle.width / 2) - width // Opens left
x: {
if (!hasIcon)
return 0;
return oppositeDirection ? (iconCircle.x + iconCircle.width / 2) : (iconCircle.x + iconCircle.width / 2) - width;
}
opacity: revealed ? Style.opacityFull : Style.opacityNone
color: Color.transparent // Make pill background transparent to avoid double opacity
@@ -119,6 +130,9 @@ Item {
id: textItem
anchors.verticalCenter: parent.verticalCenter
x: {
if (!hasIcon)
return (parent.width - width) / 2;
// Better text horizontal centering
var centerX = (parent.width - width) / 2;
var offset = oppositeDirection ? Style.marginXS : -Style.marginXS;
@@ -155,7 +169,7 @@ Item {
Rectangle {
id: iconCircle
width: pillHeight
width: hasIcon ? pillHeight : 0
height: pillHeight
radius: Math.min(Style.radiusL, width / 2)
color: Color.transparent // Make icon background transparent to avoid double opacity
+22 -4
View File
@@ -52,6 +52,7 @@ Item {
// Effective shown state (true if animated open or forced, but not if force closed)
readonly property bool revealed: !forceClose && (forceOpen || showPill)
readonly property bool hasIcon: root.icon !== ""
// Always prioritize hover color, then the custom one and finally the fallback color
readonly property color bgColor: hovered ? Color.mHover : (customBackgroundColor.a > 0) ? customBackgroundColor : Style.capsuleColor
@@ -77,7 +78,18 @@ Item {
// For vertical bars: width is just icon size, height includes pill space
width: buttonSize
height: collapseToIcon ? buttonSize : (revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize)
height: {
if (collapseToIcon) {
return hasIcon ? buttonSize : 0;
}
if (revealed) {
var overlap = hasIcon ? pillOverlap : 0;
var baseHeight = hasIcon ? buttonSize : 0;
return baseHeight + Math.max(0, maxPillHeight - overlap);
}
// Fallback to buttonSize in idle state to remain clickable
return buttonSize;
}
Connections {
target: root
@@ -92,9 +104,11 @@ Item {
Rectangle {
id: pillBackground
width: buttonSize
height: collapseToIcon ? buttonSize : (revealed ? (buttonSize + maxPillHeight - pillOverlap) : buttonSize)
height: root.height
radius: Style.radiusM
color: root.bgColor
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
Behavior on color {
ColorAnimation {
@@ -112,7 +126,11 @@ Item {
// Position based on direction - center the pill relative to the icon
x: 0
y: openUpward ? (iconCircle.y + iconCircle.height / 2 - height) : (iconCircle.y + iconCircle.height / 2)
y: {
if (!hasIcon)
return 0;
return openUpward ? (iconCircle.y + iconCircle.height / 2 - height) : (iconCircle.y + iconCircle.height / 2);
}
opacity: revealed ? Style.opacityFull : Style.opacityNone
color: Color.transparent // Make pill background transparent to avoid double opacity
@@ -129,7 +147,7 @@ Item {
id: textItem
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: openDownward ? Style.marginXXS : -Style.marginXXS
anchors.verticalCenterOffset: hasIcon ? (openDownward ? Style.marginXXS : -Style.marginXXS) : 0
rotation: rotateText ? -90 : 0
text: root.text + root.suffix
family: Settings.data.ui.fontFixed
+11
View File
@@ -305,6 +305,17 @@ PopupWindow {
// PIN / UNPIN
Rectangle {
visible: {
if (widgetSection === "" || widgetIndex < 0)
return false;
var widgets = Settings.data.bar.widgets[widgetSection];
if (!widgets || widgetIndex >= widgets.length)
return false;
var widgetSettings = widgets[widgetIndex];
if (!widgetSettings)
return false;
return widgetSettings.drawerEnabled ?? false;
}
Layout.preferredWidth: parent.width
Layout.preferredHeight: 28
color: pinUnpinMouseArea.containsMouse ? Qt.alpha(Color.mPrimary, 0.2) : Qt.alpha(Color.mPrimary, 0.08)
+83 -3
View File
@@ -52,6 +52,83 @@ Item {
readonly property string textCollapse: widgetSettings.textCollapse !== undefined ? widgetSettings.textCollapse : (widgetMetadata.textCollapse || "")
readonly property bool parseJson: widgetSettings.parseJson !== undefined ? widgetSettings.parseJson : (widgetMetadata.parseJson || false)
readonly property bool hasExec: (leftClickExec || rightClickExec || middleClickExec || (wheelMode === "unified" && wheelExec) || (wheelMode === "separate" && (wheelUpExec || wheelDownExec)))
readonly property bool showIcon: (widgetSettings.showIcon !== undefined) ? widgetSettings.showIcon : true
readonly property string hideMode: widgetSettings.hideMode || "alwaysExpanded"
readonly property bool hasOutput: _dynamicText !== ""
readonly property bool shouldForceOpen: textStream && (hideMode === "alwaysExpanded" || hideMode === "maxTransparent")
readonly property bool _useNewHideLogic: textCommand && textCommand.length > 0 && textStream
readonly property bool _useTextCommandLogic: textCommand && textCommand.length > 0 && textStream
readonly property bool _pillVisible: {
if (!_useTextCommandLogic) {
return true;
}
if (hideMode === "alwaysExpanded" || hideMode === "maxTransparent") {
return true;
}
var hasActualIcon = (_dynamicIcon !== "" || customIcon !== "");
return hasOutput || (showIcon && hasActualIcon);
}
readonly property real _pillOpacity: {
if (!_useTextCommandLogic) {
return 1.0;
}
if (hideMode === "maxTransparent" && !hasOutput) {
return 0.0;
}
return 1.0;
}
readonly property bool _pillForceOpen: {
if (!_useTextCommandLogic) {
return _dynamicText !== "" || (textStream && currentMaxTextLength > 0);
}
if (currentMaxTextLength <= 0) {
return false;
}
if (hideMode === "alwaysExpanded" || hideMode === "maxTransparent") {
return true;
}
return hasOutput;
}
readonly property string _pillIcon: {
if (!_useTextCommandLogic) {
if (textCommand && textCommand.length > 0 && showIcon) {
return _dynamicIcon !== "" ? _dynamicIcon : customIcon;
} else if (!(textCommand && textCommand.length > 0)) {
return _dynamicIcon !== "" ? _dynamicIcon : customIcon;
} else {
return "";
}
}
if (!showIcon)
return "";
var actualIcon = _dynamicIcon !== "" ? _dynamicIcon : customIcon;
if (hideMode === "expandWithOutput" && actualIcon === "") {
return "question-mark";
}
return actualIcon;
}
readonly property string _pillText: {
if (!_useTextCommandLogic) {
return (!isVerticalBar || currentMaxTextLength > 0) ? _dynamicText : "";
}
if (currentMaxTextLength <= 0) {
return "";
}
if (hasOutput) {
return _dynamicText;
}
if (hideMode === "expandWithOutput") {
return "";
}
return " ".repeat(currentMaxTextLength);
}
implicitWidth: pill.width
implicitHeight: pill.height
@@ -59,14 +136,17 @@ Item {
BarPill {
id: pill
visible: _pillVisible
opacity: _pillOpacity
screen: root.screen
oppositeDirection: BarService.getPillDirection(root)
icon: _dynamicIcon !== "" ? _dynamicIcon : customIcon
text: (!isVerticalBar || currentMaxTextLength > 0) ? _dynamicText : ""
icon: _pillIcon
text: _pillText
density: Settings.data.bar.density
rotateText: isVerticalBar && currentMaxTextLength > 0
autoHide: false
forceOpen: _dynamicText !== ""
forceOpen: _pillForceOpen
tooltipText: {
var tooltipLines = [];
+1 -1
View File
@@ -266,7 +266,7 @@ Item {
anchors.fill: parent
visible: showProgressRing
progress: MediaService.trackLength > 0 ? MediaService.currentPosition / MediaService.trackLength : 0
lineWidth: 2.5 * scaling
lineWidth: 2 * scaling
}
Item {
+221 -44
View File
@@ -42,6 +42,7 @@ Rectangle {
readonly property bool onlyActiveWorkspaces: (widgetSettings.onlyActiveWorkspaces !== undefined) ? widgetSettings.onlyActiveWorkspaces : widgetMetadata.onlyActiveWorkspaces
readonly property bool showTitle: isVerticalBar ? false : (widgetSettings.showTitle !== undefined) ? widgetSettings.showTitle : widgetMetadata.showTitle
readonly property int titleWidth: (widgetSettings.titleWidth !== undefined) ? widgetSettings.titleWidth : widgetMetadata.titleWidth
readonly property bool showPinnedApps: (widgetSettings.showPinnedApps !== undefined) ? widgetSettings.showPinnedApps : widgetMetadata.showPinnedApps
// Context menu state
property var selectedWindow: null
@@ -50,6 +51,149 @@ Rectangle {
// Hover state
property var hoveredWindowId: ""
// Combined model of running windows and pinned apps
property var combinedModel: []
// Helper function to normalize app IDs for case-insensitive matching
function normalizeAppId(appId) {
if (!appId || typeof appId !== 'string')
return "";
return appId.toLowerCase().trim();
}
// Helper function to check if an app ID matches a pinned app (case-insensitive)
function isAppIdPinned(appId, pinnedApps) {
if (!appId || !pinnedApps || pinnedApps.length === 0)
return false;
const normalizedId = normalizeAppId(appId);
return pinnedApps.some(pinnedId => normalizeAppId(pinnedId) === normalizedId);
}
// Helper function to get app name from desktop entry
function getAppNameFromDesktopEntry(appId) {
if (!appId)
return appId;
try {
if (typeof DesktopEntries !== 'undefined' && DesktopEntries.heuristicLookup) {
const entry = DesktopEntries.heuristicLookup(appId);
if (entry && entry.name) {
return entry.name;
}
}
if (typeof DesktopEntries !== 'undefined' && DesktopEntries.byId) {
const entry = DesktopEntries.byId(appId);
if (entry && entry.name) {
return entry.name;
}
}
} catch (e)
// Fall through to return original appId
{}
// Return original appId if we can't find a desktop entry
return appId;
}
// Function to update the combined model
function updateCombinedModel() {
const runningWindows = [];
const pinnedApps = Settings.data.dock.pinnedApps || [];
const processedAppIds = new Set();
// First pass: Add all running windows
try {
const total = CompositorService.windows.count || 0;
const activeIds = CompositorService.getActiveWorkspaces().map(function (ws) {
return ws.id;
});
for (var i = 0; i < total; i++) {
var w = CompositorService.windows.get(i);
if (!w)
continue;
var passOutput = (!onlySameOutput) || (w.output == screen?.name);
var passWorkspace = (!onlyActiveWorkspaces) || (activeIds.includes(w.workspaceId));
if (passOutput && passWorkspace) {
const isPinned = isAppIdPinned(w.appId, pinnedApps);
runningWindows.push({
"type": isPinned ? "pinned-running" : "running",
"window": w,
"appId": w.appId,
"title": w.title || getAppNameFromDesktopEntry(w.appId)
});
processedAppIds.add(normalizeAppId(w.appId));
}
}
} catch (e)
// Ignore errors
{}
// Second pass: Add non-running pinned apps (only if showPinnedApps is enabled)
if (showPinnedApps) {
pinnedApps.forEach(pinnedAppId => {
const normalizedPinnedId = normalizeAppId(pinnedAppId);
if (!processedAppIds.has(normalizedPinnedId)) {
const appName = getAppNameFromDesktopEntry(pinnedAppId);
runningWindows.push({
"type": "pinned",
"window": null,
"appId": pinnedAppId,
"title": appName
});
}
});
}
combinedModel = runningWindows;
updateHasWindow();
}
// Function to launch a pinned app
function launchPinnedApp(appId) {
if (!appId)
return;
try {
const app = DesktopEntries.byId(appId);
if (Settings.data.appLauncher.customLaunchPrefixEnabled && Settings.data.appLauncher.customLaunchPrefix) {
// Use custom launch prefix
const prefix = Settings.data.appLauncher.customLaunchPrefix.split(" ");
if (app.runInTerminal) {
const terminal = Settings.data.appLauncher.terminalCommand.split(" ");
const command = prefix.concat(terminal.concat(app.command));
Quickshell.execDetached(command);
} else {
const command = prefix.concat(app.command);
Quickshell.execDetached(command);
}
} else if (Settings.data.appLauncher.useApp2Unit && app.id) {
Logger.d("Taskbar", `Using app2unit for: ${app.id}`);
if (app.runInTerminal)
Quickshell.execDetached(["app2unit", "--", app.id + ".desktop"]);
else
Quickshell.execDetached(["app2unit", "--"].concat(app.command));
} else {
// Fallback logic when app2unit is not used
if (app.runInTerminal) {
Logger.d("Taskbar", "Executing terminal app manually: " + app.name);
const terminal = Settings.data.appLauncher.terminalCommand.split(" ");
const command = terminal.concat(app.command);
Quickshell.execDetached(command);
} else if (app.execute) {
// Default execution for GUI apps
app.execute();
} else {
Logger.w("Taskbar", `Could not launch: ${app.name}. No valid launch method.`);
}
}
} catch (e) {
Logger.e("Taskbar", "Failed to launch app: " + e);
}
}
NPopupContextMenu {
id: contextMenu
@@ -95,41 +239,31 @@ Rectangle {
}
function updateHasWindow() {
try {
var total = CompositorService.windows.count || 0;
var activeIds = CompositorService.getActiveWorkspaces().map(function (ws) {
return ws.id;
});
var found = false;
for (var i = 0; i < total; i++) {
var w = CompositorService.windows.get(i);
if (!w)
continue;
var passOutput = (!onlySameOutput) || (w.output == screen.name);
var passWorkspace = (!onlyActiveWorkspaces) || (activeIds.includes(w.workspaceId));
if (passOutput && passWorkspace) {
found = true;
break;
}
}
hasWindow = found;
} catch (e) {
hasWindow = false;
}
// Check if we have any items in the combined model (windows or pinned apps)
hasWindow = combinedModel.length > 0;
}
Connections {
target: CompositorService
function onWindowListChanged() {
updateHasWindow();
updateCombinedModel();
}
function onWorkspaceChanged() {
updateHasWindow();
updateCombinedModel();
}
}
Component.onCompleted: updateHasWindow()
onScreenChanged: updateHasWindow()
Connections {
target: Settings.data.dock
function onPinnedAppsChanged() {
updateCombinedModel();
}
}
Component.onCompleted: {
updateCombinedModel();
}
onScreenChanged: updateCombinedModel()
// "visible": Always Visible, "hidden": Hide When Empty, "transparent": Transparent When Empty
visible: hideMode !== "hidden" || hasWindow
@@ -164,15 +298,16 @@ Rectangle {
columnSpacing: isVerticalBar ? 0 : Style.marginXXS
Repeater {
model: CompositorService.windows
model: root.combinedModel
delegate: Item {
id: taskbarItem
required property var modelData
property ShellScreen screen: root.screen
visible: (!onlySameOutput || modelData.output === screen?.name) && (!onlyActiveWorkspaces || CompositorService.getActiveWorkspaces().map(function (ws) {
return ws.id;
}).includes(modelData.workspaceId))
readonly property bool isRunning: modelData.window !== null
readonly property bool isPinned: modelData.type === "pinned" || modelData.type === "pinned-running"
readonly property bool isFocused: isRunning && modelData.window && modelData.window.isFocused
readonly property bool isPinnedRunning: isPinned && isRunning && !isFocused
readonly property bool isHovered: root.hoveredWindowId === modelData.id
readonly property real itemSpacing: Style.marginS
@@ -200,6 +335,29 @@ Rectangle {
duration: Style.animationFast
easing.type: Easing.InOutQuad
}
height: parent.height
source: ThemeIcons.iconForAppId(modelData.appId)
smooth: true
asynchronous: true
// Opacity: Focused (1.0) > Pinned Running (0.7) > Regular Running (0.6) > Just Pinned (0.4)
opacity: isFocused ? Style.opacityFull : (isPinnedRunning ? 0.7 : (isRunning ? 0.6 : 0.4))
// For pinned apps that aren't running: use a muted color to indicate not running
// For other apps: use standard colorization if enabled
layer.enabled: (isPinned && !isRunning) || (root.widgetSettings.colorizeIcons !== false && !isFocused)
layer.effect: ShaderEffect {
property color targetColor: {
// Pinned but not running: use a muted/desaturated color to indicate not running
if (isPinned && !isRunning) {
// Use a muted secondary or outline color
return Settings.data.colorSchemes.darkMode ? Qt.darker(Color.mSecondary, 1.3) : Qt.lighter(Color.mSecondary, 1.5);
}
// Standard colorization for other cases
return Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mSurfaceVariant;
}
property real colorizeMode: 0.0 // Dock mode (grayscale)
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb")
}
}
@@ -268,6 +426,16 @@ Rectangle {
color: titleFgColor
opacity: Style.opacityFull
}
// Active indicator (focused window)
Rectangle {
id: iconBackground
anchors.bottomMargin: -2
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
width: 4
height: 4
color: isFocused ? Color.mPrimary : Color.transparent
radius: Math.min(Style.radiusXXS, width / 2)
}
}
@@ -279,33 +447,42 @@ Rectangle {
preventStealing: true
onPressed: function (mouse) {
if (!taskbarItem.modelData)
if (!modelData)
return;
if (mouse.button === Qt.LeftButton) {
try {
CompositorService.focusWindow(taskbarItem.modelData);
} catch (error) {
Logger.e("Taskbar", "Failed to activate toplevel: " + error);
if (isRunning && modelData.window) {
// Running app - focus it
try {
CompositorService.focusWindow(modelData.window);
} catch (error) {
Logger.e("Taskbar", "Failed to activate toplevel: " + error);
}
} else if (isPinned) {
// Pinned app not running - launch it
root.launchPinnedApp(modelData.appId);
}
}
}
onReleased: function (mouse) {
if (!taskbarItem.modelData)
if (!modelData)
return;
if (mouse.button === Qt.RightButton) {
mouse.accepted = true;
TooltipService.hide();
root.selectedWindow = taskbarItem.modelData;
root.selectedAppName = CompositorService.getCleanAppName(taskbarItem.modelData.appId, taskbarItem.modelData.title);
// Only show context menu for running apps
if (isRunning && modelData.window) {
root.selectedWindow = modelData.window;
root.selectedAppName = CompositorService.getCleanAppName(modelData.appId, modelData.title);
// Store position and size for timer callback
const globalPos = taskbarItem.mapToItem(root, 0, 0);
contextMenuOpenTimer.globalX = globalPos.x;
contextMenuOpenTimer.globalY = globalPos.y;
contextMenuOpenTimer.itemWidth = taskbarItem.width;
contextMenuOpenTimer.itemHeight = taskbarItem.height;
contextMenuOpenTimer.restart();
// Store position and size for timer callback
const globalPos = taskbarItem.mapToItem(root, 0, 0);
contextMenuOpenTimer.globalX = globalPos.x;
contextMenuOpenTimer.globalY = globalPos.y;
contextMenuOpenTimer.itemWidth = taskbarItem.width;
contextMenuOpenTimer.itemHeight = taskbarItem.height;
contextMenuOpenTimer.restart();
}
}
}
onEntered: {
+50 -8
View File
@@ -21,7 +21,7 @@ Rectangle {
// Get shared popup menu window from PanelService (reactive to trigger changes)
readonly property var popupMenuWindow: {
// Reference trigger to force re-evaluation
var _ = popupMenuUpdateTrigger;
var popupMenuUpdateTriggerRef = popupMenuUpdateTrigger;
return PanelService.getPopupMenuWindow(screen);
}
@@ -61,12 +61,10 @@ Rectangle {
property list<string> blacklist: widgetSettings.blacklist || widgetMetadata.blacklist || [] // Read from settings
property list<string> pinned: widgetSettings.pinned || widgetMetadata.pinned || [] // Pinned items (shown inline)
property bool drawerEnabled: widgetSettings.drawerEnabled !== undefined ? widgetSettings.drawerEnabled : (widgetMetadata.drawerEnabled !== undefined ? widgetMetadata.drawerEnabled : true) // Enable drawer panel
property bool hidePassive: widgetSettings.hidePassive !== undefined ? widgetSettings.hidePassive : true // Hide passive status items
property var filteredItems: [] // Items to show inline (pinned)
property var dropdownItems: [] // Items to show in drawer (unpinned)
// Debounce timer for updateFilteredItems to prevent excessive calls
// when multiple events (e.g., SystemTray changes, settings saves)
// trigger it in rapid succession, reducing redundant processing.
Timer {
id: updateDebounceTimer
interval: 100 // milliseconds
@@ -75,6 +73,43 @@ Rectangle {
onTriggered: _performFilteredItemsUpdate()
}
readonly property var statusSignature: {
if (!SystemTray.items || !SystemTray.items.values) {
return "";
}
var sig = "";
var items = SystemTray.items.values;
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item) {
// Direct property access creates reactive binding
var s = item.status;
sig += (item.id || i) + ":" + (s !== undefined ? s : -1);
}
}
// Trigger update when signature changes (status changed)
if (root.hidePassive) {
Qt.callLater(root.updateFilteredItems);
}
return sig;
}
Repeater {
id: statusConnectionsRepeater
model: SystemTray.items && SystemTray.items.values ? SystemTray.items.values : []
delegate: Item {
Connections {
target: modelData
enabled: modelData !== null && modelData !== undefined
function onStatusChanged() {
if (root.hidePassive) {
root.updateFilteredItems();
}
}
}
}
}
function _performFilteredItemsUpdate() {
let newItems = [];
if (SystemTray.items && SystemTray.items.values) {
@@ -87,6 +122,11 @@ Rectangle {
const title = item.tooltipTitle || item.name || item.id || "";
// Skip passive items if hidePassive is enabled
if (root.hidePassive && item.status !== undefined && (item.status === SystemTray.Passive || item.status === 0)) {
continue;
}
// Check if blacklisted
let isBlacklisted = false;
if (root.blacklist && root.blacklist.length > 0) {
@@ -159,7 +199,6 @@ Rectangle {
if (!str || !rule) {
return false;
}
//Logger.d("Tray", "wildCardMatch - Input str:", str, "rule:", rule)
// First, convert '*' to a placeholder to preserve it, then escape other special regex characters
// Use a unique placeholder that won't appear in normal strings
@@ -172,11 +211,9 @@ Rectangle {
// Add ^ and $ to match the entire string
pattern = '^' + pattern + '$';
//Logger.d("Tray", "wildCardMatch - Generated pattern:", pattern)
try {
const regex = new RegExp(pattern, 'i');
// 'i' for case-insensitive
//Logger.d("Tray", "wildCardMatch - Regex test result:", regex.test(str))
return regex.test(str);
} catch (e) {
Logger.w("Tray", "Invalid regex pattern for wildcard match:", rule, e.message);
@@ -211,6 +248,7 @@ Rectangle {
target: SystemTray.items
function onValuesChanged() {
root.updateFilteredItems();
// Repeater will automatically update when items change
}
}
@@ -221,10 +259,14 @@ Rectangle {
}
}
// Watch for hidePassive changes to update filtering immediately
onHidePassiveChanged: {
root.updateFilteredItems();
}
Component.onCompleted: {
root.updateFilteredItems(); // Initial update
}
visible: filteredItems.length > 0 || dropdownItems.length > 0
implicitWidth: isVertical ? Style.capsuleHeight : Math.round(trayFlow.implicitWidth)
implicitHeight: isVertical ? Math.round(trayFlow.implicitHeight) : Style.capsuleHeight
+41 -35
View File
@@ -146,43 +146,49 @@ Loader {
const combined = [];
const processedAppIds = new Set();
// Strategy: Maintain app positions as much as possible
// 1. First pass: Add all running apps (both pinned and non-pinned) in their current order
runningApps.forEach(toplevel => {
if (toplevel && toplevel.appId && !(Settings.data.dock.onlySameOutput && toplevel.screens && !toplevel.screens.includes(modelData))) {
const isPinned = isAppIdPinned(toplevel.appId, pinnedApps);
const appType = isPinned ? "pinned-running" : "running";
//push an app onto combined with the given appType
function pushApp(appType, toplevel, appId, title) {
if (!processedAppIds.has(appId) && !(toplevel && Settings.data.dock.onlySameOutput && toplevel.screens && !toplevel.screens.includes(modelData))) {
combined.push({
"type": appType,
"toplevel": toplevel,
"appId": appId,
"title": title
});
processedAppIds.add(appId);
}
}
// Use desktop entry name if title is "Loading..." or empty
let appTitle = toplevel.title;
if (!appTitle || appTitle === "Loading..." || appTitle.trim() === "") {
appTitle = getAppNameFromDesktopEntry(toplevel.appId);
function pushRunning(first) {
runningApps.forEach(toplevel => {
if (toplevel) {
pushApp((first && pinnedApps.includes(toplevel.appId)) ? "pinned-running" : "running", toplevel, toplevel.appId, toplevel.title);
}
});
}
combined.push({
"type": appType,
"toplevel": toplevel,
"appId": toplevel.appId,
"title": appTitle
});
processedAppIds.add(normalizeAppId(toplevel.appId));
}
});
function pushPinned() {
pinnedApps.forEach(pinnedAppId => {
var toplevel = null;
for (var app of runningApps) {
if (app.appId === pinnedAppId) {
toplevel = app;
}
}
pushApp(toplevel ? "pinned-running" : "pinned", toplevel, pinnedAppId, toplevel ? toplevel.title : pinnedAppId);
});
}
// 2. Second pass: Add non-running pinned apps at the end
pinnedApps.forEach(pinnedAppId => {
const normalizedPinnedId = normalizeAppId(pinnedAppId);
if (!processedAppIds.has(normalizedPinnedId)) {
// Pinned app that is not running - get name from desktop entry
const appName = getAppNameFromDesktopEntry(pinnedAppId);
combined.push({
"type": "pinned",
"toplevel": null,
"appId": pinnedAppId,
"title": appName
});
}
});
//if pinnedStatic then push all pinned and then all remaining running apps
if (Settings.data.dock.pinnedStatic) {
pushPinned();
pushRunning(false);
//else add all running apps and then remaining pinned apps
} else {
pushRunning(true);
pushPinned();
}
dockApps = combined;
}
@@ -455,7 +461,7 @@ Loader {
cache: true
// Dim pinned apps that aren't running
opacity: appButton.isRunning ? 1.0 : 0.6
opacity: appButton.isRunning ? 1.0 : Settings.data.dock.deadOpacity
scale: appButton.hovered ? 1.15 : 1.0
@@ -657,7 +663,7 @@ Loader {
// Active indicator
Rectangle {
visible: isActive
visible: Settings.data.dock.inactiveIndicators ? isRunning : isActive
width: iconSize * 0.2
height: iconSize * 0.1
color: Color.mPrimary
+4 -4
View File
@@ -32,11 +32,11 @@ PopupWindow {
visible: false
// Hidden text element for measuring text width
Text {
NText {
id: textMeasure
visible: false
font.pointSize: Style.fontSizeS
font.family: "Sans Serif" // Match your NText font if different
pointSize: Style.fontSizeS
family: "Sans Serif" // Match your NText font if different
wrapMode: Text.NoWrap
elide: Text.ElideNone
}
@@ -67,7 +67,7 @@ PopupWindow {
}
}
// Apply a reasonable minimum width (like 120px)
menuContentWidth = Math.max(120, maxWidth);
menuContentWidth = Math.max(120, Math.ceil(maxWidth));
}
function initItems() {
+2 -2
View File
@@ -33,8 +33,8 @@ PanelWindow {
readonly property string barPosition: Settings.data.bar.position || "top"
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
readonly property bool barFloating: Settings.data.bar.floating || false
readonly property real barMarginH: Math.round(barFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0)
readonly property real barMarginV: Math.round(barFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0)
readonly property real barMarginH: Math.ceil(barFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0)
readonly property real barMarginV: Math.ceil(barFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0)
// Anchor to the bar's edge
anchors {
+6 -6
View File
@@ -17,8 +17,8 @@ PanelWindow {
readonly property string barPosition: Settings.data.bar.position || "top"
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
readonly property bool barFloating: Settings.data.bar.floating || false
readonly property real barMarginH: barFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
readonly property real barMarginV: barFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0
readonly property real barMarginH: barFloating ? Math.ceil(Settings.data.bar.marginHorizontal * Style.marginXL) : 0
readonly property real barMarginV: barFloating ? Math.ceil(Settings.data.bar.marginVertical * Style.marginXL) : 0
// Invisible - just reserves space
color: "transparent"
@@ -45,9 +45,9 @@ PanelWindow {
// Vertical bar: reserve bar height + margin on the anchored edge only
if (barFloating) {
// For left bar, reserve left margin; for right bar, reserve right margin
return Style.barHeight + barMarginH;
return Style.barHeight + barMarginH + 1;
}
return Style.barHeight;
return Style.barHeight + 1;
}
return 0; // Auto-width when left/right anchors are true
}
@@ -57,9 +57,9 @@ PanelWindow {
// Horizontal bar: reserve bar height + margin on the anchored edge only
if (barFloating) {
// For top bar, reserve top margin; for bottom bar, reserve bottom margin
return Style.barHeight + barMarginV;
return Style.barHeight + barMarginV + 1;
}
return Style.barHeight;
return Style.barHeight + 1;
}
return 0; // Auto-height when top/bottom anchors are true
}
+35 -102
View File
@@ -325,8 +325,8 @@ PanelWindow {
readonly property string barPosition: Settings.data.bar.position || "top"
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
readonly property bool barFloating: Settings.data.bar.floating || false
readonly property real barMarginH: barFloating ? Math.round(Settings.data.bar.marginHorizontal * Style.marginXL) : 0
readonly property real barMarginV: barFloating ? Math.round(Settings.data.bar.marginVertical * Style.marginXL) : 0
readonly property real barMarginH: barFloating ? Math.ceil(Settings.data.bar.marginHorizontal * Style.marginXL) : 0
readonly property real barMarginV: barFloating ? Math.ceil(Settings.data.bar.marginVertical * Style.marginXL) : 0
readonly property real attachmentOverlap: 1 // Attachment overlap to fix hairline gap with fractional scaling
// Expose bar dimensions directly on this Item for BarBackground
@@ -419,167 +419,100 @@ PanelWindow {
// ========================================
// These shortcuts delegate to the opened panel's handler functions
// Panels can implement: onEscapePressed, onTabPressed, onBackTabPressed,
// onUpPressed, onDownPressed, onReturnPressed
// onUpPressed, onDownPressed, onReturnPressed, etc...
Shortcut {
sequence: "Escape"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onEscapePressed) {
PanelService.openedPanel.onEscapePressed();
} else if (PanelService.openedPanel) {
PanelService.openedPanel.close();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onEscapePressed !== undefined)
onActivated: PanelService.openedPanel.onEscapePressed()
}
Shortcut {
sequence: "Tab"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onTabPressed) {
PanelService.openedPanel.onTabPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onTabPressed !== undefined)
onActivated: PanelService.openedPanel.onTabPressed()
}
Shortcut {
sequence: "Backtab"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onBackTabPressed) {
PanelService.openedPanel.onBackTabPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onBackTabPressed !== undefined)
onActivated: PanelService.openedPanel.onBackTabPressed()
}
Shortcut {
sequence: "Up"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onUpPressed) {
PanelService.openedPanel.onUpPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onUpPressed !== undefined)
onActivated: PanelService.openedPanel.onUpPressed()
}
Shortcut {
sequence: "Down"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onDownPressed) {
PanelService.openedPanel.onDownPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onDownPressed !== undefined)
onActivated: PanelService.openedPanel.onDownPressed()
}
Shortcut {
sequence: "Return"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onReturnPressed) {
PanelService.openedPanel.onReturnPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onReturnPressed !== undefined)
onActivated: PanelService.openedPanel.onReturnPressed()
}
Shortcut {
sequence: "Left"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onLeftPressed) {
PanelService.openedPanel.onLeftPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onLeftPressed !== undefined)
onActivated: PanelService.openedPanel.onLeftPressed()
}
Shortcut {
sequence: "Right"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onRightPressed) {
PanelService.openedPanel.onRightPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onRightPressed !== undefined)
onActivated: PanelService.openedPanel.onRightPressed()
}
Shortcut {
sequence: "Home"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onHomePressed) {
PanelService.openedPanel.onHomePressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onHomePressed !== undefined)
onActivated: PanelService.openedPanel.onHomePressed()
}
Shortcut {
sequence: "End"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onEndPressed) {
PanelService.openedPanel.onEndPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onEndPressed !== undefined)
onActivated: PanelService.openedPanel.onEndPressed()
}
Shortcut {
sequence: "PgUp"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onPageUpPressed) {
PanelService.openedPanel.onPageUpPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onPageUpPressed !== undefined)
onActivated: PanelService.openedPanel.onPageUpPressed()
}
Shortcut {
sequence: "PgDown"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onPageDownPressed) {
PanelService.openedPanel.onPageDownPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onPageDownPressed !== undefined)
onActivated: PanelService.openedPanel.onPageDownPressed()
}
Shortcut {
sequence: "Ctrl+J"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onCtrlJPressed) {
PanelService.openedPanel.onCtrlJPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onCtrlJPressed !== undefined)
onActivated: PanelService.openedPanel.onCtrlJPressed()
}
Shortcut {
sequence: "Ctrl+K"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onCtrlKPressed) {
PanelService.openedPanel.onCtrlKPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onCtrlKPressed !== undefined)
onActivated: PanelService.openedPanel.onCtrlKPressed()
}
Shortcut {
sequence: "Ctrl+N"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onCtrlNPressed) {
PanelService.openedPanel.onCtrlNPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onCtrlNPressed !== undefined)
onActivated: PanelService.openedPanel.onCtrlNPressed()
}
Shortcut {
sequence: "Ctrl+P"
enabled: root.isPanelOpen
onActivated: {
if (PanelService.openedPanel && PanelService.openedPanel.onCtrlPPressed) {
PanelService.openedPanel.onCtrlPPressed();
}
}
enabled: root.isPanelOpen && (PanelService.openedPanel.onCtrlPPressed !== undefined)
onActivated: PanelService.openedPanel.onCtrlPPressed()
}
}
+106 -78
View File
@@ -63,43 +63,27 @@ Item {
property bool closeWatchdogActive: false
property bool openWatchdogActive: false
// Cached animation direction - set when panel opens, doesn't change during animation
// These are computed once when opening and used for the entire open/close cycle
property bool cachedAnimateFromTop: false
property bool cachedAnimateFromBottom: false
property bool cachedAnimateFromLeft: false
property bool cachedAnimateFromRight: false
property bool cachedShouldAnimateWidth: false
property bool cachedShouldAnimateHeight: false
// Close with escape key
property bool closeWithEscape: true
property bool exclusiveKeyboard: true
// Keyboard event handlers - override these in specific panels to handle shortcuts
// Keyboard event handler
// These are called from MainScreen's centralized shortcuts
// override these in specific panels to handle shortcuts
function onEscapePressed() {
if (closeWithEscape)
close();
}
function onTabPressed() {
}
function onBackTabPressed() {
}
function onUpPressed() {
}
function onDownPressed() {
}
function onLeftPressed() {
}
function onRightPressed() {
}
function onReturnPressed() {
}
function onHomePressed() {
}
function onEndPressed() {
}
function onPageUpPressed() {
}
function onPageDownPressed() {
}
function onCtrlJPressed() {
}
function onCtrlKPressed() {
}
// Expose panel region for background rendering
readonly property var panelRegion: panelContent.geometryPlaceholder
@@ -107,8 +91,8 @@ Item {
readonly property string barPosition: Settings.data.bar.position
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
readonly property bool barFloating: Settings.data.bar.floating
readonly property real barMarginH: barFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
readonly property real barMarginV: barFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0
readonly property real barMarginH: barFloating ? Math.ceil(Settings.data.bar.marginHorizontal * Style.marginXL) : 0
readonly property real barMarginV: barFloating ? Math.ceil(Settings.data.bar.marginVertical * Style.marginXL) : 0
// Check if bar should be visible on this screen
readonly property bool barShouldShow: {
@@ -124,14 +108,14 @@ Item {
readonly property bool hasExplicitVerticalAnchor: panelAnchorVerticalCenter || panelAnchorTop || panelAnchorBottom
// Effective anchor properties (depend on allowAttach)
// These are true when:
// 1. Explicitly anchored, OR
// These are true when allowAttach is enabled AND:
// 1. Explicitly anchored to that edge, OR
// 2. Using button position and bar is on that edge, OR
// 3. Attached to bar with no explicit anchors (default centering behavior)
readonly property bool effectivePanelAnchorTop: panelAnchorTop || (useButtonPosition && barPosition === "top") || (panelContent.allowAttach && !hasExplicitVerticalAnchor && barPosition === "top" && !barIsVertical)
readonly property bool effectivePanelAnchorBottom: panelAnchorBottom || (useButtonPosition && barPosition === "bottom") || (panelContent.allowAttach && !hasExplicitVerticalAnchor && barPosition === "bottom" && !barIsVertical)
readonly property bool effectivePanelAnchorLeft: panelAnchorLeft || (useButtonPosition && barPosition === "left") || (panelContent.allowAttach && !hasExplicitHorizontalAnchor && barPosition === "left" && barIsVertical)
readonly property bool effectivePanelAnchorRight: panelAnchorRight || (useButtonPosition && barPosition === "right") || (panelContent.allowAttach && !hasExplicitHorizontalAnchor && barPosition === "right" && barIsVertical)
// 3. No explicit anchors and bar is on that edge (default centering behavior)
readonly property bool effectivePanelAnchorTop: panelContent.allowAttach && (panelAnchorTop || (useButtonPosition && barPosition === "top") || (!hasExplicitVerticalAnchor && barPosition === "top" && !barIsVertical))
readonly property bool effectivePanelAnchorBottom: panelContent.allowAttach && (panelAnchorBottom || (useButtonPosition && barPosition === "bottom") || (!hasExplicitVerticalAnchor && barPosition === "bottom" && !barIsVertical))
readonly property bool effectivePanelAnchorLeft: panelContent.allowAttach && (panelAnchorLeft || (useButtonPosition && barPosition === "left") || (!hasExplicitHorizontalAnchor && barPosition === "left" && barIsVertical))
readonly property bool effectivePanelAnchorRight: panelContent.allowAttach && (panelAnchorRight || (useButtonPosition && barPosition === "right") || (!hasExplicitHorizontalAnchor && barPosition === "right" && barIsVertical))
signal opened
signal closed
@@ -347,36 +331,44 @@ Item {
} else {
calculatedX = (root.width - panelWidth) / 2;
}
} else if (root.effectivePanelAnchorRight) {
if (panelContent.allowAttach && root.barIsVertical && root.barPosition === "right") {
var rightBarEdge = root.width - root.barMarginH - Style.barHeight;
calculatedX = rightBarEdge - panelWidth;
} else if (panelContent.allowAttach) {
// Account for corner inset when bar is floating, horizontal, AND panel is on same edge as bar
var panelOnSameEdgeAsBar = (root.barPosition === "top" && root.effectivePanelAnchorTop) || (root.barPosition === "bottom" && root.effectivePanelAnchorBottom);
if (!root.barIsVertical && root.barFloating && panelOnSameEdgeAsBar) {
var rightCornerInset = Style.radiusL * 2;
calculatedX = root.width - root.barMarginH - rightCornerInset - panelWidth;
} else if (root.panelAnchorRight) {
// Use raw panelAnchorRight for positioning decision
if (root.effectivePanelAnchorRight) {
// Attached: snap to edge/bar
if (root.barIsVertical && root.barPosition === "right") {
var rightBarEdge = root.width - root.barMarginH - Style.barHeight;
calculatedX = rightBarEdge - panelWidth;
} else {
calculatedX = root.width - panelWidth;
var panelOnSameEdgeAsBar = (root.barPosition === "top" && root.effectivePanelAnchorTop) || (root.barPosition === "bottom" && root.effectivePanelAnchorBottom);
if (!root.barIsVertical && root.barFloating && panelOnSameEdgeAsBar) {
var rightCornerInset = Style.radiusL * 2;
calculatedX = root.width - root.barMarginH - rightCornerInset - panelWidth;
} else {
calculatedX = root.width - panelWidth;
}
}
} else {
// Not attached: position at right with margin
calculatedX = root.width - panelWidth - Style.marginL;
}
} else if (root.effectivePanelAnchorLeft) {
if (panelContent.allowAttach && root.barIsVertical && root.barPosition === "left") {
var leftBarEdge = root.barMarginH + Style.barHeight;
calculatedX = leftBarEdge;
} else if (panelContent.allowAttach) {
// Account for corner inset when bar is floating, horizontal, AND panel is on same edge as bar
var panelOnSameEdgeAsBar = (root.barPosition === "top" && root.effectivePanelAnchorTop) || (root.barPosition === "bottom" && root.effectivePanelAnchorBottom);
if (!root.barIsVertical && root.barFloating && panelOnSameEdgeAsBar) {
var leftCornerInset = Style.radiusL * 2;
calculatedX = root.barMarginH + leftCornerInset;
} else if (root.panelAnchorLeft) {
// Use raw panelAnchorLeft for positioning decision
if (root.effectivePanelAnchorLeft) {
// Attached: snap to edge/bar
if (root.barIsVertical && root.barPosition === "left") {
var leftBarEdge = root.barMarginH + Style.barHeight;
calculatedX = leftBarEdge;
} else {
calculatedX = 0;
var panelOnSameEdgeAsBar = (root.barPosition === "top" && root.effectivePanelAnchorTop) || (root.barPosition === "bottom" && root.effectivePanelAnchorBottom);
if (!root.barIsVertical && root.barFloating && panelOnSameEdgeAsBar) {
var leftCornerInset = Style.radiusL * 2;
calculatedX = root.barMarginH + leftCornerInset;
} else {
calculatedX = 0;
}
}
} else {
// Not attached: position at left with margin
calculatedX = Style.marginL;
}
} else {
@@ -496,17 +488,23 @@ Item {
} else {
calculatedY = (root.height - panelHeight) / 2;
}
} else if (root.effectivePanelAnchorTop) {
if (panelContent.allowAttach) {
calculatedY = 0;
} else if (root.panelAnchorTop) {
// Use raw panelAnchorTop for positioning decision
if (root.effectivePanelAnchorTop) {
// Attached: snap to edge/bar
calculatedY = root.barPosition === "top" ? root.barMarginV + Style.barHeight : 0;
} else {
// Not attached: position at top with margin
var topBarOffset = (root.barPosition === "top") ? barOffset : 0;
calculatedY = topBarOffset + Style.marginL;
}
} else if (root.effectivePanelAnchorBottom) {
if (panelContent.allowAttach) {
calculatedY = root.height - panelHeight;
} else if (root.panelAnchorBottom) {
// Use raw panelAnchorBottom for positioning decision
if (root.effectivePanelAnchorBottom) {
// Attached: snap to edge/bar
calculatedY = root.barPosition === "bottom" ? root.height - root.barMarginV - Style.barHeight - panelHeight : root.height - panelHeight;
} else {
// Not attached: position at bottom with margin
var bottomBarOffset = (root.barPosition === "bottom") ? barOffset : 0;
calculatedY = root.height - panelHeight - bottomBarOffset - Style.marginL;
}
@@ -794,10 +792,20 @@ Item {
return true;
}
// Attached to vertical bar (left/right) - don't animate from top
if (panelContent.allowAttachToBar && root.barIsVertical && (root.effectivePanelAnchorLeft || root.effectivePanelAnchorRight)) {
// Only if panel is on the SAME side as the bar
var attachedToVerticalBar = panelContent.allowAttachToBar && root.barIsVertical && ((root.effectivePanelAnchorLeft && root.barPosition === "left") || (root.effectivePanelAnchorRight && root.barPosition === "right"));
if (attachedToVerticalBar) {
return false;
}
// Default: animate from top
// Panel anchored to left/right edge - animate from that edge instead
if (root.panelAnchorLeft || root.panelAnchorRight) {
return false;
}
// Attached to top edge
if (panelContent.allowAttach && root.panelAnchorTop) {
return true;
}
// Default: animate from top (for floating panels)
return true;
}
// Panel is visible - use calculated positions
@@ -829,7 +837,13 @@ Item {
}
readonly property bool animateFromLeft: {
if (!root.isPanelVisible) {
if (panelContent.allowAttachToBar && root.effectivePanelAnchorLeft && root.barIsVertical) {
// Attached to vertical bar on left - must verify bar is actually on left
if (panelContent.allowAttachToBar && root.effectivePanelAnchorLeft && root.barIsVertical && root.barPosition === "left") {
return true;
}
// Panel anchored to left edge - animate from left
// Takes precedence over top/bottom when bar is vertical
if (root.panelAnchorLeft) {
return true;
}
return false;
@@ -850,7 +864,13 @@ Item {
}
readonly property bool animateFromRight: {
if (!root.isPanelVisible) {
if (panelContent.allowAttachToBar && root.effectivePanelAnchorRight && root.barIsVertical) {
// Attached to vertical bar on right - must verify bar is actually on right
if (panelContent.allowAttachToBar && root.effectivePanelAnchorRight && root.barIsVertical && root.barPosition === "right") {
return true;
}
// Panel anchored to right edge - animate from right
// Takes precedence over top/bottom when bar is vertical
if (root.panelAnchorRight) {
return true;
}
return false;
@@ -873,6 +893,7 @@ Item {
// Determine animation axis based on which edge is closest
// Priority: horizontal edges (top/bottom) take precedence over vertical edges (left/right)
// This prevents diagonal animations when panel is attached to a corner
// Use reactive values here - they're evaluated BEFORE isPanelVisible becomes true
readonly property bool shouldAnimateWidth: !shouldAnimateHeight && (animateFromLeft || animateFromRight)
readonly property bool shouldAnimateHeight: animateFromTop || animateFromBottom
@@ -901,23 +922,21 @@ Item {
x: {
// Offset x to make panel grow/shrink from the appropriate edge
if (animateFromRight) {
// Use CACHED values to prevent recalculation during animation
if (root.cachedAnimateFromRight && root.cachedShouldAnimateWidth) {
// Keep the RIGHT edge fixed at its target position
if (isPanelVisible || isClosing) {
var targetRightEdge = targetX + targetWidth;
return targetRightEdge - width;
}
var targetRightEdge = targetX + targetWidth;
return targetRightEdge - width;
}
return targetX;
}
y: {
// Offset y to make panel grow/shrink from the appropriate edge
if (animateFromBottom) {
// Use CACHED values to prevent recalculation during animation
if (root.cachedAnimateFromBottom && root.cachedShouldAnimateHeight) {
// Keep the BOTTOM edge fixed at its target position
if (isPanelVisible || isClosing) {
var targetBottomEdge = targetY + targetHeight;
return targetBottomEdge - height;
}
var targetBottomEdge = targetY + targetHeight;
return targetBottomEdge - height;
}
return targetY;
}
@@ -1158,6 +1177,15 @@ Item {
// Mark dimensions as initialized to enable animations
panelBackground.dimensionsInitialized = true;
// Cache animation direction BEFORE isPanelVisible becomes true
// This locks in the direction for the entire open/close cycle
root.cachedAnimateFromTop = panelBackground.animateFromTop;
root.cachedAnimateFromBottom = panelBackground.animateFromBottom;
root.cachedAnimateFromLeft = panelBackground.animateFromLeft;
root.cachedAnimateFromRight = panelBackground.animateFromRight;
root.cachedShouldAnimateWidth = panelBackground.shouldAnimateWidth;
root.cachedShouldAnimateHeight = panelBackground.shouldAnimateHeight;
// Make panel visible, now only the intended dimension will animate
root.isPanelVisible = true;
opacityTrigger.start();
+4 -4
View File
@@ -67,28 +67,28 @@ Variants {
readonly property int barOffsetTop: {
if (barPos !== "top")
return 0;
const floatMarginV = isFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0;
const floatMarginV = isFloating ? Math.ceil(Settings.data.bar.marginVertical * Style.marginXL) : 0;
return Style.barHeight + floatMarginV;
}
readonly property int barOffsetBottom: {
if (barPos !== "bottom")
return 0;
const floatMarginV = isFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0;
const floatMarginV = isFloating ? Math.ceil(Settings.data.bar.marginVertical * Style.marginXL) : 0;
return Style.barHeight + floatMarginV;
}
readonly property int barOffsetLeft: {
if (barPos !== "left")
return 0;
const floatMarginH = isFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0;
const floatMarginH = isFloating ? Math.ceil(Settings.data.bar.marginHorizontal * Style.marginXL) : 0;
return Style.barHeight + floatMarginH;
}
readonly property int barOffsetRight: {
if (barPos !== "right")
return 0;
const floatMarginH = isFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0;
const floatMarginH = isFloating ? Math.ceil(Settings.data.bar.marginHorizontal * Style.marginXL) : 0;
return Style.barHeight + floatMarginH;
}
+1 -1
View File
@@ -419,7 +419,7 @@ Variants {
let base = Style.marginM;
if (Settings.data.bar.position === position) {
const isVertical = position === "top" || position === "bottom";
const floatExtra = Settings.data.bar.floating ? (isVertical ? Settings.data.bar.marginVertical : Settings.data.bar.marginHorizontal) * Style.marginXL : 0;
const floatExtra = Math.ceil(Settings.data.bar.floating ? (isVertical ? Settings.data.bar.marginVertical : Settings.data.bar.marginHorizontal) * Style.marginXL : 0);
return Style.barHeight + base + floatExtra;
}
return base;
+29 -10
View File
@@ -22,6 +22,19 @@ SmartPanel {
preferredWidth: Math.round(420 * Style.uiScaleRatio)
preferredHeight: Math.round(420 * Style.uiScaleRatio)
Component.onCompleted: {
var vol = AudioService.volume;
localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
var inputVol = AudioService.inputVolume;
localInputVolume = (inputVol !== undefined && !isNaN(inputVol)) ? inputVol : 0;
if (AudioService.sink) {
lastSinkId = AudioService.sink.id;
}
if (AudioService.source) {
lastSourceId = AudioService.source.id;
}
}
// Reset local volume when device changes - use current device's volume
Connections {
target: AudioService
@@ -31,7 +44,8 @@ SmartPanel {
if (newSinkId !== lastSinkId) {
lastSinkId = newSinkId;
// Immediately set local volume to current device's volume
localOutputVolume = AudioService.volume;
var vol = AudioService.volume;
localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
}
} else {
lastSinkId = -1;
@@ -48,7 +62,8 @@ SmartPanel {
if (newSourceId !== lastSourceId) {
lastSourceId = newSourceId;
// Immediately set local volume to current device's volume
localInputVolume = AudioService.inputVolume;
var vol = AudioService.inputVolume;
localInputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
}
} else {
lastSourceId = -1;
@@ -62,7 +77,8 @@ SmartPanel {
target: AudioService
function onVolumeChanged() {
if (!localOutputVolumeChanging && AudioService.sink && AudioService.sink.id === lastSinkId) {
localOutputVolume = AudioService.volume;
var vol = AudioService.volume;
localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
}
}
}
@@ -71,7 +87,8 @@ SmartPanel {
target: AudioService.sink?.audio ? AudioService.sink?.audio : null
function onVolumeChanged() {
if (!localOutputVolumeChanging && AudioService.sink && AudioService.sink.id === lastSinkId) {
localOutputVolume = AudioService.volume;
var vol = AudioService.volume;
localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
}
}
}
@@ -80,7 +97,8 @@ SmartPanel {
target: AudioService
function onInputVolumeChanged() {
if (!localInputVolumeChanging && AudioService.source && AudioService.source.id === lastSourceId) {
localInputVolume = AudioService.inputVolume;
var vol = AudioService.inputVolume;
localInputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
}
}
}
@@ -89,7 +107,8 @@ SmartPanel {
target: AudioService.source?.audio ? AudioService.source?.audio : null
function onVolumeChanged() {
if (!localInputVolumeChanging && AudioService.source && AudioService.source.id === lastSourceId) {
localInputVolume = AudioService.inputVolume;
var vol = AudioService.inputVolume;
localInputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
}
}
}
@@ -228,8 +247,8 @@ SmartPanel {
value: localOutputVolume
stepSize: 0.01
heightRatio: 0.5
onMoved: value => localOutputVolume = value
onPressedChanged: (pressed, value) => localOutputVolumeChanging = pressed
onMoved: localOutputVolume = value
onPressedChanged: localOutputVolumeChanging = pressed
text: Math.round(localOutputVolume * 100) + "%"
Layout.bottomMargin: Style.marginM
}
@@ -285,8 +304,8 @@ SmartPanel {
value: localInputVolume
stepSize: 0.01
heightRatio: 0.5
onMoved: value => localInputVolume = value
onPressedChanged: (pressed, value) => localInputVolumeChanging = pressed
onMoved: localInputVolume = value
onPressedChanged: localInputVolumeChanging = pressed
text: Math.round(localInputVolume * 100) + "%"
Layout.bottomMargin: Style.marginM
}
+14 -4
View File
@@ -68,7 +68,7 @@ SmartPanel {
}
// Target columns, but actual columns may vary based on available width
// Account for NTabBar margins (Style.marginXS on each side) to match category tabs width
// Account for NTabBar margins to match category tabs width
readonly property int targetGridColumns: 5
readonly property int gridContentWidth: listPanelWidth - (2 * Style.marginXS)
readonly property int gridCellSize: Math.floor((gridContentWidth - ((targetGridColumns - 1) * Style.marginS)) / targetGridColumns)
@@ -87,7 +87,7 @@ SmartPanel {
var currentIndex = emojiPlugin.categories.indexOf(emojiPlugin.selectedCategory);
var nextIndex = (currentIndex + 1) % emojiPlugin.categories.length;
emojiPlugin.selectCategory(emojiPlugin.categories[nextIndex]);
} else if ((activePlugin === null || activePlugin === appsPlugin) && appsPlugin.isBrowsingMode && !root.searchText.startsWith(">")) {
} else if ((activePlugin === null || activePlugin === appsPlugin) && appsPlugin.isBrowsingMode && !root.searchText.startsWith(">") && Settings.data.appLauncher.showCategories) {
// In apps browsing mode (no search), Tab navigates between categories
var availableCategories = appsPlugin.availableCategories || ["all"];
var currentIndex = availableCategories.indexOf(appsPlugin.selectedCategory);
@@ -103,7 +103,7 @@ SmartPanel {
var currentIndex = emojiPlugin.categories.indexOf(emojiPlugin.selectedCategory);
var previousIndex = ((currentIndex - 1) % emojiPlugin.categories.length + emojiPlugin.categories.length) % emojiPlugin.categories.length;
emojiPlugin.selectCategory(emojiPlugin.categories[previousIndex]);
} else if ((activePlugin === null || activePlugin === appsPlugin) && appsPlugin.isBrowsingMode && !root.searchText.startsWith(">")) {
} else if ((activePlugin === null || activePlugin === appsPlugin) && appsPlugin.isBrowsingMode && !root.searchText.startsWith(">") && Settings.data.appLauncher.showCategories) {
var availableCategories = appsPlugin.availableCategories || ["all"];
var currentIndex = availableCategories.indexOf(appsPlugin.selectedCategory);
var previousIndex = ((currentIndex - 1) % availableCategories.length + availableCategories.length) % availableCategories.length;
@@ -320,6 +320,14 @@ SmartPanel {
}
}
CommandPlugin {
id: cmdPlugin
Component.onCompleted: {
registerPlugin(this);
Logger.d("Launcher", "Registered: CommandPlugin");
}
}
EmojiPlugin {
id: emojiPlugin
Component.onCompleted: {
@@ -648,6 +656,7 @@ SmartPanel {
id: emojiCategoryTabs
visible: root.activePlugin === emojiPlugin && emojiPlugin.isBrowsingMode
Layout.fillWidth: true
margins: Style.marginM
property int computedCurrentIndex: {
if (visible && emojiPlugin.categories) {
return emojiPlugin.categories.indexOf(emojiPlugin.selectedCategory);
@@ -690,8 +699,9 @@ SmartPanel {
// App category tabs (shown when browsing apps without search)
NTabBar {
id: appCategoryTabs
visible: (root.activePlugin === null || root.activePlugin === appsPlugin) && appsPlugin.isBrowsingMode && !root.searchText.startsWith(">")
visible: (root.activePlugin === null || root.activePlugin === appsPlugin) && appsPlugin.isBrowsingMode && !root.searchText.startsWith(">") && Settings.data.appLauncher.showCategories
Layout.fillWidth: true
margins: Style.marginM
property int computedCurrentIndex: {
if (visible && appsPlugin.availableCategories) {
return appsPlugin.availableCategories.indexOf(appsPlugin.selectedCategory);
@@ -15,11 +15,12 @@ Item {
// Category support
property string selectedCategory: "all"
property bool isBrowsingMode: false
property var categories: ["all", "AudioVideo", "Chat", "Development", "Education", "Game", "Graphics", "Network", "Office", "System", "Misc", "WebBrowser"]
property var categories: ["all", "Pinned", "AudioVideo", "Chat", "Development", "Education", "Game", "Graphics", "Network", "Office", "System", "Misc", "WebBrowser"]
property var availableCategories: ["all"] // Reactive property for available categories
property var categoryIcons: ({
"all": "apps",
"Pinned": "pin",
"AudioVideo": "music",
"Chat": "message-circle",
"Development": "code",
@@ -38,6 +39,7 @@ Item {
function getCategoryName(category) {
const names = {
"all": I18n.tr("launcher.categories.all"),
"Pinned": I18n.tr("launcher.categories.pinned"),
"AudioVideo": I18n.tr("launcher.categories.audiovideo"),
"Chat": I18n.tr("launcher.categories.chat"),
"Development": I18n.tr("launcher.categories.development"),
@@ -200,11 +202,33 @@ Item {
return "Misc";
}
// Helper function to normalize app IDs for case-insensitive matching
function normalizeAppId(appId) {
if (!appId || typeof appId !== 'string')
return "";
return appId.toLowerCase().trim();
}
// Helper function to check if an app is pinned
function isAppPinned(app) {
if (!app)
return false;
const pinnedApps = Settings.data.dock.pinnedApps || [];
const appId = getAppKey(app);
const normalizedId = normalizeAppId(appId);
return pinnedApps.some(pinnedId => normalizeAppId(pinnedId) === normalizedId);
}
function appMatchesCategory(app, category) {
// Check if app matches the selected category
if (category === "all")
return true;
// Handle Pinned category separately
if (category === "Pinned") {
return isAppPinned(app);
}
// Get the primary category for this app (first matching standard category)
const primaryCategory = getAppCategory(app);
@@ -241,6 +265,19 @@ Item {
let hasAudioVideo = false;
let hasEducation = false;
let hasSystem = false;
let hasPinned = false;
// Check if there are any pinned apps
const pinnedApps = Settings.data.dock.pinnedApps || [];
if (pinnedApps.length > 0) {
// Verify that at least one pinned app exists in entries
for (let app of entries) {
if (isAppPinned(app)) {
hasPinned = true;
break;
}
}
}
for (let app of entries) {
const appCategories = getAppCategories(app);
@@ -257,6 +294,13 @@ Item {
}
}
const result = ["all"];
// Add Pinned category first if there are pinned apps
if (hasPinned) {
result.push("Pinned");
}
if (hasAudioVideo) {
categorySet.add("AudioVideo");
}
@@ -267,9 +311,8 @@ Item {
categorySet.add("System");
}
const result = ["all"];
for (let cat of root.categories) {
if (cat !== "all" && cat !== "Misc" && categorySet.has(cat)) {
if (cat !== "all" && cat !== "Pinned" && cat !== "Misc" && categorySet.has(cat)) {
result.push(cat);
}
}
@@ -308,6 +351,27 @@ Item {
availableCategories = getAvailableCategories();
}
Connections {
target: Settings.data.dock
function onPinnedAppsChanged() {
const wasViewingPinned = selectedCategory === "Pinned";
updateAvailableCategories();
// If we were viewing Pinned category and it's no longer available, switch to "all"
if (wasViewingPinned && !availableCategories.includes("Pinned")) {
selectedCategory = "all";
}
// Update results if we're currently viewing the Pinned category
if (selectedCategory === "Pinned" && launcher) {
launcher.updateResults();
} else if (wasViewingPinned && selectedCategory === "all" && launcher) {
// Also update results when switching to "all"
launcher.updateResults();
}
}
}
function getExecutableName(app) {
if (!app)
return "";
@@ -0,0 +1,45 @@
import QtQuick
import Quickshell
import qs.Commons
Item {
property var launcher: null
property string name: I18n.tr("plugins.command")
function handleCommand(query) {
return query.startsWith(">cmd");
}
function commands() {
return [
{
"name": ">cmd",
"description": I18n.tr("plugins.command-description"),
"icon": "utilities-terminal",
"isImage": false,
"onActivate": function () {
launcher.setSearchText(">cmd ");
}
}
];
}
function getResults(query) {
if (!query.startsWith(">cmd"))
return [];
let expression = query.substring(4).trim();
return [
{
"name": I18n.tr("plugins.command-name"),
"description": I18n.tr("plugins.command-description"),
"icon": "utilities-terminal",
"isImage": false,
"onActivate": function () {
launcher.close();
Quickshell.execDetached(["sh", "-c", expression]);
}
}
];
}
}
@@ -123,6 +123,38 @@ SmartPanel {
id: notificationRect
color: Color.transparent
// Calculate content height based on header + tabs (if visible) + content
property real headerHeight: headerBox.implicitHeight
property real tabsHeight: tabsBox.visible ? tabsBox.implicitHeight + Style.marginS : 0
property real contentHeight: {
if (NotificationService.historyList.count === 0) {
return emptyState.implicitHeight;
}
// Calculate actual height of visible notifications
var totalHeight = 0;
var count = NotificationService.historyList.count;
var visibleCount = 0;
for (var i = 0; i < count; i++) {
var item = NotificationService.historyList.get(i);
if (item && root.isInCurrentRange(item.timestamp)) {
visibleCount++;
}
}
// Estimate: each notification is roughly 100-150px, use conservative estimate
var avgNotificationHeight = 120 * Style.uiScaleRatio;
totalHeight = visibleCount * avgNotificationHeight + (visibleCount - 1) * Style.marginM;
return totalHeight;
}
property real calculatedHeight: headerHeight + tabsHeight + contentHeight + (Style.marginL * 2) + (Style.marginM * 2)
property real contentPreferredHeight: {
if (NotificationService.historyList.count === 0) {
// Empty state: smaller height
return Math.min(root.preferredHeight, 280 * Style.uiScaleRatio);
}
// Clamp between minimum (280) and maximum (540)
return Math.max(280 * Style.uiScaleRatio, Math.min(root.preferredHeight, calculatedHeight));
}
ColumnLayout {
id: mainColumn
anchors.fill: parent
@@ -131,6 +163,7 @@ SmartPanel {
// Header section
NBox {
id: headerBox
Layout.fillWidth: true
implicitHeight: headerRow.implicitHeight + (Style.marginM * 2)
@@ -183,6 +216,7 @@ SmartPanel {
// Time range tabs ([All] / [Today] / [Yesterday] / [Earlier])
NBox {
id: tabsBox
Layout.fillWidth: true
Layout.topMargin: Style.marginS
implicitHeight: timeTabs.implicitHeight + (Style.marginS * 2)
@@ -237,6 +271,7 @@ SmartPanel {
// Empty state when no notifications
ColumnLayout {
id: emptyState
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter
@@ -276,201 +311,205 @@ SmartPanel {
}
}
// Notification list
NScrollView {
id: scrollView
// Notification list container with gradient overlay
Item {
Layout.fillWidth: true
Layout.fillHeight: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
clip: true
visible: NotificationService.historyList.count > 0
// Track which notification is expanded
property string expandedId: ""
NScrollView {
id: scrollView
anchors.fill: parent
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
clip: true
contentWidth: availableWidth
// Track which notification is expanded
property string expandedId: ""
Column {
width: scrollView.width
spacing: Style.marginM
contentWidth: availableWidth
Repeater {
model: NotificationService.historyList
Column {
width: scrollView.width
spacing: Style.marginM
delegate: Item {
id: notificationDelegate
width: parent.width
visible: root.isInCurrentRange(model.timestamp)
height: visible ? contentColumn.height + (Style.marginM * 2) : 0
Repeater {
model: NotificationService.historyList
property string notificationId: model.id
property bool isExpanded: scrollView.expandedId === notificationId
property bool canExpand: summaryText.truncated || bodyText.truncated
delegate: Item {
id: notificationDelegate
width: parent.width
visible: root.isInCurrentRange(model.timestamp)
height: visible ? contentColumn.height + (Style.marginM * 2) : 0
Rectangle {
anchors.fill: parent
radius: Style.radiusM
color: Color.mSurfaceVariant
border.color: Qt.alpha(Color.mOutline, Style.opacityMedium)
border.width: Style.borderS
property string notificationId: model.id
property bool isExpanded: scrollView.expandedId === notificationId
property bool canExpand: summaryText.truncated || bodyText.truncated
Behavior on color {
enabled: !Settings.data.general.animationDisabled
ColorAnimation {
duration: Style.animationFast
Rectangle {
anchors.fill: parent
radius: Style.radiusM
color: Color.mSurfaceVariant
border.color: Qt.alpha(Color.mOutline, Style.opacityMedium)
border.width: Style.borderS
Behavior on color {
enabled: !Settings.data.general.animationDisabled
ColorAnimation {
duration: Style.animationFast
}
}
}
}
// Click to expand/collapse
MouseArea {
anchors.fill: parent
anchors.rightMargin: Style.baseWidgetSize
enabled: notificationDelegate.canExpand
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (scrollView.expandedId === notificationId) {
scrollView.expandedId = "";
} else {
scrollView.expandedId = notificationId;
// Click to expand/collapse
MouseArea {
anchors.fill: parent
anchors.rightMargin: Style.baseWidgetSize
enabled: notificationDelegate.canExpand
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
onClicked: {
if (scrollView.expandedId === notificationId) {
scrollView.expandedId = "";
} else {
scrollView.expandedId = notificationId;
}
}
}
}
Column {
id: contentColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Style.marginM
spacing: Style.marginM
Row {
width: parent.width
Column {
id: contentColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.margins: Style.marginM
spacing: Style.marginM
// Icon
NImageRounded {
anchors.verticalCenter: parent.verticalCenter
width: Math.round(40 * Style.uiScaleRatio)
height: Math.round(40 * Style.uiScaleRatio)
radius: Math.min(Style.radiusL, width / 2)
imagePath: model.cachedImage || model.originalImage || ""
borderColor: Color.transparent
borderWidth: 0
fallbackIcon: "bell"
fallbackIconSize: 24
}
Row {
width: parent.width
spacing: Style.marginM
// Content
Column {
width: parent.width - Math.round(40 * Style.uiScaleRatio) - Style.marginM - Style.baseWidgetSize
spacing: Style.marginXS
// Icon
NImageRounded {
anchors.verticalCenter: parent.verticalCenter
width: Math.round(40 * Style.uiScaleRatio)
height: Math.round(40 * Style.uiScaleRatio)
radius: Math.min(Style.radiusL, width / 2)
imagePath: model.cachedImage || model.originalImage || ""
borderColor: Color.transparent
borderWidth: 0
fallbackIcon: "bell"
fallbackIconSize: 24
}
// Header row with app name and timestamp
Row {
width: parent.width
spacing: Style.marginS
// Content
Column {
width: parent.width - Math.round(40 * Style.uiScaleRatio) - Style.marginM - Style.baseWidgetSize
spacing: Style.marginXS
// Urgency indicator
Rectangle {
width: 6
height: 6
anchors.verticalCenter: parent.verticalCenter
radius: 3
visible: model.urgency !== 1
color: {
if (model.urgency === 2)
return Color.mError;
else if (model.urgency === 0)
return Color.mOnSurfaceVariant;
else
return Color.transparent;
// Header row with app name and timestamp
Row {
width: parent.width
spacing: Style.marginS
// Urgency indicator
Rectangle {
width: 6
height: 6
anchors.verticalCenter: parent.verticalCenter
radius: 3
visible: model.urgency !== 1
color: {
if (model.urgency === 2)
return Color.mError;
else if (model.urgency === 0)
return Color.mOnSurfaceVariant;
else
return Color.transparent;
}
}
NText {
text: model.appName || "Unknown App"
pointSize: Style.fontSizeXS
font.weight: Style.fontWeightBold
color: Color.mSecondary
}
NText {
textFormat: Text.PlainText
text: " " + Time.formatRelativeTime(model.timestamp)
pointSize: Style.fontSizeXXS
color: Color.mOnSurfaceVariant
anchors.bottom: parent.bottom
}
}
// Summary
NText {
text: model.appName || "Unknown App"
pointSize: Style.fontSizeXS
font.weight: Style.fontWeightBold
color: Color.mSecondary
}
NText {
textFormat: Text.PlainText
text: " " + Time.formatRelativeTime(model.timestamp)
pointSize: Style.fontSizeXXS
color: Color.mOnSurfaceVariant
anchors.bottom: parent.bottom
}
}
// Summary
NText {
id: summaryText
width: parent.width
text: model.summary || I18n.tr("general.no-summary")
pointSize: Style.fontSizeM
font.weight: Font.Medium
color: Color.mOnSurface
textFormat: Text.PlainText
wrapMode: Text.Wrap
maximumLineCount: notificationDelegate.isExpanded ? 999 : 2
elide: Text.ElideRight
}
// Body
NText {
id: bodyText
width: parent.width
text: model.body || ""
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
textFormat: Text.PlainText
wrapMode: Text.Wrap
maximumLineCount: notificationDelegate.isExpanded ? 999 : 3
elide: Text.ElideRight
visible: text.length > 0
}
// Expand indicator
Row {
width: parent.width
visible: !notificationDelegate.isExpanded && notificationDelegate.canExpand
spacing: Style.marginXS
Item {
width: parent.width - expandText.width - expandIcon.width - Style.marginXS
height: 1
}
NText {
id: expandText
text: I18n.tr("notifications.panel.click-to-expand") || "Click to expand"
pointSize: Style.fontSizeXS
color: Color.mPrimary
id: summaryText
width: parent.width
text: model.summary || I18n.tr("general.no-summary")
pointSize: Style.fontSizeM
font.weight: Font.Medium
color: Color.mOnSurface
textFormat: Text.PlainText
wrapMode: Text.Wrap
maximumLineCount: notificationDelegate.isExpanded ? 999 : 2
elide: Text.ElideRight
}
NIcon {
id: expandIcon
icon: "chevron-down"
// Body
NText {
id: bodyText
width: parent.width
text: model.body || ""
pointSize: Style.fontSizeS
color: Color.mPrimary
color: Color.mOnSurfaceVariant
textFormat: Text.PlainText
wrapMode: Text.Wrap
maximumLineCount: notificationDelegate.isExpanded ? 999 : 3
elide: Text.ElideRight
visible: text.length > 0
}
// Expand indicator
Row {
width: parent.width
visible: !notificationDelegate.isExpanded && notificationDelegate.canExpand
spacing: Style.marginXS
Item {
width: parent.width - expandText.width - expandIcon.width - Style.marginXS
height: 1
}
NText {
id: expandText
text: I18n.tr("notifications.panel.click-to-expand") || "Click to expand"
pointSize: Style.fontSizeXS
color: Color.mPrimary
font.weight: Font.Medium
}
NIcon {
id: expandIcon
icon: "chevron-down"
pointSize: Style.fontSizeS
color: Color.mPrimary
}
}
}
}
// Delete button
NIconButton {
icon: "trash"
tooltipText: I18n.tr("tooltips.delete-notification")
baseSize: Style.baseWidgetSize * 0.7
anchors.verticalCenter: parent.verticalCenter
// Delete button
NIconButton {
icon: "trash"
tooltipText: I18n.tr("tooltips.delete-notification")
baseSize: Style.baseWidgetSize * 0.7
anchors.verticalCenter: parent.verticalCenter
onClicked: {
NotificationService.removeFromHistory(notificationId);
onClicked: {
NotificationService.removeFromHistory(notificationId);
}
}
}
}
@@ -478,6 +517,27 @@ SmartPanel {
}
}
}
// Overlay gradient to smooth the hard cut due to scrolling at the bottom (only visible when scrollable)
Rectangle {
anchors.fill: parent
color: Color.transparent
visible: scrollView.ScrollBar.vertical && scrollView.ScrollBar.vertical.size < 1.0
gradient: Gradient {
GradientStop {
position: 0.0
color: Color.transparent
}
GradientStop {
position: 0.85
color: Color.transparent
}
GradientStop {
position: 1.0
color: Qt.alpha(Color.mSurface, 0.95)
}
}
}
}
}
}
@@ -23,6 +23,14 @@ SmartPanel {
// Reference to the plugin content loader (set when panel content is created)
property var contentLoader: null
// Pass through anchor properties from plugin panel content
panelAnchorHorizontalCenter: pluginInstance?.panelAnchorHorizontalCenter ?? false
panelAnchorVerticalCenter: pluginInstance?.panelAnchorVerticalCenter ?? false
panelAnchorTop: pluginInstance?.panelAnchorTop ?? false
panelAnchorBottom: pluginInstance?.panelAnchorBottom ?? false
panelAnchorLeft: pluginInstance?.panelAnchorLeft ?? false
panelAnchorRight: pluginInstance?.panelAnchorRight ?? false
// Panel content is dynamically loaded
panelContent: Component {
Item {
@@ -18,7 +18,7 @@ ColumnLayout {
property bool valueUseDistroLogo: widgetData.useDistroLogo !== undefined ? widgetData.useDistroLogo : widgetMetadata.useDistroLogo
property string valueCustomIconPath: widgetData.customIconPath !== undefined ? widgetData.customIconPath : ""
property bool valueEnableColorization: widgetData.enableColorization || false
property string valueColorizeSystemIcon: widgetData.colorizeSystemIcon !== undefined ? widgetData.colorizeSystemIcon : (widgetMetadata.colorizeSystemIcon !== undefined ? widgetMetadata.colorizeSystemIcon : "none")
property string valueColorizeSystemIcon: widgetData.colorizeSystemIcon !== undefined ? widgetData.colorizeSystemIcon : widgetMetadata.colorizeSystemIcon
function saveSettings() {
var settings = Object.assign({}, widgetData || {});
@@ -18,6 +18,8 @@ ColumnLayout {
property bool valueParseJson: widgetData.parseJson !== undefined ? widgetData.parseJson : widgetMetadata.parseJson
property int valueMaxTextLengthHorizontal: widgetData?.maxTextLength?.horizontal ?? widgetMetadata?.maxTextLength?.horizontal
property int valueMaxTextLengthVertical: widgetData?.maxTextLength?.vertical ?? widgetMetadata?.maxTextLength?.vertical
property string valueHideMode: (widgetData.hideMode !== undefined) ? widgetData.hideMode : widgetMetadata.hideMode
property bool valueShowIcon: (widgetData.showIcon !== undefined) ? widgetData.showIcon : widgetMetadata.showIcon
function saveSettings() {
var settings = Object.assign({}, widgetData || {});
@@ -39,6 +41,8 @@ ColumnLayout {
settings.textCollapse = textCollapseInput.text;
settings.textStream = valueTextStream;
settings.parseJson = valueParseJson;
settings.showIcon = valueShowIcon;
settings.hideMode = valueHideMode;
settings.maxTextLength = {
"horizontal": valueMaxTextLengthHorizontal,
"vertical": valueMaxTextLengthVertical
@@ -88,6 +92,15 @@ ColumnLayout {
}
}
NToggle {
id: showIconToggle
label: I18n.tr("bar.widget-settings.custom-button.show-icon.label", "Show icon")
description: I18n.tr("bar.widget-settings.custom-button.show-icon.description", "Toggles the visibility of the widget's icon.")
checked: valueShowIcon
onToggled: checked => valueShowIcon = checked
visible: textCommandInput.text !== ""
}
RowLayout {
spacing: Style.marginM
@@ -166,7 +179,7 @@ ColumnLayout {
Layout.fillWidth: true
label: I18n.tr("bar.widget-settings.custom-button.wheel-mode-separate.label", "Separate wheel commands")
description: I18n.tr("bar.widget-settings.custom-button.wheel-mode-separate.description", "Enable separate commands for wheel up and down")
property bool internalChecked: (widgetData?.wheelMode || widgetMetadata?.wheelMode || "unified") === "separate"
property bool internalChecked: (widgetData?.wheelMode || widgetMetadata?.wheelMode) === "separate"
checked: internalChecked
onToggled: checked => {
internalChecked = checked;
@@ -188,7 +201,7 @@ ColumnLayout {
label: I18n.tr("bar.widget-settings.custom-button.wheel.label")
description: I18n.tr("bar.widget-settings.custom-button.wheel.description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.wheelExec || widgetMetadata?.wheelExec || ""
text: widgetData?.wheelExec || widgetMetadata?.wheelExec
}
NToggle {
@@ -217,7 +230,7 @@ ColumnLayout {
label: I18n.tr("bar.widget-settings.custom-button.wheel-up.label")
description: I18n.tr("bar.widget-settings.custom-button.wheel-up.description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.wheelUpExec || widgetMetadata?.wheelUpExec || ""
text: widgetData?.wheelUpExec || widgetMetadata?.wheelUpExec
}
NToggle {
@@ -227,7 +240,7 @@ ColumnLayout {
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(wheelUpUpdateText, I18n.tr("bar.widget-settings.custom-button.wheel.update-text"), "auto")
onExited: TooltipService.hide()
checked: (widgetData?.wheelUpUpdateText !== undefined) ? widgetData.wheelUpUpdateText : (widgetMetadata?.wheelUpUpdateText ?? false)
checked: (widgetData?.wheelUpUpdateText !== undefined) ? widgetData.wheelUpUpdateText : widgetMetadata?.wheelUpUpdateText
onToggled: isChecked => checked = isChecked
}
}
@@ -241,7 +254,7 @@ ColumnLayout {
label: I18n.tr("bar.widget-settings.custom-button.wheel-down.label")
description: I18n.tr("bar.widget-settings.custom-button.wheel-down.description")
placeholderText: I18n.tr("placeholders.enter-command")
text: widgetData?.wheelDownExec || widgetMetadata?.wheelDownExec || ""
text: widgetData?.wheelDownExec || widgetMetadata?.wheelDownExec
}
NToggle {
@@ -251,7 +264,7 @@ ColumnLayout {
Layout.bottomMargin: Style.marginS
onEntered: TooltipService.show(wheelDownUpdateText, I18n.tr("bar.widget-settings.custom-button.wheel.update-text"), "auto")
onExited: TooltipService.hide()
checked: (widgetData?.wheelDownUpdateText !== undefined) ? widgetData.wheelDownUpdateText : (widgetMetadata?.wheelDownUpdateText ?? false)
checked: (widgetData?.wheelDownUpdateText !== undefined) ? widgetData.wheelDownUpdateText : widgetMetadata?.wheelDownUpdateText
onToggled: isChecked => checked = isChecked
}
}
@@ -325,9 +338,32 @@ ColumnLayout {
visible: !valueTextStream
label: I18n.tr("bar.widget-settings.custom-button.refresh-interval.label")
description: I18n.tr("bar.widget-settings.custom-button.refresh-interval.description")
placeholderText: String(widgetMetadata.textIntervalMs || 3000)
placeholderText: String(widgetMetadata.textIntervalMs)
text: widgetData && widgetData.textIntervalMs !== undefined ? String(widgetData.textIntervalMs) : ""
}
NComboBox {
id: hideModeComboBox
label: I18n.tr("bar.widget-settings.custom-button.hide-mode.label", "Hide mode")
description: I18n.tr("bar.widget-settings.custom-button.hide-mode.description", "Controls widget visibility when the command has no output.")
model: [
{
name: I18n.tr("bar.widget-settings.custom-button.hide-mode.alwaysExpanded", "Always expanded"),
key: "alwaysExpanded"
},
{
name: I18n.tr("bar.widget-settings.custom-button.hide-mode.expandWithOutput", "Expand when has output"),
key: "expandWithOutput"
},
{
name: I18n.tr("bar.widget-settings.custom-button.hide-mode.maxTransparent", "Max expanded but transparent"),
key: "maxTransparent"
}
]
currentKey: valueHideMode
onSelected: key => valueHideMode = key
visible: textCommandInput.text !== "" && valueTextStream == true
}
}
}
}
@@ -15,7 +15,7 @@ ColumnLayout {
// Local state
property string valueHideMode: "hidden" // Default to 'Hide When Empty'
// Deprecated: hideWhenIdle now folded into hideMode = "idle"
property bool valueHideWhenIdle: widgetData.hideWhenIdle !== undefined ? widgetData.hideWhenIdle : (widgetMetadata.hideWhenIdle !== undefined ? widgetMetadata.hideWhenIdle : false)
property bool valueHideWhenIdle: widgetData.hideWhenIdle !== undefined ? widgetData.hideWhenIdle : widgetMetadata.hideWhenIdle
property bool valueShowAlbumArt: widgetData.showAlbumArt !== undefined ? widgetData.showAlbumArt : widgetMetadata.showAlbumArt
property bool valueShowArtistFirst: widgetData.showArtistFirst !== undefined ? widgetData.showArtistFirst : widgetMetadata.showArtistFirst
property bool valueShowVisualizer: widgetData.showVisualizer !== undefined ? widgetData.showVisualizer : widgetMetadata.showVisualizer
@@ -21,6 +21,7 @@ ColumnLayout {
property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons
property bool valueShowTitle: isVerticalBar ? false : widgetData.showTitle !== undefined ? widgetData.showTitle : widgetMetadata.showTitle
property int valueTitleWidth: widgetData.titleWidth !== undefined ? widgetData.titleWidth : widgetMetadata.titleWidth
property bool valueShowPinnedApps: widgetData.showPinnedApps !== undefined ? widgetData.showPinnedApps : widgetMetadata.showPinnedApps
Component.onCompleted: {
if (widgetData && widgetData.hideMode !== undefined) {
@@ -38,6 +39,7 @@ ColumnLayout {
settings.colorizeIcons = valueColorizeIcons;
settings.showTitle = valueShowTitle;
settings.titleWidth = parseInt(titleWidthInput.text) || widgetMetadata.titleWidth;
settings.showPinnedApps = valueShowPinnedApps;
return settings;
}
@@ -104,5 +106,9 @@ ColumnLayout {
description: I18n.tr("bar.widget-settings.taskbar.title-width.description")
text: widgetData.titleWidth || widgetMetadata.titleWidth
placeholderText: I18n.tr("placeholders.enter-width-pixels")
label: I18n.tr("bar.widget-settings.taskbar.show-pinned-apps.label")
description: I18n.tr("bar.widget-settings.taskbar.show-pinned-apps.description")
checked: root.valueShowPinnedApps
onToggled: checked => root.valueShowPinnedApps = checked
}
}
@@ -13,7 +13,8 @@ ColumnLayout {
// Local state
property var localBlacklist: widgetData.blacklist || []
property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons
property bool valueDrawerEnabled: widgetData.drawerEnabled !== undefined ? widgetData.drawerEnabled : (widgetMetadata.drawerEnabled !== undefined ? widgetMetadata.drawerEnabled : true)
property bool valueDrawerEnabled: widgetData.drawerEnabled !== undefined ? widgetData.drawerEnabled : widgetMetadata.drawerEnabled
property bool valueHidePassive: widgetData.hidePassive !== undefined ? widgetData.hidePassive : widgetMetadata.hidePassive
ListModel {
id: blacklistModel
@@ -46,6 +47,14 @@ ColumnLayout {
onToggled: checked => root.valueDrawerEnabled = checked
}
NToggle {
Layout.fillWidth: true
label: I18n.tr("bar.widget-settings.tray.hide-passive.label")
description: I18n.tr("bar.widget-settings.tray.hide-passive.description")
checked: root.valueHidePassive
onToggled: checked => root.valueHidePassive = checked
}
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginS
@@ -150,6 +159,7 @@ ColumnLayout {
settings.blacklist = newBlacklist;
settings.colorizeIcons = root.valueColorizeIcons;
settings.drawerEnabled = root.valueDrawerEnabled;
settings.hidePassive = root.valueHidePassive;
return settings;
}
}
@@ -23,7 +23,7 @@ ColumnLayout {
property bool enableOnStateLogic: (widgetData && widgetData.enableOnStateLogic !== undefined) ? widgetData.enableOnStateLogic : widgetMetadata.enableOnStateLogic
Component.onCompleted: {
stateChecksJson = (widgetData && widgetData.stateChecksJson !== undefined) ? widgetData.stateChecksJson : widgetMetadata.stateChecksJson || "[]";
stateChecksJson = (widgetData && widgetData.stateChecksJson !== undefined) ? widgetData.stateChecksJson : widgetMetadata.stateChecksJson;
try {
var initialChecks = JSON.parse(stateChecksJson);
if (initialChecks && Array.isArray(initialChecks)) {
+122 -74
View File
@@ -19,8 +19,8 @@ SmartPanel {
readonly property bool attachToBar: Settings.data.ui.settingsPanelAttachToBar
readonly property string barPosition: Settings.data.bar.position
readonly property bool barFloating: Settings.data.bar.floating
readonly property real barMarginH: barFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
readonly property real barMarginV: barFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0
readonly property real barMarginH: barFloating ? Math.ceil(Settings.data.bar.marginHorizontal * Style.marginXL) : 0
readonly property real barMarginV: barFloating ? Math.ceil(Settings.data.bar.marginVertical * Style.marginXL) : 0
forceAttachToBar: attachToBar
panelAnchorHorizontalCenter: attachToBar ? (barPosition === "top" || barPosition === "bottom") : true
@@ -440,91 +440,118 @@ SmartPanel {
border.width: Style.borderS
radius: Style.radiusM
NListView {
id: sidebarList
Item {
anchors.fill: parent
anchors.margins: Style.marginS
model: root.tabsModel
spacing: Style.marginXS
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.marginS * 2
radius: Style.radiusS
color: selected ? Color.mPrimary : (tabItem.hovering ? Color.mHover : Color.transparent)
readonly property bool selected: index === root.currentTabIndex
property bool hovering: false
property color tabTextColor: selected ? Color.mOnPrimary : (tabItem.hovering ? Color.mOnHover : Color.mOnSurface)
NListView {
id: sidebarList
anchors.fill: parent
anchors.margins: Style.marginS
model: root.tabsModel
spacing: Style.marginXS
currentIndex: root.currentTabIndex
verticalPolicy: ScrollBar.AsNeeded
Behavior on width {
NumberAnimation {
duration: Style.animationFast
delegate: Rectangle {
id: tabItem
width: sidebarList.verticalScrollBarActive ? sidebarList.width - sidebarList.scrollBarWidth - Style.marginXS : sidebarList.width
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
property bool hovering: false
property color tabTextColor: selected ? Color.mOnPrimary : (tabItem.hovering ? Color.mOnHover : Color.mOnSurface)
Behavior on width {
NumberAnimation {
duration: Style.animationFast
}
}
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
Behavior on tabTextColor {
ColorAnimation {
duration: Style.animationFast
}
}
RowLayout {
id: tabEntryRow
anchors.fill: parent
anchors.leftMargin: Style.marginS
anchors.rightMargin: Style.marginS
spacing: Style.marginM
// Tab icon
NIcon {
icon: modelData.icon
color: tabTextColor
pointSize: Style.fontSizeXL
}
// Tab label
NText {
text: I18n.tr(modelData.label)
color: tabTextColor
pointSize: Style.fontSizeM
font.weight: Style.fontWeightBold
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton
onEntered: tabItem.hovering = true
onExited: tabItem.hovering = false
onCanceled: tabItem.hovering = false
onClicked: root.currentTabIndex = index
}
}
Behavior on color {
ColorAnimation {
duration: Style.animationFast
onCurrentIndexChanged: {
if (currentIndex !== root.currentTabIndex) {
root.currentTabIndex = currentIndex;
}
}
Behavior on tabTextColor {
ColorAnimation {
duration: Style.animationFast
Connections {
target: root
function onCurrentTabIndexChanged() {
if (sidebarList.currentIndex !== root.currentTabIndex) {
sidebarList.currentIndex = root.currentTabIndex;
sidebarList.positionViewAtIndex(root.currentTabIndex, ListView.Contain);
}
}
}
RowLayout {
id: tabEntryRow
anchors.fill: parent
anchors.leftMargin: Style.marginS
anchors.rightMargin: Style.marginS
spacing: Style.marginM
// Tab icon
NIcon {
icon: modelData.icon
color: tabTextColor
pointSize: Style.fontSizeXL
}
// Tab label
NText {
text: I18n.tr(modelData.label)
color: tabTextColor
pointSize: Style.fontSizeM
font.weight: Style.fontWeightBold
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton
onEntered: tabItem.hovering = true
onExited: tabItem.hovering = false
onCanceled: tabItem.hovering = false
onClicked: root.currentTabIndex = index
}
}
onCurrentIndexChanged: {
if (currentIndex !== root.currentTabIndex) {
root.currentTabIndex = currentIndex;
}
}
Connections {
target: root
function onCurrentTabIndexChanged() {
if (sidebarList.currentIndex !== root.currentTabIndex) {
sidebarList.currentIndex = root.currentTabIndex;
sidebarList.positionViewAtIndex(root.currentTabIndex, ListView.Contain);
// Overlay gradient for sidebar scrolling (only visible when scrollable)
Rectangle {
anchors.fill: parent
anchors.margins: Style.borderS
radius: Style.radiusM
color: Color.transparent
visible: sidebarList.verticalScrollBarActive
gradient: Gradient {
GradientStop {
position: 0.0
color: Color.transparent
}
GradientStop {
position: 0.95
color: Color.transparent
}
GradientStop {
position: 1.0
color: Color.mSurfaceVariant
}
}
}
@@ -633,6 +660,27 @@ SmartPanel {
}
}
}
// Overlay gradient for content scrolling (only visible when scrollable)
Rectangle {
anchors.fill: parent
color: Color.transparent
visible: root.activeScrollView && root.activeScrollView.ScrollBar.vertical && root.activeScrollView.ScrollBar.vertical.size < 1.0
gradient: Gradient {
GradientStop {
position: 0.0
color: Color.transparent
}
GradientStop {
position: 0.95
color: Color.transparent
}
GradientStop {
position: 1.0
color: Qt.alpha(Color.mSurfaceVariant, 0.95)
}
}
}
}
}
}
@@ -530,4 +530,10 @@ ColumnLayout {
}
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.bottomMargin: Style.marginL
}
}
+1 -1
View File
@@ -181,7 +181,7 @@ ColumnLayout {
stepSize: 0.01
value: Settings.data.bar.marginHorizontal
onMoved: value => Settings.data.bar.marginHorizontal = value
text: Math.round(Settings.data.bar.marginHorizontal * 100) + "%"
text: Math.ceil(Settings.data.bar.marginHorizontal * 100) + "%"
}
}
}
@@ -933,4 +933,10 @@ ColumnLayout {
}
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.bottomMargin: Style.marginL
}
}
+13 -6
View File
@@ -7,6 +7,7 @@ import qs.Commons
import qs.Services.Compositor
import qs.Services.Hardware
import qs.Services.Location
import qs.Services.UI
import qs.Widgets
ColumnLayout {
@@ -372,6 +373,7 @@ ColumnLayout {
// Manual scheduling
ColumnLayout {
spacing: Style.marginS
Layout.fillWidth: true
visible: Settings.data.nightLight.enabled && !Settings.data.nightLight.autoSchedule && !Settings.data.nightLight.forced
NLabel {
@@ -379,14 +381,16 @@ ColumnLayout {
description: I18n.tr("settings.display.night-light.manual-schedule.description")
}
// Sunrise time
RowLayout {
Layout.fillWidth: false
Layout.fillWidth: true
spacing: Style.marginS
NText {
text: I18n.tr("settings.display.night-light.manual-schedule.sunrise")
pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignVCenter
}
NComboBox {
@@ -394,17 +398,20 @@ ColumnLayout {
currentKey: Settings.data.nightLight.manualSunrise
placeholder: I18n.tr("settings.display.night-light.manual-schedule.select-start")
onSelected: key => Settings.data.nightLight.manualSunrise = key
minimumWidth: 120
Layout.fillWidth: true
}
}
Item {
Layout.preferredWidth: 20
}
// Sunset time
RowLayout {
Layout.fillWidth: true
spacing: Style.marginS
NText {
text: I18n.tr("settings.display.night-light.manual-schedule.sunset")
pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignVCenter
}
NComboBox {
@@ -412,7 +419,7 @@ ColumnLayout {
currentKey: Settings.data.nightLight.manualSunset
placeholder: I18n.tr("settings.display.night-light.manual-schedule.select-stop")
onSelected: key => Settings.data.nightLight.manualSunset = key
minimumWidth: 120
Layout.fillWidth: true
}
}
}
+35 -1
View File
@@ -81,6 +81,25 @@ ColumnLayout {
}
}
ColumnLayout {
visible: Settings.data.dock.enabled
spacing: Style.marginXXS
Layout.fillWidth: true
NLabel {
label: I18n.tr("settings.dock.appearance.dead-opacity.label")
description: I18n.tr("settings.dock.appearance.dead-opacity.description")
}
NValueSlider {
Layout.fillWidth: true
from: 0
to: 1
stepSize: 0.01
value: Settings.data.dock.deadOpacity
onMoved: value => Settings.data.dock.deadOpacity = value
text: Math.floor(Settings.data.dock.deadOpacity * 100) + "%"
}
}
ColumnLayout {
visible: Settings.data.dock.enabled
spacing: Style.marginXXS
@@ -121,6 +140,22 @@ ColumnLayout {
}
}
NToggle {
visible: Settings.data.dock.enabled
label: I18n.tr("settings.dock.appearance.inactive-indicators.label")
description: I18n.tr("settings.dock.appearance.inactive-indicators.description")
checked: Settings.data.dock.inactiveIndicators
onToggled: checked => Settings.data.dock.inactiveIndicators = checked
}
NToggle {
visible: Settings.data.dock.enabled
label: I18n.tr("settings.dock.appearance.pinned-static.label")
description: I18n.tr("settings.dock.appearance.pinned-static.description")
checked: Settings.data.dock.pinnedStatic
onToggled: checked => Settings.data.dock.pinnedStatic = checked
}
NToggle {
visible: Settings.data.dock.enabled
label: I18n.tr("settings.dock.monitors.only-same-output.label")
@@ -183,7 +218,6 @@ ColumnLayout {
}
NDivider {
visible: Settings.data.dock.enabled
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.bottomMargin: Style.marginL
@@ -93,4 +93,10 @@ ColumnLayout {
}
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.bottomMargin: Style.marginL
}
}
@@ -65,6 +65,13 @@ ColumnLayout {
onToggled: checked => Settings.data.appLauncher.viewMode = checked ? "grid" : "list"
}
NToggle {
label: I18n.tr("settings.launcher.settings.show-categories.label")
description: I18n.tr("settings.launcher.settings.show-categories.description")
checked: Settings.data.appLauncher.showCategories
onToggled: checked => Settings.data.appLauncher.showCategories = checked
}
NToggle {
label: I18n.tr("settings.launcher.settings.clipboard-history.label")
description: I18n.tr("settings.launcher.settings.clipboard-history.description")
+6
View File
@@ -235,4 +235,10 @@ ColumnLayout {
}
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.bottomMargin: Style.marginL
}
}
+18 -2
View File
@@ -14,6 +14,16 @@ ColumnLayout {
// Track which plugins are currently updating
property var updatingPlugins: ({})
function stripAuthorEmail(author) {
if (!author)
return "";
var lastBracket = author.lastIndexOf("<");
if (lastBracket >= 0) {
return author.substring(0, lastBracket).trim();
}
return author;
}
// Check for updates when tab becomes visible
onVisibleChanged: {
if (visible && PluginService.pluginsFullyLoaded) {
@@ -152,7 +162,7 @@ ColumnLayout {
}
NText {
text: modelData.author
text: stripAuthorEmail(modelData.author)
font.pointSize: Style.fontSizeXXS
color: Color.mOnSurfaceVariant
}
@@ -473,7 +483,7 @@ ColumnLayout {
}
NText {
text: modelData.author
text: stripAuthorEmail(modelData.author)
font.pointSize: Style.fontSizeXXS
color: Color.mOnSurfaceVariant
}
@@ -525,6 +535,12 @@ ColumnLayout {
Layout.fillWidth: true
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.bottomMargin: Style.marginL
}
// ------------------------------
// Dialogs
// ------------------------------
@@ -269,4 +269,10 @@ ColumnLayout {
}
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.bottomMargin: Style.marginL
}
}
@@ -510,4 +510,10 @@ ColumnLayout {
}
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.bottomMargin: Style.marginL
}
}
@@ -468,4 +468,10 @@ ColumnLayout {
}
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.bottomMargin: Style.marginL
}
}
+17 -5
View File
@@ -25,7 +25,7 @@ SmartPanel {
// Read widget settings for reactivity
readonly property var widgetSettings: {
// Reference settingsVersion to force recalculation when it changes
var _ = root.settingsVersion;
var settingsVersionRef = root.settingsVersion;
if (widgetSection === "" || widgetIndex < 0)
return {};
var widgets = Settings.data.bar.widgets[widgetSection];
@@ -39,6 +39,7 @@ SmartPanel {
// Read pinned list directly from settings for reactivity
readonly property var pinnedList: widgetSettings.pinned || []
readonly property bool hidePassive: widgetSettings.hidePassive !== undefined ? widgetSettings.hidePassive : true
function wildCardMatch(str, rule) {
if (!str || !rule)
@@ -72,9 +73,20 @@ SmartPanel {
// Dynamic sizing based on item count
// Show items that are NOT pinned (unpinned items go to drawer)
readonly property var trayValuesAll: (SystemTray.items && SystemTray.items.values) ? SystemTray.items.values : []
readonly property var trayValues: trayValuesAll.filter(function (it) {
return !root.isPinned(it);
})
// Explicitly reference hidePassive to ensure reactivity
readonly property var trayValues: {
// Reference hidePassive to ensure dependency tracking
var hidePassiveRef = root.hidePassive;
return trayValuesAll.filter(function (it) {
if (!it)
return false;
// Filter out passive items if hidePassive is enabled
if (root.hidePassive && it.status !== undefined && (it.status === SystemTray.Passive || it.status === 0)) {
return false;
}
return !root.isPinned(it);
});
}
readonly property int itemCount: trayValues.length
readonly property int maxColumns: 8
readonly property real cellSize: Math.round(Style.capsuleHeight * 0.65)
@@ -111,7 +123,7 @@ SmartPanel {
// Get the trayMenu window and loader from PanelService (reactive to trigger changes)
readonly property var popupMenuWindow: {
// Reference trigger to force re-evaluation
var _ = popupMenuUpdateTrigger;
var popupMenuUpdateTriggerRef = popupMenuUpdateTrigger;
return PanelService.getPopupMenuWindow(screen);
}
+4 -4
View File
@@ -148,28 +148,28 @@ Item {
readonly property int barOffsetTop: {
if (barPos !== "top")
return 0;
const floatMarginV = isFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0;
const floatMarginV = isFloating ? Math.ceil(Settings.data.bar.marginVertical * Style.marginXL) : 0;
return Style.barHeight + floatMarginV;
}
readonly property int barOffsetBottom: {
if (barPos !== "bottom")
return 0;
const floatMarginV = isFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0;
const floatMarginV = isFloating ? Math.ceil(Settings.data.bar.marginVertical * Style.marginXL) : 0;
return Style.barHeight + floatMarginV;
}
readonly property int barOffsetLeft: {
if (barPos !== "left")
return 0;
const floatMarginH = isFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0;
const floatMarginH = isFloating ? Math.ceil(Settings.data.bar.marginHorizontal * Style.marginXL) : 0;
return Style.barHeight + floatMarginH;
}
readonly property int barOffsetRight: {
if (barPos !== "right")
return 0;
const floatMarginH = isFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0;
const floatMarginH = isFloating ? Math.ceil(Settings.data.bar.marginHorizontal * Style.marginXL) : 0;
return Style.barHeight + floatMarginH;
}
+84 -4
View File
@@ -1,5 +1,4 @@
pragma Singleton
import QtQuick
import Quickshell
import Quickshell.Io
@@ -21,19 +20,32 @@ Singleton {
var command = buildCommand();
// Compare with previous command to avoid unecessary restart
// Compare with previous command to avoid unnecessary restart
if (JSON.stringify(command) !== JSON.stringify(lastCommand)) {
lastCommand = command;
runner.command = command;
// Set running to false so it may restarts below if still enabled
// Set running to false so it may restart below if still enabled
runner.running = false;
}
runner.running = params.enabled;
}
function parseTime(timeStr) {
var parts = timeStr.split(':');
return {
hour: parseInt(parts[0]),
minute: parseInt(parts[1])
};
}
function timeToMinutes(timeObj) {
return timeObj.hour * 60 + timeObj.minute;
}
function buildCommand() {
var cmd = ["wlsunset"];
if (params.forced) {
// Force immediate full night temperature regardless of time
// Keep distinct day/night temps but set times so we're effectively always in "night"
@@ -48,25 +60,79 @@ Singleton {
if (params.autoSchedule) {
cmd.push("-l", `${LocationService.stableLatitude}`, "-L", `${LocationService.stableLongitude}`);
} else {
// Manual schedule - we need to handle the edge case at midnight
var now = new Date();
var currentMinutes = now.getHours() * 60 + now.getMinutes();
var sunrise = parseTime(params.manualSunrise);
var sunset = parseTime(params.manualSunset);
var sunriseMinutes = timeToMinutes(sunrise);
var sunsetMinutes = timeToMinutes(sunset);
// Determine if we're currently in night period
var inNightPeriod = false;
if (sunsetMinutes < sunriseMinutes) {
// Normal case: sunset before sunrise (e.g., 20:00 to 06:00)
inNightPeriod = currentMinutes >= sunsetMinutes || currentMinutes < sunriseMinutes;
} else {
// Edge case: sunset after sunrise (e.g., 06:00 to 20:00 means night is inverted)
inNightPeriod = currentMinutes >= sunsetMinutes && currentMinutes < sunriseMinutes;
}
// Always pass times as-is - wlsunset handles day transitions
cmd.push("-S", params.manualSunrise);
cmd.push("-s", params.manualSunset);
}
cmd.push("-d", 60 * 15); // 15min progressive fade at sunset/sunrise
}
return cmd;
}
// Timer to restart wlsunset at midnight (only for manual schedule)
// This ensures it recalculates times for the new day without visible flicker
Timer {
id: midnightTimer
running: false
repeat: false
function scheduleNextMidnight() {
if (!params.enabled || params.autoSchedule || params.forced) {
running = false;
return;
}
var now = new Date();
var midnight = new Date(now);
midnight.setHours(24, 0, 1, 0); // Next midnight + 1 second
var msUntilMidnight = midnight.getTime() - now.getTime();
interval = msUntilMidnight;
running = true;
Logger.i("NightLight", "Scheduled midnight restart in", Math.floor(msUntilMidnight / 1000), "seconds");
}
onTriggered: {
Logger.i("NightLight", "Midnight reached - restarting wlsunset");
apply();
scheduleNextMidnight();
}
}
// Observe setting changes and location readiness
Connections {
target: Settings.data.nightLight
function onEnabledChanged() {
apply();
midnightTimer.scheduleNextMidnight();
// Toast: night light toggled
const enabled = !!Settings.data.nightLight.enabled;
ToastService.showNotice(I18n.tr("settings.display.night-light.section.label"), enabled ? I18n.tr("toast.night-light.enabled") : I18n.tr("toast.night-light.disabled"), enabled ? "nightlight-on" : "nightlight-off");
}
function onForcedChanged() {
apply();
midnightTimer.scheduleNextMidnight();
if (Settings.data.nightLight.enabled) {
ToastService.showNotice(I18n.tr("settings.display.night-light.section.label"), Settings.data.nightLight.forced ? I18n.tr("toast.night-light.forced") : I18n.tr("toast.night-light.normal"), Settings.data.nightLight.forced ? "nightlight-forced" : "nightlight-on");
}
@@ -77,6 +143,16 @@ Singleton {
function onDayTempChanged() {
apply();
}
function onAutoScheduleChanged() {
apply();
midnightTimer.scheduleNextMidnight();
}
function onManualSunriseChanged() {
apply();
}
function onManualSunsetChanged() {
apply();
}
}
Connections {
@@ -88,6 +164,10 @@ Singleton {
}
}
Component.onCompleted: {
midnightTimer.scheduleNextMidnight();
}
// Foreground process runner
Process {
id: runner
+17 -6
View File
@@ -105,28 +105,39 @@ Singleton {
var name = (device.name || device.deviceName || "").toLowerCase();
var icon = (device.icon || "").toLowerCase();
if (icon.includes("headset") || icon.includes("audio") || name.includes("headphone") || name.includes("airpod") || name.includes("headset") || name.includes("arctis")) {
if (icon.includes("controller") || icon.includes("gamepad") || name.includes("controller") || name.includes("gamepad")) {
return "bt-device-gamepad";
}
if (icon.includes("microphone") || name.includes("microphone")) {
return "bt-device-microphone";
}
if (name.includes("pod") || name.includes("bud") || name.includes("minor")) {
return "bt-device-earbuds";
}
if (icon.includes("headset") || name.includes("arctis") || name.includes("headset") || name.includes("major")) {
return "bt-device-headset";
}
if (icon.includes("headphone") || name.includes("headphone")) {
return "bt-device-headphones";
}
if (icon.includes("mouse") || name.includes("mouse")) {
return "bt-device-mouse";
}
if (icon.includes("keyboard") || name.includes("keyboard")) {
return "bt-device-keyboard";
}
if (icon.includes("phone") || name.includes("phone") || name.includes("iphone") || name.includes("android") || name.includes("samsung")) {
return "bt-device-phone";
}
if (icon.includes("watch") || name.includes("watch")) {
return "bt-device-watch";
}
if (icon.includes("speaker") || name.includes("speaker")) {
if (icon.includes("speaker") || name.includes("speaker") || name.includes("audio") || name.includes("sound")) {
return "bt-device-speaker";
}
if (icon.includes("display") || name.includes("tv")) {
return "bt-device-tv";
}
if (icon.includes("phone") || name.includes("phone") || name.includes("iphone") || name.includes("android") || name.includes("samsung")) {
return "bt-device-phone";
}
return "bt-device-generic";
}
+19 -18
View File
@@ -344,7 +344,7 @@ Singleton {
}
// Enable a plugin
function enablePlugin(pluginId) {
function enablePlugin(pluginId, skipAddToBar) {
if (PluginRegistry.isPluginEnabled(pluginId)) {
Logger.w("PluginService", "Plugin already enabled:", pluginId);
return true;
@@ -358,11 +358,13 @@ Singleton {
PluginRegistry.setPluginEnabled(pluginId, true);
loadPlugin(pluginId);
// Add plugin widget to bar if it provides one
var manifest = PluginRegistry.getPluginManifest(pluginId);
if (manifest && manifest.entryPoints && manifest.entryPoints.barWidget) {
var widgetId = "plugin:" + pluginId;
addWidgetToBar(widgetId, "right"); // Default to right section
// Add plugin widget to bar if it provides one (unless we're restoring from backup)
if (!skipAddToBar) {
var manifest = PluginRegistry.getPluginManifest(pluginId);
if (manifest && manifest.entryPoints && manifest.entryPoints.barWidget) {
var widgetId = "plugin:" + pluginId;
addWidgetToBar(widgetId, "right"); // Default to right section
}
}
updatePluginInAvailable(pluginId, {
@@ -994,15 +996,16 @@ Singleton {
if (success) {
Logger.i("PluginService", "Plugin updated successfully:", pluginId);
// Restore bar layout
// Re-enable the plugin first, so the new component is registered
// Skip adding to bar since we'll restore the layout from backup
enablePlugin(pluginId, true);
// Then restore bar layout (so BarWidgetLoaders can find the new component)
Settings.data.bar.widgets.left = barBackup.left;
Settings.data.bar.widgets.center = barBackup.center;
Settings.data.bar.widgets.right = barBackup.right;
Logger.d("PluginService", "Restored bar layout");
// Re-enable the plugin
enablePlugin(pluginId);
// Remove from updates list
var updates = Object.assign({}, root.pluginUpdates);
delete updates[pluginId];
@@ -1062,12 +1065,10 @@ Singleton {
// If this slot is empty, use it
if (panel.currentPluginId === "") {
// Open the panel first so the loader gets created
// Set the pluginId first - when panel opens and panelContent loads,
// Component.onCompleted will call loadPluginPanel automatically
panel.currentPluginId = pluginId;
panel.open();
// Wait a brief moment for the panel to be fully created
Qt.callLater(function () {
panel.loadPluginPanel(pluginId);
});
return true;
}
}
@@ -1077,10 +1078,10 @@ Singleton {
var panel1 = PanelService.getPanel("pluginPanel1", screen);
if (panel1) {
panel1.unloadPluginPanel();
// Set the pluginId first - when panel opens and panelContent loads,
// Component.onCompleted will call loadPluginPanel automatically
panel1.currentPluginId = pluginId;
panel1.open();
Qt.callLater(function () {
panel1.loadPluginPanel(pluginId);
});
return true;
}
+3
View File
@@ -120,6 +120,8 @@ Singleton {
"CustomButton": {
"allowUserSettings": true,
"icon": "heart",
"showIcon": true,
"hideMode": "alwaysExpanded",
"leftClickExec": "",
"leftClickUpdateText": false,
"rightClickExec": "",
@@ -205,6 +207,7 @@ Singleton {
"colorizeIcons": false,
"showTitle": false,
"titleWidth": 120
"showPinnedApps": true
},
"TaskbarGrouped": {
"allowUserSettings": true,
+38 -2
View File
@@ -478,6 +478,7 @@ NBox {
MouseArea {
id: flowDragArea
anchors.fill: parent
anchors.margins: -20 * Style.uiScaleRatio // Buffer zone to prevent premature cancel
z: -1
acceptedButtons: Qt.LeftButton
@@ -618,6 +619,28 @@ NBox {
onPositionChanged: mouse => {
if (draggedIndex !== -1 && potentialDrag) {
// Check if mouse is too far outside the actual parent bounds
const buffer = 30 * Style.uiScaleRatio;
const isOutside = mouse.x < -buffer || mouse.x > parent.width + buffer || mouse.y < -buffer || mouse.y > parent.height + buffer;
if (isOutside && (dragStarted || potentialDrag)) {
// Cancel drag if mouse is too far outside
if (potentialDrag) {
root.dragPotentialEnded();
}
dragStarted = false;
potentialDrag = false;
draggedIndex = -1;
draggedWidget = null;
dropTargetIndex = -1;
draggedModelData = null;
preventStealing = false;
dropIndicator.opacity = 0;
pulseAnimation.running = false;
dragGhost.width = 0;
return;
}
const deltaX = mouse.x - startPos.x;
const deltaY = mouse.y - startPos.y;
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
@@ -669,10 +692,23 @@ NBox {
}
onExited: {
if (dragStarted) {
// Hide drop indicator when mouse leaves, but keep ghost visible
if (dragStarted || potentialDrag) {
// Cancel drag when mouse leaves the area
if (potentialDrag) {
root.dragPotentialEnded();
}
// Reset everything
dragStarted = false;
potentialDrag = false;
draggedIndex = -1;
draggedWidget = null;
dropTargetIndex = -1;
draggedModelData = null;
preventStealing = false;
dropIndicator.opacity = 0;
pulseAnimation.running = false;
dragGhost.width = 0;
}
}
+4 -3
View File
@@ -9,19 +9,20 @@ Rectangle {
// Public properties
property int currentIndex: 0
property int spacing: Style.marginS
property real spacing: Style.marginS
property real margins: Style.marginXS
default property alias content: tabRow.children
// Styling
Layout.fillWidth: true
implicitHeight: Style.baseWidgetSize
implicitHeight: Style.baseWidgetSize + (margins * 2)
color: Color.mSurfaceVariant
radius: Style.iRadiusS
RowLayout {
id: tabRow
anchors.fill: parent
anchors.margins: 0
anchors.margins: margins
spacing: root.spacing
}
}