Merge branch 'main' of github.com:noctalia-dev/noctalia-shell

This commit is contained in:
ItsLemmy
2025-10-15 23:24:01 -04:00
36 changed files with 2504 additions and 46 deletions
+34
View File
@@ -0,0 +1,34 @@
{
"dark": {
"mPrimary": "#37f499",
"mOnPrimary": "#171928",
"mSecondary": "#04d1f9",
"mOnSecondary": "#171928",
"mTertiary": "#a48cf2",
"mOnTertiary": "#171928",
"mError": "#f16c75",
"mOnError": "#171928",
"mSurface": "#212337",
"mOnSurface": "#ebfafa",
"mSurfaceVariant": "#292e42",
"mOnSurfaceVariant": "#ABB4DA",
"mOutline": "#3b4261",
"mShadow": "#414868"
},
"light": {
"mPrimary": "#37f499",
"mOnPrimary": "#171928",
"mSecondary": "#04d1f9",
"mOnSecondary": "#171928",
"mTertiary": "#a48cf2",
"mOnTertiary": "#171928",
"mError": "#f16c75",
"mOnError": "#171928",
"mSurface": "#ffffff",
"mOnSurface": "#171928",
"mSurfaceVariant": "#f2f4f8",
"mOnSurfaceVariant": "#3b4261",
"mOutline": "#b0b6c3",
"mShadow": "#e0e3e8"
}
}
@@ -0,0 +1,23 @@
[colors]
foreground=ebfafa
background=212337
regular0=21222c
regular1=f9515d
regular2=37f499
regular3=e9f941
regular4=9071f4
regular5=f265b5
regular6=04d1f9
regular7=ebfafa
bright0=7081d0
bright1=f16c75
bright2=69F8B3
bright3=f1fc79
bright4=a48cf2
bright5=FD92CE
bright6=66e4fd
bright7=ffffff
selection-foreground=ebfafa
selection-background=bf4f8e
cursor=37f499 f8f8f2
@@ -0,0 +1,22 @@
[colors]
foreground=212337
background=ebfafa
regular0=ebfafa # black → white
regular1=ba1a1a # red (darker)
regular2=1a7f4c # green (darker)
regular3=9e8c13 # yellow (darker)
regular4=3a3e8c # blue (darker)
regular5=8c2a6c # magenta (darker)
regular6=1a6c8c # cyan (darker)
regular7=212337 # white → black
bright0=7081d0 # keep as accent
bright1=d23b3b # lighter red
bright2=37f499 # original green
bright3=e9f941 # original yellow
bright4=9071f4 # original blue
bright5=f265b5 # original magenta
bright6=04d1f9 # original cyan
bright7=212337 # black
selection-foreground=212337
selection-background=bf4f8e
cursor=1a7f4c 212337
@@ -0,0 +1,21 @@
palette = 0=#21222c
palette = 1=#f9515d
palette = 2=#37f499
palette = 3=#e9f941
palette = 4=#9071f4
palette = 5=#f265b5
palette = 6=#04d1f9
palette = 7=#ebfafa
palette = 8=#7081d0
palette = 9=#f16c75
palette = 10=#69F8B3
palette = 11=#f1fc79
palette = 12=#a48cf2
palette = 13=#FD92CE
palette = 14=#66e4fd
palette = 15=#ffffff
background = 212337
foreground = ebfafa
cursor-color = 37f499
selection-background = bf4f8e
selection-foreground = ebfafa
@@ -0,0 +1,22 @@
palette = 0=#f8f8fa # base background (was dark, now light)
palette = 1=#d7263d # red (less saturated)
palette = 2=#1eb980 # green (cooler, lighter)
palette = 3=#f7c948 # yellow (warmer)
palette = 4=#5e60ce # blue (lighter)
palette = 5=#c77dff # magenta (lighter)
palette = 6=#38a1db # cyan (lighter)
palette = 7=#21222c # base foreground (was background, now dark)
palette = 8=#bfc9e3 # bright black (light gray)
palette = 9=#f9515d # bright red
palette = 10=#37f499 # bright green
palette = 11=#e9f941 # bright yellow
palette = 12=#9071f4 # bright blue
palette = 13=#f265b5 # bright magenta
palette = 14=#04d1f9 # bright cyan
palette = 15=#21222c # bright white (dark for contrast)
background = f8f8fa
foreground = 21222c
cursor-color = 5e60ce
selection-background = d7e3fa
selection-foreground = 21222c
@@ -0,0 +1,22 @@
color0 #21222c
color1 #f9515d
color2 #37f499
color3 #e9f941
color4 #9071f4
color5 #f265b5
color6 #04d1f9
color7 #ebfafa
color8 #7081d0
color9 #f16c75
color10 #69F8B3
color11 #f1fc79
color12 #a48cf2
color13 #FD92CE
color14 #66e4fd
color15 #ffffff
background #212337
selection_foreground #ebfafa
cursor #37f499
cursor_text_color #f8f8f2
foreground #ebfafa
selection_background #bf4f8e
@@ -0,0 +1,22 @@
color0 #ebfafa
color1 #f9515d
color2 #37f499
color3 #e9f941
color4 #9071f4
color5 #f265b5
color6 #04d1f9
color7 #212337
color8 #7081d0
color9 #f16c75
color10 #69F8B3
color11 #f1fc79
color12 #a48cf2
color13 #FD92CE
color14 #66e4fd
color15 #323449
background #ebfafa
selection_foreground #ebfafa
cursor #212337
cursor_text_color #ebfafa
foreground #212337
selection_background #bf4f8e
+32 -2
View File
@@ -1322,7 +1322,8 @@
"bottom_left": "Unten links",
"bottom_right": "Unten rechts",
"bottom_center": "Unten mittig",
"top_center": "Oben mittig"
"top_center": "Oben mittig",
"center": "Mitte"
},
"quickSettingsStyle": {
"modern": "Modern",
@@ -1622,5 +1623,34 @@
"label": "Letztes Control-Center-Widget entfernt",
"description": "Das Control-Center-Widget wurde aus der Leiste entfernt. Um es erneut über die Leiste zu öffnen, fügen Sie das Widget wieder hinzu. Sie können es auch durch Rechtsklick auf die Leiste öffnen."
}
},
"setup": {
"customize": {
"header": "Erlebnis anpassen",
"subheader": "Leistenposition, Dichte, Skalierung und mehr einstellen."
},
"appearance": {
"header": "Erscheinungsbild",
"subheader": "Dunkelmodus und Farbquellen wählen (Matugen oder vordefiniert)."
},
"wallpaper": {
"header": "Wähle dein Hintergrundbild",
"subheader": "Bestimme die Stimmung mit einem schönen Hintergrund.",
"select-prompt": "Wähle unten ein Hintergrundbild",
"preview-error": "Bild konnte nicht geladen werden",
"none-in-dir": "Keine Hintergrundbilder im Verzeichnis gefunden",
"no-dir": "Kein Hintergrundbild-Verzeichnis ausgewählt",
"no-valid": "Keine gültigen Bilddateien gefunden in: {dir}",
"choose-dir": "Wähle ein Verzeichnis mit deinen Hintergrundbildern",
"dir": {
"label": "Hintergrundbild-Verzeichnis",
"description": "Wähle den Ordner mit deinen Hintergrundbildern",
"browse": "Ordner auswählen",
"select-title": "Hintergrundbild-Ordner wählen"
}
},
"welcome": {
"note": "Nur ein paar Grundeinstellungen alle Optionen findest du in den Einstellungen"
}
}
}
}
+32 -2
View File
@@ -1305,7 +1305,8 @@
"bottom_left": "Bottom left",
"bottom_right": "Bottom right",
"bottom_center": "Bottom center",
"top_center": "Top center"
"top_center": "Top center",
"center": "Center"
},
"quickSettingsStyle": {
"modern": "Modern",
@@ -1622,5 +1623,34 @@
"lifespan": "Extended lifespan ({percent}%)",
"disabled": "Battery manager disabled"
}
},
"setup": {
"customize": {
"header": "Customize your experience",
"subheader": "Adjust bar position, density, scaling and more."
},
"appearance": {
"header": "Appearance",
"subheader": "Choose dark mode and color sources (Matugen or predefined)."
},
"wallpaper": {
"header": "Choose your wallpaper",
"subheader": "Set the mood with a beautiful background.",
"select-prompt": "Select a wallpaper below",
"preview-error": "Failed to load image",
"none-in-dir": "No wallpapers found in directory",
"no-dir": "No wallpaper directory selected",
"no-valid": "No valid image files found in: {dir}",
"choose-dir": "Choose a directory containing your wallpaper images",
"dir": {
"label": "Wallpaper directory",
"description": "Choose the folder containing your wallpapers",
"browse": "Browse for wallpaper folder",
"select-title": "Select wallpaper folder"
}
},
"welcome": {
"note": "Just a few basics to get you started - full options are in Settings"
}
}
}
}
+32 -2
View File
@@ -1305,7 +1305,8 @@
"bottom_left": "Inferior izquierda",
"bottom_right": "Inferior derecha",
"bottom_center": "Inferior central",
"top_center": "Superior central"
"top_center": "Superior central",
"center": "Centro"
},
"quickSettingsStyle": {
"modern": "Moderno",
@@ -1622,5 +1623,34 @@
"lifespan": "Vida útil prolongada ({percent}%)",
"disabled": "Administrador de batería deshabilitado"
}
},
"setup": {
"customize": {
"header": "Personaliza tu experiencia",
"subheader": "Ajusta la posición de la barra, densidad, escala y más."
},
"appearance": {
"header": "Apariencia",
"subheader": "Elige modo oscuro y fuentes de color (Matugen o predefinido)."
},
"wallpaper": {
"header": "Elige tu fondo",
"subheader": "Define el ambiente con un bonito fondo.",
"select-prompt": "Selecciona un fondo abajo",
"preview-error": "No se pudo cargar la imagen",
"none-in-dir": "No se encontraron fondos en el directorio",
"no-dir": "No se seleccionó un directorio de fondos",
"no-valid": "No se encontraron imágenes válidas en: {dir}",
"choose-dir": "Elige un directorio que contenga tus fondos",
"dir": {
"label": "Directorio de fondos",
"description": "Elige la carpeta que contiene tus fondos",
"browse": "Seleccionar carpeta",
"select-title": "Seleccionar carpeta de fondos"
}
},
"welcome": {
"note": "Solo algunos conceptos básicos para empezar: todas las opciones están en Configuración."
}
}
}
}
+32 -2
View File
@@ -1305,7 +1305,8 @@
"bottom_left": "En bas à gauche",
"bottom_right": "En bas à droite",
"bottom_center": "En bas au centre",
"top_center": "En haut au centre"
"top_center": "En haut au centre",
"center": "Centre"
},
"quickSettingsStyle": {
"modern": "Moderne",
@@ -1622,5 +1623,34 @@
"lifespan": "Durée de vie prolongée ({percent}%)",
"disabled": "Gestionnaire de batterie désactivé"
}
},
"setup": {
"customize": {
"header": "Personnaliser votre expérience",
"subheader": "Ajustez la position de la barre, la densité, l'échelle et plus encore."
},
"appearance": {
"header": "Apparence",
"subheader": "Choisissez le mode sombre et la source des couleurs (Matugen ou prédéfinie)."
},
"wallpaper": {
"header": "Choisissez votre fond d'écran",
"subheader": "Définissez l'ambiance avec un joli fond.",
"select-prompt": "Sélectionnez un fond ci-dessous",
"preview-error": "Échec du chargement de l'image",
"none-in-dir": "Aucun fond d'écran trouvé dans le répertoire",
"no-dir": "Aucun répertoire de fonds d'écran sélectionné",
"no-valid": "Aucun fichier image valide trouvé dans : {dir}",
"choose-dir": "Choisissez un répertoire contenant vos fonds d'écran",
"dir": {
"label": "Répertoire des fonds d'écran",
"description": "Choisissez le dossier contenant vos fonds d'écran",
"browse": "Parcourir le dossier",
"select-title": "Sélectionner le dossier des fonds d'écran"
}
},
"welcome": {
"note": "Quelques réglages de base pour démarrer — toutes les options sont dans Paramètres"
}
}
}
}
+38 -14
View File
@@ -1303,7 +1303,8 @@
"bottom_left": "Inferior esquerdo",
"bottom_right": "Inferior direito",
"bottom_center": "Centro inferior",
"top_center": "Centro superior"
"top_center": "Centro superior",
"center": "Centro"
},
"quickSettingsStyle": {
"modern": "Moderno",
@@ -1615,18 +1616,41 @@
"discharging-rate": "Taxa de descarregamento: {rate} W.",
"charging": "Carregando.",
"discharging": "Descarregando.",
"battery-manager": {
"title": "Limite da bateria",
"set-success-desc": "Limite da bateria definido para {percent}%",
"initial-setup": "Configuração inicial necessária",
"set-failed": "Falha ao definir o limite da bateria",
"install-success": "Instalado com sucesso",
"install-missing": "Arquivos necessários ausentes",
"install-unsupported": "Sistema não suportado",
"install-failed": "Falha na instalação",
"uninstall-setup": "Desinstalando, autenticação necessária",
"uninstall-success": "Desinstalado com sucesso",
"uninstall-failed": "Falha na desinstalação"
"panel": {
"balanced": "Balanceado ({percent}%)",
"disabled": "Gerenciador de bateria desativado",
"full": "Capacidade máxima ({percent}%)",
"lifespan": "Vida útil prolongada ({percent}%)",
"title": "Limite de carga"
}
},
"setup": {
"customize": {
"header": "Personalizar a sua experiência",
"subheader": "Ajuste a posição da barra, densidade, escala e mais."
},
"appearance": {
"header": "Aparência",
"subheader": "Escolha o modo escuro e as fontes de cores (Matugen ou predefinidas)."
},
"wallpaper": {
"header": "Escolha o seu papel de parede",
"subheader": "Defina o ambiente com um belo fundo.",
"select-prompt": "Selecione um papel de parede abaixo",
"preview-error": "Falha ao carregar a imagem",
"none-in-dir": "Nenhum papel de parede encontrado no diretório",
"no-dir": "Nenhum diretório de papéis de parede selecionado",
"no-valid": "Nenhuma imagem válida encontrada em: {dir}",
"choose-dir": "Escolha um diretório contendo seus papéis de parede",
"dir": {
"label": "Diretório de papéis de parede",
"description": "Escolha a pasta que contém seus papéis de parede",
"browse": "Procurar pasta",
"select-title": "Selecionar pasta de papéis de parede"
}
},
"welcome": {
"note": "Apenas alguns ajustes básicos para começar - o restante está em Configurações"
}
}
}
}
+32 -2
View File
@@ -1305,7 +1305,8 @@
"bottom_left": "左下角",
"bottom_right": "右下角",
"bottom_center": "底部居中",
"top_center": "顶部居中"
"top_center": "顶部居中",
"center": "居中"
},
"quickSettingsStyle": {
"modern": "现代",
@@ -1622,5 +1623,34 @@
"lifespan": "延长寿命 ({percent}%)",
"disabled": "电池管理器已禁用"
}
},
"setup": {
"customize": {
"header": "自定义体验",
"subheader": "调整状态栏位置、密度、缩放等。"
},
"appearance": {
"header": "外观",
"subheader": "选择深色模式与配色来源(Matugen 或预设)。"
},
"wallpaper": {
"header": "选择你的壁纸",
"subheader": "用精美壁纸营造氛围。",
"select-prompt": "在下方选择一张壁纸",
"preview-error": "图片加载失败",
"none-in-dir": "目录中未找到壁纸",
"no-dir": "未选择壁纸目录",
"no-valid": "在 {dir} 中未找到有效图片文件",
"choose-dir": "选择包含壁纸图片的目录",
"dir": {
"label": "壁纸目录",
"description": "选择存放壁纸的文件夹",
"browse": "浏览文件夹",
"select-title": "选择壁纸文件夹"
}
},
"welcome": {
"note": "先进行一些基础设置——更多选项可在“设置”中找到"
}
}
}
}
+65
View File
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="256"
height="256"
viewBox="0 0 67.733334 67.733334"
version="1.1"
id="svg1"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1" />
<g
id="g60"
style="fill:#ffffff;fill-opacity:1;stroke:#0e0e43;stroke-width:6.2176;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.0000606,0,0,1.0000606,-5.3736738,-63.880929)">
<g
id="g1"
transform="matrix(0.3457623,0,0,0.3457623,1.8096128,40.073954)"
style="fill:#ffffff;fill-opacity:1;stroke:#0e0e43;stroke-width:17.9823;stroke-dasharray:none;stroke-opacity:1">
<g
id="g2"
style="fill:#ffffff;fill-opacity:1;stroke:#0e0e43;stroke-width:1.4785;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(12.162505,0,0,12.162505,-32.462207,-452.96894)">
<path
id="path1"
style="fill:#ffffff;fill-opacity:1;stroke:#0e0e43;stroke-width:1.4785;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:9.1;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="m 11.646507,43.642549 c -4.038226,8.9e-4 -7.3116325,3.274297 -7.3125227,7.312523 -1.947e-4,4.038993 3.2735294,7.313597 7.3125227,7.314488 3.487073,-0.0084 6.483277,-2.47736 7.158181,-5.898508 -0.620978,1.570892 -1.854119,2.821688 -3.416025,3.464933 0.0015,0.277406 0.0039,0.532472 0.0039,0.726484 -0.739445,0 -1.37585,-0.10185 -1.92189,-0.271448 -0.146668,0.01695 -0.293894,0.02867 -0.441396,0.03514 -3.4356877,2.08e-4 -6.2209147,-2.785019 -6.2207066,-6.220707 -2.081e-4,-3.435688 2.7850189,-6.220915 6.2207066,-6.220707 0.192387,2.18e-4 0.38466,0.0094 0.576199,0.0274 -0.637785,-0.178134 -1.296807,-0.268831 -1.959001,-0.269605 z m -3.1385553,3.085838 c 0.1447941,0.443587 0.436407,0.880884 0.8274942,1.046718 -0.1090884,0.328801 -0.1096117,0.719225 -0.1096117,1.137282 0,0.90457 0.6427321,1.676019 1.5479578,1.983086 -0.329929,-0.04179 -0.632013,-0.123222 -0.8682918,-0.287054 -0.431935,0.07708 -0.6133052,0.557376 -0.5744781,1.118235 0.2769283,4.000144 2.8097509,3.741322 2.8324539,3.734783 -1.853097,-0.904141 -1.549482,-2.377876 -1.610382,-2.847445 0.07631,0.794735 0.926406,3.057084 4.098271,3.057084 0,-0.953411 0.0047,-3.40281 -0.304135,-4.157993 -0.09728,-0.294206 -0.3627,-1.081221 -0.686056,-1.169354 -0.262025,0.29403 -0.643893,0.449619 -1.095011,0.527045 0.867912,-0.322492 1.4773,-1.077475 1.4773,-1.958387 0,-0.418057 -5.29e-4,-0.808481 -0.109612,-1.137282 0.391087,-0.165834 0.682701,-0.603131 0.827494,-1.046718 -0.472651,-0.0073 -1.224795,0.166618 -1.866593,0.187028 -0.321367,-0.08366 -0.733857,-0.129693 -1.260165,-0.130256 -0.526307,5.76e-4 -0.938675,0.04659 -1.260042,0.130256 -0.6417973,-0.02041 -1.3939415,-0.194302 -1.8665933,-0.187028 z" />
</g>
</g>
</g>
<g
id="g55"
style="fill:#fff59b;fill-opacity:1"
transform="matrix(4.2055905,0,0,4.2055905,-14.788898,-180.43362)">
<path
id="path55"
style="fill:#fff59b;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:9.1;stroke-dasharray:none;paint-order:fill markers stroke"
d="m 11.646484,43.642578 a 7.3141356,7.3141356 0 0 0 -7.3124996,7.3125 7.3141356,7.3141356 0 0 0 7.3124996,7.314453 7.3141356,7.3141356 0 0 0 7.158204,-5.898437 6.2203302,6.2203302 0 0 1 -3.416016,3.464844 c 0.0015,0.277406 0.0039,0.53255 0.0039,0.726562 -0.739445,0 -1.375835,-0.101886 -1.921875,-0.271484 a 6.2203302,6.2203302 0 0 1 -0.441406,0.03516 6.2203302,6.2203302 0 0 1 -6.2207032,-6.220703 6.2203302,6.2203302 0 0 1 6.2207032,-6.220703 6.2203302,6.2203302 0 0 1 0.576172,0.02734 7.3141356,7.3141356 0 0 0 -1.958985,-0.269531 z" />
</g>
<path
id="path56"
style="fill:#a9aefe;fill-opacity:1;stroke:none;stroke-width:1.34608;stroke-miterlimit:9.1;paint-order:fill markers stroke"
d="m 42.66444,31.291474 c -1.802882,2.023105 -4.950139,2.492661 -8.5254,2.5028 -2.71816,-0.0077 -5.450476,-0.128227 -7.26956,-1.389551 -1.816542,0.324182 -2.579157,2.344033 -2.415866,4.702777 1.164647,16.822967 11.81672,15.734645 11.912198,15.707145 -7.793366,-3.802447 -6.516498,-10.00048 -6.772622,-11.975293 0.320928,3.34233 3.895926,12.856764 17.235494,12.856764 0,-4.009655 0.01992,-14.311035 -1.27908,-17.487024 -0.409124,-1.237312 -1.52526,-4.546963 -2.885164,-4.917618 z" />
<rect
style="fill:#f3edf7;fill-opacity:1;stroke-width:6.29839;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:6.4"
id="rect3"
width="16.253635"
height="10.520533"
x="25.887611"
y="19.681677" />
<path
id="path57"
style="fill:#a9aefe;fill-opacity:1;stroke:none;stroke-width:3.76565;stroke-miterlimit:9.1;paint-order:fill markers stroke"
d="m 20.992013,16.087004 c 0.608944,1.865545 1.835334,3.704314 3.480086,4.401745 -0.458781,1.382804 -0.460831,3.024949 -0.460831,4.783126 0,4.927895 4.533698,8.919413 10.130359,8.938559 5.596664,-0.01912 10.130367,-4.010667 10.130367,-8.938559 0,-1.758177 -0.0021,-3.400322 -0.460833,-4.783126 1.644753,-0.697431 2.871142,-2.5362 3.480084,-4.401745 -1.987776,-0.0305 -5.150908,0.700757 -7.850047,0.786595 -1.351539,-0.351845 -3.086137,-0.545868 -5.299571,-0.548233 -2.213431,0.0024 -3.948027,0.196367 -5.299568,0.548233 -2.699135,-0.08584 -5.862266,-0.817187 -7.850046,-0.786595 z m 6.777419,4.648053 c 0.55547,-0.01383 1.299779,0.06204 2.304161,0.246319 0.672198,0.123302 1.523536,0.452402 2.034019,0.754813 0.950807,0.563264 1.073595,1.207697 2.034015,1.207697 0.96042,0 1.083207,-0.644433 2.034018,-1.207697 0.510483,-0.302418 1.361822,-0.631511 2.034021,-0.754813 4.591459,-0.842328 3.821732,0.523962 3.821732,2.836505 0,2.387132 -1.935155,4.32229 -4.322291,4.32229 -0.76295,-0.0037 -1.511332,-0.20934 -2.169091,-0.595905 -0.01546,0.03375 -0.02887,0.06484 -0.04768,0.09535 l -0.969338,1.573189 c -0.105239,0.171222 -0.243797,0.257467 -0.381378,0.254251 -0.13758,0.0031 -0.276139,-0.08303 -0.381378,-0.254251 l -0.969338,-1.573189 c -0.01871,-0.0305 -0.03212,-0.06159 -0.04768,-0.09535 -0.657763,0.386585 -1.406142,0.592188 -2.169091,0.595905 -2.387137,0 -4.32229,-1.935158 -4.32229,-4.32229 0,-1.806673 -0.466271,-3.033173 1.517569,-3.082814 z" />
<path
id="path58"
style="fill:none;stroke:#0e0e43;stroke-width:1.22052;stroke-linecap:round;stroke-miterlimit:9.1;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="M 32.3042,25.300596 A 1.9914438,1.9914438 0 0 1 30.579559,26.29632 1.9914438,1.9914438 0 0 1 28.854918,25.300596" />
<path
id="path59"
style="fill:none;stroke:#0e0e43;stroke-width:1.22052;stroke-linecap:round;stroke-miterlimit:9.1;stroke-dasharray:none;stroke-opacity:1;paint-order:fill markers stroke"
d="M 39.428334,25.300596 A 1.9914438,1.9914438 0 0 1 37.703696,26.29632 1.9914438,1.9914438 0 0 1 35.979053,25.300596" />
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

+2 -1
View File
@@ -1,5 +1,6 @@
{
"settingsVersion": 15,
"settingsVersion": 16,
"setupCompleted": false,
"bar": {
"position": "top",
"backgroundOpacity": 1,
+6 -1
View File
@@ -14,6 +14,7 @@ Singleton {
readonly property alias data: adapter
property bool isLoaded: false
property bool directoriesCreated: false
property int settingsVersion: 16
// Define our app directories
// Default config directory: ~/.config/noctalia
@@ -100,6 +101,9 @@ Singleton {
// Emit the signal
root.settingsLoaded()
// Finally, update our local settings version
adapter.settingsVersion = settingsVersion
}
}
onLoadFailed: function (error) {
@@ -125,7 +129,8 @@ Singleton {
JsonAdapter {
id: adapter
property int settingsVersion: 15
property int settingsVersion: root.settingsVersion
property bool setupCompleted: false
// bar
property JsonObject bar: JsonObject {
+6
View File
@@ -128,6 +128,12 @@ Singleton {
"bt-device-watch": "device-watch",
"bt-device-speaker": "device-speaker",
"bt-device-tv": "device-tv",
"antenna-bars-1": "antenna-bars-1",
"antenna-bars-2": "antenna-bars-2",
"antenna-bars-3": "antenna-bars-3",
"antenna-bars-4": "antenna-bars-4",
"antenna-bars-5": "antenna-bars-5",
"antenna-bars-off": "antenna-bars-off",
"noctalia": "noctalia",
"hyprland": "hyprland",
"filepicker-folder": "folder",
@@ -109,7 +109,7 @@ ColumnLayout {
NIcon {
visible: modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked
text: BluetoothService.getSignalIcon(modelData)
icon: BluetoothService.getSignalIcon(modelData)
pointSize: Style.fontSizeXS
color: getContentColor(Color.mOnSurface)
}
+2 -2
View File
@@ -46,8 +46,8 @@ NPanel {
// Positioning
readonly property string controlCenterPosition: Settings.data.controlCenter.position
panelAnchorHorizontalCenter: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.endsWith("_center")
panelAnchorVerticalCenter: false
panelAnchorHorizontalCenter: controlCenterPosition !== "close_to_bar_button" && (controlCenterPosition.endsWith("_center") || controlCenterPosition === "center")
panelAnchorVerticalCenter: controlCenterPosition === "center"
panelAnchorLeft: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.endsWith("_left")
panelAnchorRight: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.endsWith("_right")
panelAnchorBottom: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.startsWith("bottom_")
-1
View File
@@ -336,7 +336,6 @@ ColumnLayout {
NIcon {
icon: "check"
pointSize: Style.fontSizeXS
font.weight: Style.fontWeightBold
color: Color.mOnSecondary
anchors.centerIn: parent
}
@@ -143,6 +143,9 @@ ColumnLayout {
}, {
"key": "top_center",
"name": I18n.tr("options.control-center.position.top_center")
}, {
"key": "center",
"name": I18n.tr("options.control-center.position.center")
}]
currentKey: Settings.data.controlCenter.position
onSelected: function (key) {
+557
View File
@@ -0,0 +1,557 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell.Io
import qs.Commons
import qs.Services
import qs.Widgets
ColumnLayout {
id: root
spacing: Style.marginM
function extractSchemeName(path) {
var basename = path.split('/').pop()
return basename.replace('.json', '')
}
// Cache for scheme colors (mirrors ColorSchemeTab approach)
property var schemeColorsCache: ({})
property int cacheVersion: 0
function getSchemeColor(schemeName, key) {
try {
var mode = Settings.data.colorSchemes.darkMode ? "dark" : "light"
var data = schemeColorsCache[schemeName]
if (data && data[mode] && data[mode][key])
return data[mode][key]
} catch (e) {
}
return Color.mSurfaceVariant
}
// Match ColorSchemeTab helpers
function schemeLoaded(schemeName, jsonData) {
var value = jsonData || {}
schemeColorsCache[schemeName] = value
cacheVersion++
Logger.log("SetupAppearanceStep", `Loaded scheme ${schemeName}`)
}
Connections {
target: ColorSchemeService
function onSchemesChanged() {
Logger.log("SetupAppearanceStep", `Color schemes changed: ${ColorSchemeService.schemes.length}`)
schemeColorsCache = {}
cacheVersion++
}
}
// Beautiful header with icon
RowLayout {
Layout.fillWidth: true
Layout.bottomMargin: Style.marginL
spacing: Style.marginM
Rectangle {
width: 40
height: 40
radius: Style.radiusL
color: Color.mSurfaceVariant
opacity: 0.6
NIcon {
icon: "palette"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginXS
NText {
text: I18n.tr("setup.appearance.header")
pointSize: Style.fontSizeXL
font.weight: Style.fontWeightBold
color: Color.mPrimary
}
NText {
text: I18n.tr("setup.appearance.subheader")
pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
}
}
}
ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
contentWidth: availableWidth
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ColumnLayout {
width: parent.width
spacing: Style.marginM
// Dark Mode Toggle
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
Rectangle {
width: 28
height: 28
radius: Style.radiusM
color: Color.mSurface
NIcon {
icon: "moon"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
NText {
text: I18n.tr("settings.color-scheme.color-source.dark-mode.label")
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: I18n.tr("settings.color-scheme.color-source.dark-mode.description")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
NToggle {
checked: Settings.data.colorSchemes.darkMode
onToggled: checked => Settings.data.colorSchemes.darkMode = checked
}
}
// Divider
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: Color.mOutline
opacity: 0.2
Layout.topMargin: Style.marginS
Layout.bottomMargin: Style.marginS
}
// Wallpaper Colors Toggle
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
Rectangle {
width: 28
height: 28
radius: Style.radiusM
color: Color.mSurface
NIcon {
icon: "color-picker"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
NText {
text: I18n.tr("settings.color-scheme.color-source.use-wallpaper-colors.label")
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: I18n.tr("settings.color-scheme.color-source.use-wallpaper-colors.description")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
NToggle {
enabled: ProgramCheckerService.matugenAvailable
opacity: ProgramCheckerService.matugenAvailable ? 1.0 : 0.6
checked: Settings.data.colorSchemes.useWallpaperColors && ProgramCheckerService.matugenAvailable
onToggled: checked => {
if (!ProgramCheckerService.matugenAvailable)
return
if (checked) {
Settings.data.colorSchemes.useWallpaperColors = true
AppThemeService.generate()
} else {
Settings.data.colorSchemes.useWallpaperColors = false
if (Settings.data.colorSchemes.predefinedScheme) {
ColorSchemeService.applyScheme(Settings.data.colorSchemes.predefinedScheme)
}
}
}
}
}
// Matugen not available notice
RowLayout {
Layout.fillWidth: true
spacing: Style.marginS
visible: !ProgramCheckerService.matugenAvailable
Rectangle {
width: 28
height: 28
radius: Style.radiusM
color: Color.mSurface
NIcon {
icon: "alert-triangle"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
NText {
text: I18n.tr("settings.color-scheme.color-source.use-wallpaper-colors.description")
// Reuse description; availability is visually indicated
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
// Matugen scheme type (visible when wallpaper colors enabled and matugen available)
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginM
visible: Settings.data.colorSchemes.useWallpaperColors && ProgramCheckerService.matugenAvailable
RowLayout {
Layout.fillWidth: true
spacing: Style.marginS
Rectangle {
width: 28
height: 28
radius: Style.radiusM
color: Color.mSurface
NIcon {
icon: "wand"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
NText {
text: I18n.tr("settings.color-scheme.color-source.matugen-scheme-type.label")
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: I18n.tr("settings.color-scheme.color-source.matugen-scheme-type.description")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
}
}
}
// Matugen scheme options styled like bar position buttons
GridLayout {
Layout.fillWidth: true
columns: 2
rowSpacing: Style.marginS
columnSpacing: Style.marginS
Repeater {
model: [{
"key": "scheme-content",
"name": "Content"
}, {
"key": "scheme-expressive",
"name": "Expressive"
}, {
"key": "scheme-fidelity",
"name": "Fidelity"
}, {
"key": "scheme-fruit-salad",
"name": "Fruit Salad"
}, {
"key": "scheme-monochrome",
"name": "Monochrome"
}, {
"key": "scheme-neutral",
"name": "Neutral"
}, {
"key": "scheme-rainbow",
"name": "Rainbow"
}, {
"key": "scheme-tonal-spot",
"name": "Tonal Spot"
}]
delegate: Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 48
radius: Style.radiusM
border.width: 1
property bool isActive: Settings.data.colorSchemes.matugenSchemeType === modelData.key
color: (hoverHandler.hovered || isActive) ? Color.mPrimary : Color.mSurfaceVariant
border.color: (hoverHandler.hovered || isActive) ? Color.mPrimary : Color.mOutline
opacity: (hoverHandler.hovered || isActive) ? 1.0 : 0.8
NText {
text: modelData.name
pointSize: Style.fontSizeM
font.weight: (hoverHandler.hovered || parent.isActive) ? Style.fontWeightBold : Style.fontWeightMedium
color: (hoverHandler.hovered || parent.isActive) ? Color.mOnPrimary : Color.mOnSurface
anchors.centerIn: parent
}
HoverHandler {
id: hoverHandler
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
Settings.data.colorSchemes.matugenSchemeType = modelData.key
AppThemeService.generate()
}
}
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
Behavior on border.color {
ColorAnimation {
duration: Style.animationFast
}
}
Behavior on opacity {
NumberAnimation {
duration: Style.animationFast
}
}
}
}
}
}
// Divider
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: Color.mOutline
opacity: 0.2
Layout.topMargin: Style.marginS
Layout.bottomMargin: Style.marginS
visible: !Settings.data.colorSchemes.useWallpaperColors
}
// Predefined schemes section (visible when wallpaper colors disabled)
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginM
visible: !Settings.data.colorSchemes.useWallpaperColors
RowLayout {
Layout.fillWidth: true
spacing: Style.marginS
Rectangle {
width: 28
height: 28
radius: Style.radiusM
color: Color.mSurface
NIcon {
icon: "palette"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
NText {
text: I18n.tr("settings.color-scheme.predefined.section.label")
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: I18n.tr("settings.color-scheme.predefined.section.description")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
}
}
}
// Predefined schemes Grid (matches ColorSchemeTab)
GridLayout {
id: schemesGrid
columns: Math.max(2, Math.floor((parent.width - Style.marginM * 2) / 180))
rowSpacing: Style.marginM
columnSpacing: Style.marginM
Layout.fillWidth: true
Repeater {
model: ColorSchemeService.schemes
delegate: Rectangle {
id: schemeItem
property string schemePath: modelData
property string schemeName: root.extractSchemeName(modelData)
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
height: 50
radius: Style.radiusS
color: root.cacheVersion >= 0 ? root.getSchemeColor(schemeName, "mSurface") : root.getSchemeColor(schemeName, "mSurface")
border.width: Math.max(1, Style.borderL)
border.color: itemMouseArea.containsMouse ? Color.mTertiary : (Settings.data.colorSchemes.predefinedScheme === schemeName ? Color.mSecondary : Color.mOutline)
RowLayout {
anchors.fill: parent
anchors.margins: Style.marginL
spacing: Style.marginXS
NText {
text: schemeItem.schemeName
pointSize: Style.fontSizeS
font.weight: Style.fontWeightMedium
color: Color.mOnSurface
Layout.fillWidth: true
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WordWrap
maximumLineCount: 1
}
Rectangle {
width: 14
height: 14
radius: width * 0.5
color: root.cacheVersion >= 0 ? (function () {
var mode = Settings.data.colorSchemes.darkMode ? "dark" : "light"
var cached = root.schemeColorsCache[schemeItem.schemeName]
return (cached && cached[mode] && cached[mode].mPrimary) || root.getSchemeColor(schemeItem.schemeName, "mPrimary")
})() : Color.mPrimary
}
Rectangle {
width: 14
height: 14
radius: width * 0.5
color: root.cacheVersion >= 0 ? (function () {
var mode = Settings.data.colorSchemes.darkMode ? "dark" : "light"
var cached = root.schemeColorsCache[schemeItem.schemeName]
return (cached && cached[mode] && cached[mode].mSecondary) || root.getSchemeColor(schemeItem.schemeName, "mSecondary")
})() : Color.mSecondary
}
Rectangle {
width: 14
height: 14
radius: width * 0.5
color: root.cacheVersion >= 0 ? (function () {
var mode = Settings.data.colorSchemes.darkMode ? "dark" : "light"
var cached = root.schemeColorsCache[schemeItem.schemeName]
return (cached && cached[mode] && cached[mode].mTertiary) || root.getSchemeColor(schemeItem.schemeName, "mTertiary")
})() : Color.mTertiary
}
Rectangle {
width: 14
height: 14
radius: width * 0.5
color: root.cacheVersion >= 0 ? (function () {
var mode = Settings.data.colorSchemes.darkMode ? "dark" : "light"
var cached = root.schemeColorsCache[schemeItem.schemeName]
return (cached && cached[mode] && cached[mode].mError) || root.getSchemeColor(schemeItem.schemeName, "mError")
})() : Color.mError
}
}
MouseArea {
id: itemMouseArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
Settings.data.colorSchemes.useWallpaperColors = false
Settings.data.colorSchemes.predefinedScheme = schemeItem.schemeName
ColorSchemeService.applyScheme(Settings.data.colorSchemes.predefinedScheme)
}
}
}
}
}
}
// Bottom spacer
Item {
Layout.fillWidth: true
Layout.preferredHeight: Style.marginL
}
}
}
// Hidden loader to populate schemeColorsCache from files
Item {
visible: false
Repeater {
model: ColorSchemeService.schemes
delegate: Item {
FileView {
path: modelData
blockLoading: false
onLoaded: {
var schemeName = root.extractSchemeName(path)
try {
var jsonData = JSON.parse(text())
root.schemeLoaded(schemeName, jsonData)
} catch (e) {
root.schemeLoaded(schemeName, null)
}
}
}
}
}
}
}
+508
View File
@@ -0,0 +1,508 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
ColumnLayout {
id: root
property real selectedScaleRatio: 1.0
property string selectedBarPosition: "top"
property bool selectedDimDesktop: true
signal scaleRatioChanged(real ratio)
signal barPositionChanged(string position)
signal dimDesktopChanged(bool dim)
spacing: Style.marginM
// Beautiful header with icon
RowLayout {
Layout.fillWidth: true
Layout.bottomMargin: Style.marginL
spacing: Style.marginM
Rectangle {
width: 40
height: 40
radius: Style.radiusL
color: Color.mSurfaceVariant
opacity: 0.6
NIcon {
icon: "palette"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginXS
NText {
text: I18n.tr("setup.customize.header")
pointSize: Style.fontSizeXL
font.weight: Style.fontWeightBold
color: Color.mPrimary
}
NText {
text: I18n.tr("setup.customize.subheader")
pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
}
}
}
ScrollView {
Layout.fillWidth: true
Layout.fillHeight: true
clip: true
contentWidth: availableWidth
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
ScrollBar.vertical.policy: ScrollBar.AsNeeded
ColumnLayout {
width: parent.width
spacing: Style.marginM
// Bar Position section
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginM
RowLayout {
Layout.fillWidth: true
spacing: Style.marginS
Rectangle {
width: 28
height: 28
radius: Style.radiusM
color: Color.mSurface
NIcon {
icon: "layout-2"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
NText {
text: I18n.tr("settings.bar.appearance.position.label")
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: I18n.tr("settings.bar.appearance.position.description")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
}
}
}
RowLayout {
Layout.fillWidth: true
spacing: Style.marginS
Repeater {
model: [{
"key": "top",
"name": I18n.tr("options.bar.position.top"),
"icon": "arrow-up"
}, {
"key": "bottom",
"name": I18n.tr("options.bar.position.bottom"),
"icon": "arrow-down"
}, {
"key": "left",
"name": I18n.tr("options.bar.position.left"),
"icon": "arrow-left"
}, {
"key": "right",
"name": I18n.tr("options.bar.position.right"),
"icon": "arrow-right"
}]
delegate: Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 40
radius: Style.radiusM
border.width: 1
property bool isActive: selectedBarPosition === modelData.key
color: (hoverHandler.hovered || isActive) ? Color.mPrimary : Color.mSurfaceVariant
border.color: (hoverHandler.hovered || isActive) ? Color.mPrimary : Color.mOutline
opacity: (hoverHandler.hovered || isActive) ? 1.0 : 0.8
NText {
text: modelData.name
pointSize: Style.fontSizeM
font.weight: (hoverHandler.hovered || parent.isActive) ? Style.fontWeightBold : Style.fontWeightMedium
color: (hoverHandler.hovered || parent.isActive) ? Color.mOnPrimary : Color.mOnSurface
anchors.centerIn: parent
}
HoverHandler {
id: hoverHandler
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
selectedBarPosition = modelData.key
barPositionChanged(modelData.key)
}
}
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
Behavior on border.color {
ColorAnimation {
duration: Style.animationFast
}
}
Behavior on opacity {
NumberAnimation {
duration: Style.animationFast
}
}
}
}
}
}
// Divider
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: Color.mOutline
opacity: 0.2
Layout.topMargin: Style.marginS
Layout.bottomMargin: Style.marginS
}
// Dim Desktop section
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
Rectangle {
width: 32
height: 32
radius: Style.radiusM
color: Color.mSurface
NIcon {
icon: "moon"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
NText {
text: I18n.tr("settings.user-interface.dim-desktop.label")
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: I18n.tr("settings.user-interface.dim-desktop.description")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
NToggle {
checked: selectedDimDesktop
onToggled: function (checked) {
selectedDimDesktop = checked
dimDesktopChanged(checked)
}
}
}
// Divider
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: Color.mOutline
opacity: 0.2
Layout.topMargin: Style.marginS
Layout.bottomMargin: Style.marginS
}
// Bar Density section
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
Rectangle {
width: 32
height: 32
radius: Style.radiusM
color: Color.mSurface
NIcon {
icon: "minimize"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
NText {
text: I18n.tr("settings.bar.appearance.density.label")
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: I18n.tr("settings.bar.appearance.density.description")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
RowLayout {
spacing: Style.marginS
Repeater {
model: [{
"key": "mini",
"name": I18n.tr("options.bar.density.mini")
}, {
"key": "compact",
"name": I18n.tr("options.bar.density.compact")
}, {
"key": "default",
"name": I18n.tr("options.bar.density.default")
}, {
"key": "comfortable",
"name": I18n.tr("options.bar.density.comfortable")
}]
delegate: Rectangle {
radius: 16
border.width: 1
Layout.preferredHeight: 32
Layout.preferredWidth: Math.max(90, densityText.implicitWidth + Style.marginXL * 2)
property bool isActive: Settings.data.bar.density === modelData.key
color: (hoverHandler.hovered || isActive) ? Color.mPrimary : Color.mSurfaceVariant
border.color: (hoverHandler.hovered || isActive) ? Color.mPrimary : Color.mOutline
opacity: (hoverHandler.hovered || isActive) ? 1.0 : 0.8
NText {
id: densityText
text: modelData.name
pointSize: Style.fontSizeS
font.weight: (hoverHandler.hovered || parent.isActive) ? Style.fontWeightBold : Style.fontWeightMedium
color: (hoverHandler.hovered || parent.isActive) ? Color.mOnPrimary : Color.mOnSurface
anchors.centerIn: parent
}
HoverHandler {
id: hoverHandler
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
Settings.data.bar.density = modelData.key
}
}
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
Behavior on border.color {
ColorAnimation {
duration: Style.animationFast
}
}
Behavior on opacity {
NumberAnimation {
duration: Style.animationFast
}
}
}
}
}
}
// Divider
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: Color.mOutline
opacity: 0.2
Layout.topMargin: Style.marginS
Layout.bottomMargin: Style.marginS
}
// UI Scale section
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginM
RowLayout {
Layout.fillWidth: true
spacing: Style.marginS
Rectangle {
width: 32
height: 32
radius: Style.radiusM
color: Color.mSurface
NIcon {
icon: "maximize"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
NText {
text: I18n.tr("settings.user-interface.scaling.label")
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: I18n.tr("settings.user-interface.scaling.description")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
}
}
}
NValueSlider {
Layout.fillWidth: true
from: 0.8
to: 1.2
stepSize: 0.05
value: selectedScaleRatio
onMoved: function (value) {
selectedScaleRatio = value
scaleRatioChanged(value)
}
text: Math.floor(selectedScaleRatio * 100) + "%"
}
}
// Divider
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: Color.mOutline
opacity: 0.2
Layout.topMargin: Style.marginS
Layout.bottomMargin: Style.marginS
}
// Bar Floating toggle
RowLayout {
Layout.fillWidth: true
spacing: Style.marginM
Rectangle {
width: 32
height: 32
radius: Style.radiusM
color: Color.mSurface
NIcon {
icon: "layout-2"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 2
NText {
text: I18n.tr("settings.bar.appearance.floating.label")
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: I18n.tr("settings.bar.appearance.floating.description")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
NToggle {
checked: Settings.data.bar.floating
onToggled: function (checked) {
Settings.data.bar.floating = checked
}
}
}
// Divider
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: Color.mOutline
opacity: 0.2
Layout.topMargin: Style.marginS
Layout.bottomMargin: Style.marginS
}
// Bar Background Opacity
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginM
NLabel {
label: I18n.tr("settings.bar.appearance.background-opacity.label")
description: I18n.tr("settings.bar.appearance.background-opacity.description")
}
NValueSlider {
Layout.fillWidth: true
from: 0
to: 1
stepSize: 0.01
value: Settings.data.bar.backgroundOpacity
onMoved: function (value) {
Settings.data.bar.backgroundOpacity = value
}
text: Math.floor(Settings.data.bar.backgroundOpacity * 100) + "%"
}
}
Item {
Layout.fillWidth: true
Layout.preferredHeight: Style.marginL
}
}
}
}
+508
View File
@@ -0,0 +1,508 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Effects
import Quickshell
import Quickshell.Io
import qs.Commons
import qs.Services
import qs.Widgets
import "../../Helpers/FuzzySort.js" as FuzzySort
ColumnLayout {
id: root
property string selectedDirectory: ""
property string selectedWallpaper: ""
signal directoryChanged(string directory)
signal wallpaperChanged(string wallpaper)
spacing: Style.marginL
// Beautiful header with icon
ColumnLayout {
Layout.fillWidth: true
Layout.bottomMargin: Style.marginL
spacing: Style.marginM
RowLayout {
spacing: Style.marginM
Rectangle {
width: 40
height: 40
radius: Style.radiusL
color: Color.mSurfaceVariant
opacity: 0.6
NIcon {
icon: "image"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
ColumnLayout {
spacing: Style.marginXS
NText {
text: I18n.tr("setup.wallpaper.header")
pointSize: Style.fontSizeXL
font.weight: Style.fontWeightBold
color: Color.mPrimary
}
NText {
text: I18n.tr("setup.wallpaper.subheader")
pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
}
}
}
}
// Large preview with rounded corners and shadow effect
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: 180
color: Color.mSurfaceVariant
radius: Style.radiusL
border.color: selectedWallpaper !== "" ? Color.mPrimary : Color.mOutline
border.width: selectedWallpaper !== "" ? 2 : 1
clip: true
// Mirror WallpaperPanel approach with rounded shader mask
NImageCached {
id: previewCached
anchors.fill: parent
anchors.margins: 4
maxCacheDimension: 512
cacheFolder: Settings.cacheDirImagesWallpapers
imagePath: selectedWallpaper !== "" ? "file://" + selectedWallpaper : ""
visible: false // used as texture source for the shader
}
ShaderEffect {
anchors.fill: parent
anchors.margins: 4
property var source: ShaderEffectSource {
sourceItem: previewCached
hideSource: true
live: true
recursive: false
format: ShaderEffectSource.RGBA
}
property real itemWidth: width
property real itemHeight: height
property real cornerRadius: Style.radiusL
property real imageOpacity: 1.0
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/rounded_image.frag.qsb")
supportsAtlasTextures: false
blending: true
}
// Loading placeholder
Rectangle {
anchors.fill: parent
color: Color.mSurfaceVariant
radius: Style.radiusL
visible: (previewCached.status === Image.Loading || previewCached.status === Image.Null) && selectedWallpaper !== ""
NIcon {
icon: "image"
pointSize: Style.fontSizeXXL
color: Color.mOnSurfaceVariant
anchors.centerIn: parent
}
}
// Error placeholder
Rectangle {
anchors.fill: parent
color: Color.mError
opacity: 0.1
radius: Style.radiusL
visible: previewCached.status === Image.Error && selectedWallpaper !== ""
ColumnLayout {
anchors.centerIn: parent
spacing: Style.marginS
NIcon {
icon: "alert-circle"
pointSize: Style.fontSizeXXL
color: Color.mError
Layout.alignment: Qt.AlignHCenter
}
NText {
text: I18n.tr("setup.wallpaper.preview-error")
pointSize: Style.fontSizeS
color: Color.mError
Layout.alignment: Qt.AlignHCenter
}
}
}
NBusyIndicator {
anchors.centerIn: parent
visible: (previewCached.status === Image.Loading || previewCached.status === Image.Null) && selectedWallpaper !== ""
running: visible
size: 28
}
ColumnLayout {
anchors.centerIn: parent
spacing: Style.marginL
visible: selectedWallpaper === ""
opacity: 0.6
Rectangle {
Layout.alignment: Qt.AlignHCenter
width: 64
height: 64
radius: width / 2
color: Color.mPrimary
opacity: 0.15
NIcon {
icon: "sparkles"
pointSize: Style.fontSizeXXL
color: Color.mPrimary
anchors.centerIn: parent
}
}
NText {
text: I18n.tr("setup.wallpaper.select-prompt")
pointSize: Style.fontSizeL
color: Color.mOnSurfaceVariant
Layout.alignment: Qt.AlignHCenter
font.weight: Style.fontWeightMedium
}
}
Behavior on border.color {
ColorAnimation {
duration: Style.animationFast
}
}
}
// Wallpaper gallery strip
Item {
Layout.fillWidth: true
Layout.preferredHeight: 90
visible: filteredWallpapers.length > 0
ScrollView {
anchors.fill: parent
clip: true
ScrollBar.horizontal.policy: ScrollBar.AsNeeded
ScrollBar.vertical.policy: ScrollBar.AlwaysOff
RowLayout {
spacing: Style.marginM
height: parent.height
Repeater {
model: filteredWallpapers
delegate: Rectangle {
Layout.preferredWidth: 120
Layout.preferredHeight: 80
color: Color.mSurface
radius: Style.radiusM
border.color: selectedWallpaper === modelData ? Color.mPrimary : Color.mOutline
border.width: selectedWallpaper === modelData ? 2 : 1
clip: true
// Cached thumbnail (used as shader source)
NImageCached {
id: thumbCached
anchors.fill: parent
anchors.margins: 3
maxCacheDimension: 256
cacheFolder: Settings.cacheDirImagesWallpapers
imagePath: "file://" + modelData
visible: false
}
ShaderEffect {
anchors.fill: parent
anchors.margins: 3
property var source: ShaderEffectSource {
sourceItem: thumbCached
hideSource: true
live: true
recursive: false
format: ShaderEffectSource.RGBA
}
property real itemWidth: width
property real itemHeight: height
property real cornerRadius: Style.radiusM - 3
property real imageOpacity: 1.0
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/rounded_image.frag.qsb")
supportsAtlasTextures: false
blending: true
}
// Loading state
Rectangle {
anchors.fill: parent
color: Color.mSurfaceVariant
radius: Style.radiusM
visible: thumbCached.status === Image.Loading
NIcon {
icon: "image"
pointSize: Style.fontSizeL
color: Color.mOnSurfaceVariant
anchors.centerIn: parent
}
}
// Error state
Rectangle {
anchors.fill: parent
color: Color.mSurfaceVariant
radius: Style.radiusM
visible: thumbCached.status === Image.Error
NIcon {
icon: "image"
pointSize: Style.fontSizeL
color: Color.mOnSurfaceVariant
anchors.centerIn: parent
}
}
NBusyIndicator {
anchors.centerIn: parent
visible: thumbCached.status === Image.Loading || thumbCached.status === Image.Null
running: visible
size: 18
}
Rectangle {
anchors.fill: parent
color: Color.mPrimary
opacity: hoverHandler.hovered ? 0.1 : 0
radius: Style.radiusM
Behavior on opacity {
NumberAnimation {
duration: Style.animationFast
}
}
}
Rectangle {
visible: selectedWallpaper === modelData
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 6
width: 24
height: 24
radius: width / 2
color: Color.mPrimary
NIcon {
icon: "check"
pointSize: Style.fontSizeS
color: Color.mOnPrimary
anchors.centerIn: parent
}
}
HoverHandler {
id: hoverHandler
}
TapHandler {
onTapped: {
selectedWallpaper = modelData
wallpaperChanged(modelData)
}
}
}
}
}
}
}
// Helpful info card
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 80
color: Color.mSurfaceVariant
radius: Style.radiusM
opacity: 0.4
visible: filteredWallpapers.length === 0
RowLayout {
anchors.fill: parent
anchors.margins: Style.marginL
spacing: Style.marginM
NIcon {
icon: "folder-open"
pointSize: Style.fontSizeL
color: Color.mOnSurfaceVariant
}
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginXS
NText {
text: filteredWallpapers.length === 0 && selectedDirectory !== "" ? I18n.tr("setup.wallpaper.none-in-dir") : I18n.tr("setup.wallpaper.no-dir")
pointSize: Style.fontSizeM
font.weight: Style.fontWeightBold
color: Color.mOnSurfaceVariant
}
NText {
text: selectedDirectory !== "" ? I18n.tr("setup.wallpaper.no-valid", {
"dir": selectedDirectory
}) : I18n.tr("setup.wallpaper.choose-dir")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
opacity: 0.8
}
}
}
}
// Directory selection
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginM
NTextInputButton {
id: wallpaperPathInput
label: I18n.tr("setup.wallpaper.dir.label")
description: I18n.tr("setup.wallpaper.dir.description")
text: selectedDirectory
buttonIcon: "folder-open"
buttonTooltip: I18n.tr("setup.wallpaper.dir.browse")
Layout.fillWidth: true
onInputEditingFinished: {
selectedDirectory = text
directoryChanged(text)
}
onButtonClicked: directoryPicker.open()
}
}
// Internal properties and functions
property list<string> wallpapersList: []
property list<string> filteredWallpapers: []
function updateFilteredWallpapers() {
filteredWallpapers = wallpapersList
}
function refreshWallpapers() {
if (!selectedDirectory || selectedDirectory === "") {
wallpapersList = []
filteredWallpapers = []
return
}
if (typeof WallpaperService !== "undefined" && WallpaperService.getWallpapersList) {
var wallpapers = WallpaperService.getWallpapersList(Screen.name)
wallpapersList = wallpapers
updateFilteredWallpapers()
if (wallpapersList.length > 0 && selectedWallpaper === "") {
selectedWallpaper = wallpapersList[0]
}
} else {
readDirectoryImages(selectedDirectory)
}
}
function readDirectoryImages(directoryPath) {
directoryScanner.command = ["find", directoryPath, "-type", "f", "\\(-iname", "*.jpg", "-o", "-iname", "*.jpeg", "-o", "-iname", "*.png", "-o", "-iname", "*.bmp", "-o", "-iname", "*.webp", "-o", "-iname", "*.svg", "\\)"]
directoryScanner.running = true
return []
}
onSelectedDirectoryChanged: {
if (typeof Settings !== "undefined" && Settings.data && Settings.data.wallpaper) {
Settings.data.wallpaper.directory = selectedDirectory
}
if (typeof WallpaperService !== "undefined" && WallpaperService.refreshWallpapersList) {
WallpaperService.refreshWallpapersList()
}
Qt.callLater(refreshWallpapers)
}
Connections {
target: WallpaperService
enabled: typeof WallpaperService !== "undefined"
function onWallpaperListChanged(screenName, count) {
if (screenName === Screen.name) {
Qt.callLater(refreshWallpapers)
}
}
}
Timer {
id: initialRefreshTimer
interval: 1000
running: false
repeat: false
onTriggered: refreshWallpapers()
}
Component.onCompleted: {
if (typeof Settings !== "undefined" && Settings.data && Settings.data.wallpaper && Settings.data.wallpaper.directory) {
selectedDirectory = Settings.data.wallpaper.directory
} else {
selectedDirectory = Quickshell.env("HOME") + "/Pictures/Wallpapers"
}
if (typeof WallpaperService !== "undefined" && WallpaperService.currentWallpaper) {
selectedWallpaper = WallpaperService.currentWallpaper
}
initialRefreshTimer.start()
}
NFilePicker {
id: directoryPicker
selectionMode: "folders"
title: I18n.tr("setup.wallpaper.dir.select-title")
initialPath: selectedDirectory || Quickshell.env("HOME") + "/Pictures"
onAccepted: paths => {
if (paths.length > 0) {
selectedDirectory = paths[0]
directoryChanged(paths[0])
}
}
}
Process {
id: directoryScanner
command: ["find", "", "-type", "f", "\\(-iname", "*.jpg", "-o", "-iname", "*.jpeg", "-o", "-iname", "*.png", "-o", "-iname", "*.bmp", "-o", "-iname", "*.webp", "-o", "-iname", "*.svg", "\\)"]
running: false
stdout: StdioCollector {}
stderr: StdioCollector {}
onExited: function (exitCode) {
if (exitCode === 0) {
var lines = stdout.text.split('\n')
var images = []
for (var i = 0; i < lines.length; i++) {
var line = lines[i].trim()
if (line !== '') {
images.push(line)
}
}
wallpapersList = images
updateFilteredWallpapers()
if (wallpapersList.length > 0 && selectedWallpaper === "") {
selectedWallpaper = wallpapersList[0]
}
}
}
}
}
+414
View File
@@ -0,0 +1,414 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import qs.Commons
import qs.Services
import qs.Widgets
NPanel {
id: root
preferredWidth: 520
preferredHeight: 600
preferredWidthRatio: 0.4
preferredHeightRatio: 0.6
panelAnchorHorizontalCenter: true
panelAnchorVerticalCenter: true
panelKeyboardFocus: true
// Prevent closing during setup
backgroundClickEnabled: false
draggable: false
property int currentStep: 0
property int totalSteps: 4
// Setup wizard data
property string selectedWallpaperDirectory: Settings.defaultWallpapersDirectory
property string selectedWallpaper: ""
property real selectedScaleRatio: 1.0
property string selectedBarPosition: "top"
property bool selectedDimDesktop: true
panelContent: Component {
Item {
id: container
anchors.fill: parent
ColumnLayout {
id: wizardContent
anchors.fill: parent
anchors.margins: Style.marginXL
spacing: Style.marginL
// Override ESC key to prevent closing during setup
Shortcut {
sequences: ["Escape"]
enabled: root.active
onActivated: {
// Do nothing - prevent ESC from closing the setup wizard
}
context: Qt.WindowShortcut
}
// Step content - takes most of the space
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: 300
StackLayout {
id: stepStack
anchors.fill: parent
currentIndex: currentStep
// Step 0: Welcome - Beautiful centered design
Item {
ColumnLayout {
anchors.centerIn: parent
width: Math.min(parent.width - Style.marginXL * 2, 420)
spacing: Style.marginXL
// Logo with subtle glow effect
Item {
Layout.fillWidth: true
Layout.preferredHeight: 120
Layout.alignment: Qt.AlignHCenter
Rectangle {
anchors.centerIn: parent
width: 120
height: 120
radius: width / 2
color: Color.mPrimary
opacity: 0.08
scale: 1.3
}
Image {
anchors.centerIn: parent
width: 110
height: 110
source: Qt.resolvedUrl(Quickshell.shellDir + "/Assets/noctalia.svg")
fillMode: Image.PreserveAspectFit
smooth: true
Rectangle {
anchors.fill: parent
color: Color.mSurfaceVariant
radius: width / 2
border.color: Color.mOutline
border.width: 2
visible: parent.status === Image.Error
NIcon {
icon: "sparkles"
pointSize: Style.fontSizeXXL * 1.5
color: Color.mPrimary
anchors.centerIn: parent
}
}
// Subtle pulse animation
SequentialAnimation on scale {
running: true
loops: Animation.Infinite
NumberAnimation {
from: 1.0
to: 1.05
duration: 2000
easing.type: Easing.InOutQuad
}
NumberAnimation {
from: 1.05
to: 1.0
duration: 2000
easing.type: Easing.InOutQuad
}
}
}
}
// Welcome text with gradient feel
ColumnLayout {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter
spacing: Style.marginM
NText {
text: "Welcome to Noctalia! ✨"
pointSize: Style.fontSizeXXL * 1.4
font.weight: Style.fontWeightBold
color: Color.mOnSurface
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
}
NText {
text: "Let's make your desktop uniquely yours"
pointSize: Style.fontSizeL
color: Color.mOnSurfaceVariant
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
// Friendly subtext
Rectangle {
Layout.fillWidth: true
Layout.topMargin: Style.marginL
Layout.preferredHeight: childrenRect.height + Style.marginM * 2
color: Color.mSurfaceVariant
radius: Style.radiusL
opacity: 0.4
NText {
anchors.centerIn: parent
width: parent.width - Style.marginL * 2
text: I18n.tr("setup.welcome.note")
pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.WordWrap
}
}
}
}
}
// Step 1: Wallpaper Setup
SetupWallpaperStep {
id: step1
selectedDirectory: root.selectedWallpaperDirectory
selectedWallpaper: root.selectedWallpaper
onDirectoryChanged: function (directory) {
root.selectedWallpaperDirectory = directory
root.applyWallpaperSettings()
}
onWallpaperChanged: function (wallpaper) {
root.selectedWallpaper = wallpaper
root.applyWallpaperSettings()
}
}
// Step 2: UI Configuration
SetupCustomizeStep {
id: step2
selectedScaleRatio: root.selectedScaleRatio
selectedBarPosition: root.selectedBarPosition
selectedDimDesktop: root.selectedDimDesktop
onScaleRatioChanged: function (ratio) {
root.selectedScaleRatio = ratio
root.applyUISettings()
}
onBarPositionChanged: function (position) {
root.selectedBarPosition = position
root.applyUISettings()
}
onDimDesktopChanged: function (dim) {
root.selectedDimDesktop = dim
root.applyUISettings()
}
}
// Step 3: Appearance - Dark mode and color source
SetupAppearanceStep {
id: step3
}
}
}
// Elegant divider
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: Color.mOutline
opacity: 0.2
}
// Modern progress indicator with labels
Item {
Layout.fillWidth: true
Layout.preferredHeight: 32
RowLayout {
anchors.centerIn: parent
spacing: Style.marginM
Repeater {
model: [{
"icon": "sparkles",
"label": "Welcome"
}, {
"icon": "image",
"label": "Wallpaper"
}, {
"icon": "settings",
"label": "Customize"
}, {
"icon": "palette",
"label": "Appearance"
}]
delegate: RowLayout {
spacing: Style.marginS
Rectangle {
width: 24
height: 24
radius: width / 2
color: index <= currentStep ? Color.mPrimary : Color.mSurfaceVariant
border.color: index === currentStep ? Color.mPrimary : "transparent"
border.width: index === currentStep ? 2 : 0
NIcon {
icon: modelData.icon
pointSize: Style.fontSizeS
color: index <= currentStep ? Color.mOnPrimary : Color.mOnSurfaceVariant
anchors.centerIn: parent
}
Behavior on color {
ColorAnimation {
duration: Style.animationNormal
}
}
}
NText {
text: modelData.label
pointSize: Style.fontSizeS
color: index <= currentStep ? Color.mPrimary : Color.mOnSurfaceVariant
font.weight: index === currentStep ? Style.fontWeightBold : Style.fontWeightRegular
Behavior on color {
ColorAnimation {
duration: Style.animationNormal
}
}
}
// Connector line
Rectangle {
width: 40
height: 2
radius: 1
color: index < currentStep ? Color.mPrimary : Color.mSurfaceVariant
visible: index < totalSteps - 1
Behavior on color {
ColorAnimation {
duration: Style.animationNormal
}
}
}
}
}
}
}
// Smooth navigation buttons
Item {
Layout.fillWidth: true
Layout.preferredHeight: 44
Layout.topMargin: Style.marginS
RowLayout {
anchors.fill: parent
spacing: Style.marginM
NButton {
text: "Skip Setup"
outlined: true
visible: currentStep === 0
Layout.preferredHeight: 44
onClicked: {
root.completeSetup()
}
}
Item {
Layout.fillWidth: true
}
NButton {
text: "← Back"
outlined: true
visible: currentStep > 0
Layout.preferredHeight: 44
onClicked: {
if (currentStep > 0) {
currentStep--
}
}
}
NButton {
text: currentStep === totalSteps - 1 ? "All Done!" : "Continue →"
Layout.preferredHeight: 44
onClicked: {
if (currentStep < totalSteps - 1) {
currentStep++
} else {
root.completeSetup()
}
}
}
}
}
}
}
}
function completeSetup() {
Logger.log("SetupWizard", "Completing setup with selected options")
if (selectedWallpaperDirectory !== Settings.data.wallpaper.directory) {
Settings.data.wallpaper.directory = selectedWallpaperDirectory
WallpaperService.refreshWallpapersList()
}
if (selectedWallpaper !== "") {
WallpaperService.changeWallpaper(selectedWallpaper, undefined)
}
Settings.data.general.scaleRatio = selectedScaleRatio
Settings.data.bar.position = selectedBarPosition
Settings.data.general.dimDesktop = selectedDimDesktop
Settings.data.setupCompleted = true
Settings.saveImmediate()
Logger.log("SetupWizard", "Setup completed successfully")
root.close()
}
function applyWallpaperSettings() {
if (selectedWallpaperDirectory !== Settings.data.wallpaper.directory) {
Settings.data.wallpaper.directory = selectedWallpaperDirectory
WallpaperService.refreshWallpapersList()
}
if (selectedWallpaper !== "") {
WallpaperService.changeWallpaper(selectedWallpaper, undefined)
}
}
function applyUISettings() {
Settings.data.general.scaleRatio = selectedScaleRatio
Settings.data.bar.position = selectedBarPosition
Settings.data.general.dimDesktop = selectedDimDesktop
}
Component.onCompleted: {
Logger.log("SetupWizard", "Setup wizard opened")
// Initialize selections from existing settings to avoid overwriting user config
if (Settings && Settings.data) {
selectedScaleRatio = Settings.data.general.scaleRatio
selectedBarPosition = Settings.data.bar.position
selectedDimDesktop = Settings.data.general.dimDesktop
selectedWallpaperDirectory = Settings.data.wallpaper.directory || Settings.defaultWallpapersDirectory
}
}
}
-1
View File
@@ -423,7 +423,6 @@ NPanel {
NIcon {
icon: "check"
pointSize: Style.fontSizeM
font.weight: Style.fontWeightBold
color: Color.mOnSecondary
anchors.centerIn: parent
}
+1 -1
View File
@@ -105,8 +105,8 @@ Singleton {
// Wallpaper Colors Generation
// --------------------------------------------------------------------------------
function generateFromWallpaper() {
Logger.log("AppThemeService", "Generating from wallpaper on screen:", Screen.name)
// Logger.log("AppThemeService", "Generating from wallpaper on screen:", Screen.name)
const wp = WallpaperService.getWallpaper(Screen.name).replace(/'/g, "'\\''")
if (!wp) {
Logger.error("AppThemeService", "No wallpaper found")
+1 -1
View File
@@ -60,7 +60,6 @@ Singleton {
if (enabled) {
setChargingMode(BatteryService.ChargingMode.Full)
} else {
BatteryService.chargingMode = BatteryService.ChargingMode.Disabled
BatteryService.initialSetter = true
ToastService.showNotice(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.uninstall-setup"))
PanelService.getPanel("batteryPanel")?.toggle(this)
@@ -194,6 +193,7 @@ Singleton {
Logger.log("BatteryService", "Battery Manager uninstalled successfully")
ToastService.showNotice(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.uninstall-success"))
Settings.data.battery.chargingMode = BatteryService.chargingMode
BatteryService.chargingMode = BatteryService.ChargingMode.Disabled
cleanupProcess.running = true
} else {
ToastService.showError(I18n.tr("toast.battery-manager.title"), I18n.tr("toast.battery-manager.uninstall-failed"))
+6 -6
View File
@@ -171,22 +171,22 @@ Singleton {
function getSignalIcon(device) {
if (!device || device.signalStrength === undefined || device.signalStrength <= 0) {
return "signal_cellular_null"
return "antenna-bars-off"
}
var signal = device.signalStrength
if (signal >= 80) {
return "signal_cellular_4_bar"
return "antenna-bars-5"
}
if (signal >= 60) {
return "signal_cellular_3_bar"
return "antenna-bars-4"
}
if (signal >= 40) {
return "signal_cellular_2_bar"
return "antenna-bars-3"
}
if (signal >= 20) {
return "signal_cellular_1_bar"
return "antenna-bars-2"
}
return "signal_cellular_0_bar"
return "antenna-bars-1"
}
function isDeviceBusy(device) {
+7
View File
@@ -38,12 +38,19 @@ Singleton {
let allPlayers = Mpris.players.values
let finalPlayers = []
const genericBrowsers = ["firefox", "chromium", "chrome"]
const blacklist = (Settings.data.audio && Settings.data.audio.mprisBlacklist) ? Settings.data.audio.mprisBlacklist : []
// Separate players into specific and generic lists
let specificPlayers = []
let genericPlayers = []
for (var i = 0; i < allPlayers.length; i++) {
const identity = String(allPlayers[i].identity || "").toLowerCase()
const match = blacklist.find(b => {
const s = String(b || "").toLowerCase()
return s && (identity.includes(s))
})
if (match)
continue
if (genericBrowsers.some(b => identity.includes(b))) {
genericPlayers.push(allPlayers[i])
} else {
-1
View File
@@ -61,7 +61,6 @@ RowLayout {
icon: "check"
color: root.activeOnColor
pointSize: Math.max(Style.fontSizeXS, root.baseSize * 0.5)
font.weight: Style.fontWeightBold
}
MouseArea {
-1
View File
@@ -624,7 +624,6 @@ Popup {
NIcon {
icon: "filepicker-check"
pointSize: Style.fontSizeS
font.weight: Style.fontWeightBold
color: Color.mOnSecondary
anchors.centerIn: parent
}
+18 -2
View File
@@ -31,8 +31,9 @@ Image {
}
onCachePathChanged: {
if (imageHash && cachePath) {
// Try to load the cached version, failure will be detected below in onStatusChanged
source = cachePath
// Check if cache file exists before trying to load it
cacheChecker.command = ["test", "-f", cachePath]
cacheChecker.running = true
}
}
onStatusChanged: {
@@ -48,4 +49,19 @@ Image {
})
}
}
// Check if cache file exists to avoid warnings
Process {
id: cacheChecker
running: false
onExited: function (exitCode) {
if (exitCode === 0 && root.cachePath) {
// Cache file exists, load it
root.source = root.cachePath
} else if (root.imagePath) {
// Cache doesn't exist, load original directly
root.source = root.imagePath
}
}
}
}
-1
View File
@@ -217,7 +217,6 @@ Item {
icon: "check"
color: root.activeOnColor
pointSize: Math.max(Style.fontSizeXS, root.baseSize * 0.5)
font.weight: Style.fontWeightBold
}
MouseArea {
+6 -2
View File
@@ -49,9 +49,13 @@
nixpkgs.legacyPackages.${pkgs.system}.app2unit;
};
nixosModules.default = {pkgs, ...}: {
nixosModules.default = {
pkgs,
lib,
...
}: {
imports = [./nix/nixos-module.nix];
services.noctalia-shell.package = self.packages.${pkgs.system}.default;
services.noctalia-shell.package = lib.mkDefault self.packages.${pkgs.system}.default;
};
};
}
+29
View File
@@ -40,6 +40,7 @@ import qs.Modules.OSD
import qs.Modules.Settings
import qs.Modules.Toast
import qs.Modules.Wallpaper
import qs.Modules.SetupWizard
ShellRoot {
id: shellRoot
@@ -168,4 +169,32 @@ ShellRoot {
}
}
}
// ------------------------------
// Setup Wizard
Loader {
id: setupWizardLoader
active: false
asynchronous: true
sourceComponent: SetupWizard {}
onLoaded: {
if (setupWizardLoader.item && setupWizardLoader.item.open) {
setupWizardLoader.item.open()
}
}
}
Connections {
target: Settings
function onSettingsLoaded() {
// Only open the setup wizard for new users
if (!Settings.data.setupCompleted) {
if (Settings.data.settingsVersion >= Settings.settingsVersion) {
setupWizardLoader.active = true
} else {
Settings.data.setupCompleted = true
}
}
}
}
}