diff --git a/Modals/SettingsModal.qml b/Modals/SettingsModal.qml index fa97583f..3e9fa521 100644 --- a/Modals/SettingsModal.qml +++ b/Modals/SettingsModal.qml @@ -153,9 +153,6 @@ DankModal { }, { "text": "Theme & Colors", "icon": "palette" - }, { - "text": "System Themes", - "icon": "extension" }, { "text": "About", "icon": "info" @@ -328,21 +325,11 @@ DankModal { sourceComponent: ThemeColorsTab {} } - Loader { - id: systemThemesLoader - - anchors.fill: parent - active: sidebarContainer.currentIndex === 8 - visible: active - asynchronous: true - sourceComponent: SystemThemesTab {} - } - Loader { id: aboutLoader anchors.fill: parent - active: sidebarContainer.currentIndex === 9 + active: sidebarContainer.currentIndex === 8 visible: active asynchronous: true sourceComponent: AboutTab {} diff --git a/Modules/Settings/PersonalizationTab.qml b/Modules/Settings/PersonalizationTab.qml index 89fe4b82..553bb27e 100644 --- a/Modules/Settings/PersonalizationTab.qml +++ b/Modules/Settings/PersonalizationTab.qml @@ -13,10 +13,62 @@ Item { property alias profileBrowser: profileBrowser property alias wallpaperBrowser: wallpaperBrowser property var parentModal: null + property var cachedFontFamilies: [] + property var cachedMonoFamilies: [] + property bool fontsEnumerated: false + + function enumerateFonts() { + var fonts = ["Default"]; + var availableFonts = Qt.fontFamilies(); + var rootFamilies = []; + var seenFamilies = new Set(); + for (var i = 0; i < availableFonts.length; i++) { + var fontName = availableFonts[i]; + if (fontName.startsWith(".")) + continue; + + if (fontName === SettingsData.defaultFontFamily) + continue; + + var rootName = fontName.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").replace(/ (UI|Display|Text|Mono|Sans|Serif)$/i, function(match, suffix) { + return match; + }).trim(); + if (!seenFamilies.has(rootName) && rootName !== "") { + seenFamilies.add(rootName); + rootFamilies.push(rootName); + } + } + cachedFontFamilies = fonts.concat(rootFamilies.sort()); + var monoFonts = ["Default"]; + var monoFamilies = []; + var seenMonoFamilies = new Set(); + for (var j = 0; j < availableFonts.length; j++) { + var fontName2 = availableFonts[j]; + if (fontName2.startsWith(".")) + continue; + + if (fontName2 === SettingsData.defaultMonoFontFamily) + continue; + + var lowerName = fontName2.toLowerCase(); + if (lowerName.includes("mono") || lowerName.includes("code") || lowerName.includes("console") || lowerName.includes("terminal") || lowerName.includes("courier") || lowerName.includes("dejavu sans mono") || lowerName.includes("jetbrains") || lowerName.includes("fira") || lowerName.includes("hack") || lowerName.includes("source code") || lowerName.includes("ubuntu mono") || lowerName.includes("cascadia")) { + var rootName2 = fontName2.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").trim(); + if (!seenMonoFamilies.has(rootName2) && rootName2 !== "") { + seenMonoFamilies.add(rootName2); + monoFamilies.push(rootName2); + } + } + } + cachedMonoFamilies = monoFonts.concat(monoFamilies.sort()); + } Component.onCompleted: { // Access WallpaperCyclingService to ensure it's initialized WallpaperCyclingService.cyclingActive; + if (!fontsEnumerated) { + enumerateFonts(); + fontsEnumerated = true; + } } DankFlickable { @@ -840,6 +892,257 @@ Item { } + // Display Settings + StyledRect { + width: parent.width + height: displaySection.implicitHeight + Theme.spacingL * 2 + radius: Theme.cornerRadius + color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) + border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) + border.width: 1 + + Column { + id: displaySection + + anchors.fill: parent + anchors.margins: Theme.spacingL + spacing: Theme.spacingM + + Row { + width: parent.width + spacing: Theme.spacingM + + DankIcon { + name: "monitor" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: "Display Settings" + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + + } + + DankToggle { + id: nightModeToggle + + width: parent.width + text: "Night Mode" + description: "Apply warm color temperature to reduce eye strain" + checked: BrightnessService.nightModeActive + onToggled: (checked) => { + if (checked !== BrightnessService.nightModeActive) { + if (checked) + BrightnessService.enableNightMode(); + else + BrightnessService.disableNightMode(); + } + } + + Connections { + function onNightModeActiveChanged() { + nightModeToggle.checked = BrightnessService.nightModeActive; + } + + target: BrightnessService + } + + } + + DankDropdown { + width: parent.width + text: "Night Mode Temperature" + description: BrightnessService.nightModeActive ? "Disable night mode to adjust" : "Set temperature for night mode" + enabled: !BrightnessService.nightModeActive + opacity: !BrightnessService.nightModeActive ? 1 : 0.6 + currentValue: SessionData.nightModeTemperature + "K" + options: { + var temps = []; + for (var i = 2500; i <= 6000; i += 500) { + temps.push(i + "K"); + } + return temps; + } + onValueChanged: (value) => { + var temp = parseInt(value.replace("K", "")); + SessionData.setNightModeTemperature(temp); + } + } + + DankToggle { + width: parent.width + text: "Light Mode" + description: "Use light theme instead of dark theme" + checked: SessionData.isLightMode + onToggled: (checked) => { + SessionData.setLightMode(checked); + Theme.isLightMode = checked; + PortalService.setLightMode(checked); + } + } + + } + + } + + // Font Settings + StyledRect { + width: parent.width + height: fontSection.implicitHeight + Theme.spacingL * 2 + radius: Theme.cornerRadius + color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) + border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) + border.width: 1 + + Column { + id: fontSection + + anchors.fill: parent + anchors.margins: Theme.spacingL + spacing: Theme.spacingM + + Row { + width: parent.width + spacing: Theme.spacingM + + DankIcon { + name: "font_download" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: "Font Settings" + font.pixelSize: Theme.fontSizeLarge + font.weight: Font.Medium + color: Theme.surfaceText + anchors.verticalCenter: parent.verticalCenter + } + + } + + DankDropdown { + width: parent.width + text: "Font Family" + description: "Select system font family" + currentValue: { + if (SettingsData.fontFamily === SettingsData.defaultFontFamily) + return "Default"; + else + return SettingsData.fontFamily || "Default"; + } + enableFuzzySearch: true + popupWidthOffset: 100 + maxPopupHeight: 400 + options: cachedFontFamilies + onValueChanged: (value) => { + if (value.startsWith("Default")) + SettingsData.setFontFamily(SettingsData.defaultFontFamily); + else + SettingsData.setFontFamily(value); + } + } + + DankDropdown { + width: parent.width + text: "Font Weight" + description: "Select font weight" + currentValue: { + switch (SettingsData.fontWeight) { + case Font.Thin: + return "Thin"; + case Font.ExtraLight: + return "Extra Light"; + case Font.Light: + return "Light"; + case Font.Normal: + return "Regular"; + case Font.Medium: + return "Medium"; + case Font.DemiBold: + return "Demi Bold"; + case Font.Bold: + return "Bold"; + case Font.ExtraBold: + return "Extra Bold"; + case Font.Black: + return "Black"; + default: + return "Regular"; + } + } + options: ["Thin", "Extra Light", "Light", "Regular", "Medium", "Demi Bold", "Bold", "Extra Bold", "Black"] + onValueChanged: (value) => { + var weight; + switch (value) { + case "Thin": + weight = Font.Thin; + break; + case "Extra Light": + weight = Font.ExtraLight; + break; + case "Light": + weight = Font.Light; + break; + case "Regular": + weight = Font.Normal; + break; + case "Medium": + weight = Font.Medium; + break; + case "Demi Bold": + weight = Font.DemiBold; + break; + case "Bold": + weight = Font.Bold; + break; + case "Extra Bold": + weight = Font.ExtraBold; + break; + case "Black": + weight = Font.Black; + break; + default: + weight = Font.Normal; + break; + } + SettingsData.setFontWeight(weight); + } + } + + DankDropdown { + width: parent.width + text: "Monospace Font" + description: "Select monospace font for process list and technical displays" + currentValue: { + if (SettingsData.monoFontFamily === SettingsData.defaultMonoFontFamily) + return "Default"; + + return SettingsData.monoFontFamily || "Default"; + } + enableFuzzySearch: true + popupWidthOffset: 100 + maxPopupHeight: 400 + options: cachedMonoFamilies + onValueChanged: (value) => { + if (value === "Default") + SettingsData.setMonoFontFamily(SettingsData.defaultMonoFontFamily); + else + SettingsData.setMonoFontFamily(value); + } + } + + } + + } + } diff --git a/Modules/Settings/SystemThemesTab.qml b/Modules/Settings/SystemThemesTab.qml deleted file mode 100644 index 37f00125..00000000 --- a/Modules/Settings/SystemThemesTab.qml +++ /dev/null @@ -1,181 +0,0 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Services -import qs.Widgets - -Item { - id: systemThemesTab - - DankFlickable { - anchors.fill: parent - anchors.topMargin: Theme.spacingL - clip: true - contentHeight: mainColumn.height - contentWidth: width - - Column { - id: mainColumn - - width: parent.width - spacing: Theme.spacingXL - - // System Configuration Warning - Rectangle { - width: parent.width - height: warningText.implicitHeight + Theme.spacingM * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12) - border.color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3) - border.width: 1 - - Row { - anchors.fill: parent - anchors.margins: Theme.spacingM - spacing: Theme.spacingM - - DankIcon { - name: "info" - size: Theme.iconSizeSmall - color: Theme.warning - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - id: warningText - - text: "Changing these settings will manipulate GTK and Qt configurations on the system" - font.pixelSize: Theme.fontSizeSmall - color: Theme.warning - wrapMode: Text.WordWrap - width: parent.width - Theme.iconSizeSmall - Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - } - - } - - } - - // Icon Theme - StyledRect { - width: parent.width - height: iconThemeSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 1 - - Column { - id: iconThemeSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingXS - - DankIcon { - name: "image" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - DankDropdown { - width: parent.width - Theme.iconSize - Theme.spacingXS - anchors.verticalCenter: parent.verticalCenter - text: "Icon Theme" - description: "DankShell & System Icons" - currentValue: SettingsData.iconTheme - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 400 - options: { - SettingsData.detectAvailableIconThemes(); - return SettingsData.availableIconThemes; - } - onValueChanged: (value) => { - SettingsData.setIconTheme(value); - if (value !== "System Default" && !SettingsData.qt5ctAvailable && !SettingsData.qt6ctAvailable) - ToastService.showWarning("qt5ct or qt6ct not found - Qt app themes may not update without these tools"); - - } - } - - } - - } - - } - - // System App Theming - StyledRect { - width: parent.width - height: systemThemingSection.implicitHeight + Theme.spacingL * 2 - radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) - border.width: 1 - visible: Theme.isDynamicTheme && Colors.matugenAvailable - - Column { - id: systemThemingSection - - anchors.fill: parent - anchors.margins: Theme.spacingL - spacing: Theme.spacingM - - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "extension" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "System App Theming" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - - } - - DankToggle { - width: parent.width - text: "Theme GTK Applications" - description: Colors.gtkThemingEnabled ? "File managers, text editors, and system dialogs will match your theme" : "GTK theming not available (install gsettings)" - enabled: Colors.gtkThemingEnabled - checked: Colors.gtkThemingEnabled && SettingsData.gtkThemingEnabled - onToggled: function(checked) { - SettingsData.setGtkThemingEnabled(checked); - } - } - - DankToggle { - width: parent.width - text: "Theme Qt Applications" - description: Colors.qtThemingEnabled ? "Qt applications will match your theme colors" : "Qt theming not available (install qt5ct or qt6ct)" - enabled: Colors.qtThemingEnabled - checked: Colors.qtThemingEnabled && SettingsData.qtThemingEnabled - onToggled: function(checked) { - SettingsData.setQtThemingEnabled(checked); - } - } - - } - - } - - } - - } - -} \ No newline at end of file diff --git a/Modules/Settings/ThemeColorsTab.qml b/Modules/Settings/ThemeColorsTab.qml index e175d15d..80f14ad6 100644 --- a/Modules/Settings/ThemeColorsTab.qml +++ b/Modules/Settings/ThemeColorsTab.qml @@ -564,116 +564,108 @@ Item { } - // Display Settings - StyledRect { + // System Configuration Warning + Rectangle { width: parent.width - height: displaySection.implicitHeight + Theme.spacingL * 2 + height: warningText.implicitHeight + Theme.spacingM * 2 radius: Theme.cornerRadius - color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) + color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12) + border.color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3) border.width: 1 - Column { - id: displaySection - + Row { anchors.fill: parent - anchors.margins: Theme.spacingL + anchors.margins: Theme.spacingM spacing: Theme.spacingM - Row { - width: parent.width - spacing: Theme.spacingM - - DankIcon { - name: "monitor" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: "Display Settings" - font.pixelSize: Theme.fontSizeLarge - font.weight: Font.Medium - color: Theme.surfaceText - anchors.verticalCenter: parent.verticalCenter - } - + DankIcon { + name: "info" + size: Theme.iconSizeSmall + color: Theme.warning + anchors.verticalCenter: parent.verticalCenter } - DankToggle { - id: nightModeToggle + StyledText { + id: warningText - width: parent.width - text: "Night Mode" - description: "Apply warm color temperature to reduce eye strain" - checked: BrightnessService.nightModeActive - onToggled: (checked) => { - if (checked !== BrightnessService.nightModeActive) { - if (checked) - BrightnessService.enableNightMode(); - else - BrightnessService.disableNightMode(); - } - } - - Connections { - function onNightModeActiveChanged() { - nightModeToggle.checked = BrightnessService.nightModeActive; - } - - target: BrightnessService - } - - } - - DankDropdown { - width: parent.width - text: "Night Mode Temperature" - description: BrightnessService.nightModeActive ? "Disable night mode to adjust" : "Set temperature for night mode" - enabled: !BrightnessService.nightModeActive - opacity: !BrightnessService.nightModeActive ? 1 : 0.6 - currentValue: SessionData.nightModeTemperature + "K" - options: { - var temps = []; - for (var i = 2500; i <= 6000; i += 500) { - temps.push(i + "K"); - } - return temps; - } - onValueChanged: (value) => { - var temp = parseInt(value.replace("K", "")); - SessionData.setNightModeTemperature(temp); - } - } - - DankToggle { - width: parent.width - text: "Light Mode" - description: "Use light theme instead of dark theme" - checked: SessionData.isLightMode - onToggled: (checked) => { - SessionData.setLightMode(checked); - Theme.isLightMode = checked; - PortalService.setLightMode(checked); - } + text: "Changing these settings will manipulate GTK and Qt configurations on the system" + font.pixelSize: Theme.fontSizeSmall + color: Theme.warning + wrapMode: Text.WordWrap + width: parent.width - Theme.iconSizeSmall - Theme.spacingM + anchors.verticalCenter: parent.verticalCenter } } } - // Font Settings + // Icon Theme StyledRect { width: parent.width - height: fontSection.implicitHeight + Theme.spacingL * 2 + height: iconThemeSection.implicitHeight + Theme.spacingL * 2 radius: Theme.cornerRadius color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) border.width: 1 Column { - id: fontSection + id: iconThemeSection + + anchors.fill: parent + anchors.margins: Theme.spacingL + spacing: Theme.spacingM + + Row { + width: parent.width + spacing: Theme.spacingXS + + DankIcon { + name: "image" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + DankDropdown { + width: parent.width - Theme.iconSize - Theme.spacingXS + anchors.verticalCenter: parent.verticalCenter + text: "Icon Theme" + description: "DankShell & System Icons" + currentValue: SettingsData.iconTheme + enableFuzzySearch: true + popupWidthOffset: 100 + maxPopupHeight: 236 + options: { + SettingsData.detectAvailableIconThemes(); + return SettingsData.availableIconThemes; + } + onValueChanged: (value) => { + SettingsData.setIconTheme(value); + if (value !== "System Default" && !SettingsData.qt5ctAvailable && !SettingsData.qt6ctAvailable) + ToastService.showWarning("qt5ct or qt6ct not found - Qt app themes may not update without these tools"); + + } + } + + } + + } + + } + + // System App Theming + StyledRect { + width: parent.width + height: systemThemingSection.implicitHeight + Theme.spacingL * 2 + radius: Theme.cornerRadius + color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3) + border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2) + border.width: 1 + visible: Theme.isDynamicTheme && Colors.matugenAvailable + + Column { + id: systemThemingSection anchors.fill: parent anchors.margins: Theme.spacingL @@ -684,14 +676,14 @@ Item { spacing: Theme.spacingM DankIcon { - name: "font_download" + name: "extension" size: Theme.iconSize color: Theme.primary anchors.verticalCenter: parent.verticalCenter } StyledText { - text: "Font Settings" + text: "System App Theming" font.pixelSize: Theme.fontSizeLarge font.weight: Font.Medium color: Theme.surfaceText @@ -700,114 +692,25 @@ Item { } - DankDropdown { + DankToggle { width: parent.width - text: "Font Family" - description: "Select system font family" - currentValue: { - if (SettingsData.fontFamily === SettingsData.defaultFontFamily) - return "Default"; - else - return SettingsData.fontFamily || "Default"; - } - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 400 - options: cachedFontFamilies - onValueChanged: (value) => { - if (value.startsWith("Default")) - SettingsData.setFontFamily(SettingsData.defaultFontFamily); - else - SettingsData.setFontFamily(value); + text: "Theme GTK Applications" + description: Colors.gtkThemingEnabled ? "File managers, text editors, and system dialogs will match your theme" : "GTK theming not available (install gsettings)" + enabled: Colors.gtkThemingEnabled + checked: Colors.gtkThemingEnabled && SettingsData.gtkThemingEnabled + onToggled: function(checked) { + SettingsData.setGtkThemingEnabled(checked); } } - DankDropdown { + DankToggle { width: parent.width - text: "Font Weight" - description: "Select font weight" - currentValue: { - switch (SettingsData.fontWeight) { - case Font.Thin: - return "Thin"; - case Font.ExtraLight: - return "Extra Light"; - case Font.Light: - return "Light"; - case Font.Normal: - return "Regular"; - case Font.Medium: - return "Medium"; - case Font.DemiBold: - return "Demi Bold"; - case Font.Bold: - return "Bold"; - case Font.ExtraBold: - return "Extra Bold"; - case Font.Black: - return "Black"; - default: - return "Regular"; - } - } - options: ["Thin", "Extra Light", "Light", "Regular", "Medium", "Demi Bold", "Bold", "Extra Bold", "Black"] - onValueChanged: (value) => { - var weight; - switch (value) { - case "Thin": - weight = Font.Thin; - break; - case "Extra Light": - weight = Font.ExtraLight; - break; - case "Light": - weight = Font.Light; - break; - case "Regular": - weight = Font.Normal; - break; - case "Medium": - weight = Font.Medium; - break; - case "Demi Bold": - weight = Font.DemiBold; - break; - case "Bold": - weight = Font.Bold; - break; - case "Extra Bold": - weight = Font.ExtraBold; - break; - case "Black": - weight = Font.Black; - break; - default: - weight = Font.Normal; - break; - } - SettingsData.setFontWeight(weight); - } - } - - DankDropdown { - width: parent.width - text: "Monospace Font" - description: "Select monospace font for process list and technical displays" - currentValue: { - if (SettingsData.monoFontFamily === SettingsData.defaultMonoFontFamily) - return "Default"; - - return SettingsData.monoFontFamily || "Default"; - } - enableFuzzySearch: true - popupWidthOffset: 100 - maxPopupHeight: 400 - options: cachedMonoFamilies - onValueChanged: (value) => { - if (value === "Default") - SettingsData.setMonoFontFamily(SettingsData.defaultMonoFontFamily); - else - SettingsData.setMonoFontFamily(value); + text: "Theme Qt Applications" + description: Colors.qtThemingEnabled ? "Qt applications will match your theme colors" : "Qt theming not available (install qt5ct or qt6ct)" + enabled: Colors.qtThemingEnabled + checked: Colors.qtThemingEnabled && SettingsData.qtThemingEnabled + onToggled: function(checked) { + SettingsData.setQtThemingEnabled(checked); } }