mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-07 05:55:37 -05:00
settings: redesign
This commit is contained in:
@@ -1,56 +1,554 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
ScrollView {
|
||||
id: root
|
||||
id: appearanceTab
|
||||
|
||||
contentWidth: availableWidth
|
||||
contentHeight: column.implicitHeight + Theme.spacingXL
|
||||
clip: true
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
|
||||
Column {
|
||||
width: root.width - 20
|
||||
spacing: Theme.spacingL
|
||||
topPadding: Theme.spacingM
|
||||
bottomPadding: Theme.spacingL
|
||||
id: column
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXL
|
||||
topPadding: Theme.spacingL
|
||||
bottomPadding: Theme.spacingXL
|
||||
|
||||
// Display Settings
|
||||
Column {
|
||||
// Display Settings Section
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
height: displaySection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadiusLarge
|
||||
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
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
Column {
|
||||
id: displaySection
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "monitor"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
text: "Display"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: "Night Mode"
|
||||
description: "Apply warm color temperature to reduce eye strain"
|
||||
checked: Prefs.nightModeEnabled
|
||||
onToggled: (checked) => {
|
||||
Prefs.setNightModeEnabled(checked);
|
||||
if (checked)
|
||||
nightModeEnableProcess.running = true;
|
||||
else
|
||||
nightModeDisableProcess.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
width: parent.width
|
||||
text: "Light Mode"
|
||||
description: "Use light theme instead of dark theme"
|
||||
checked: Prefs.isLightMode
|
||||
onToggled: (checked) => {
|
||||
Prefs.setLightMode(checked);
|
||||
Theme.isLightMode = checked;
|
||||
}
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width
|
||||
text: "Icon Theme"
|
||||
description: "Select icon theme (requires restart)"
|
||||
currentValue: Prefs.iconTheme
|
||||
options: Prefs.availableIconThemes
|
||||
onValueChanged: (value) => {
|
||||
Prefs.setIconTheme(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Transparency Settings Section
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: transparencySection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadiusLarge
|
||||
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
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
Column {
|
||||
id: transparencySection
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "opacity"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Transparency Settings"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Top Bar Transparency"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
width: parent.width
|
||||
height: 24
|
||||
value: Math.round(Prefs.topBarTransparency * 100)
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
unit: ""
|
||||
showValue: false
|
||||
onSliderValueChanged: (newValue) => {
|
||||
Prefs.setTopBarTransparency(newValue / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Popup Transparency"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
width: parent.width
|
||||
height: 24
|
||||
value: Math.round(Prefs.popupTransparency * 100)
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
unit: ""
|
||||
showValue: false
|
||||
onSliderValueChanged: (newValue) => {
|
||||
Prefs.setPopupTransparency(newValue / 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Theme Picker Section
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: themeSection.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadiusLarge
|
||||
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
|
||||
|
||||
DisplayTab {
|
||||
width: parent.width
|
||||
Column {
|
||||
id: themeSection
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "palette"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Theme Color"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Current Theme: " + (Theme.isDynamicTheme ? "Auto" : (Theme.currentThemeIndex < Theme.themes.length ? Theme.themes[Theme.currentThemeIndex].name : "Blue"))
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (Theme.isDynamicTheme)
|
||||
return "Wallpaper-based dynamic colors";
|
||||
|
||||
var descriptions = ["Material blue inspired by modern interfaces", "Deep blue inspired by material 3", "Rich purple tones for BB elegance", "Natural green for productivity", "Energetic orange for creativity", "Bold red for impact", "Cool cyan for tranquility", "Vibrant pink for expression", "Warm amber for comfort", "Soft coral for gentle warmth"];
|
||||
return descriptions[Theme.currentThemeIndex] || "Select a theme";
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
wrapMode: Text.WordWrap
|
||||
width: Math.min(parent.width, 400)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
// Theme Grid
|
||||
Column {
|
||||
spacing: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
// First row - Blue, Deep Blue, Purple, Green, Orange
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Repeater {
|
||||
model: 5
|
||||
|
||||
Rectangle {
|
||||
width: 32
|
||||
height: 32
|
||||
radius: 16
|
||||
color: Theme.themes[index].primary
|
||||
border.color: Theme.outline
|
||||
border.width: (Theme.currentThemeIndex === index && !Theme.isDynamicTheme) ? 2 : 1
|
||||
scale: (Theme.currentThemeIndex === index && !Theme.isDynamicTheme) ? 1.1 : 1
|
||||
|
||||
// Theme name tooltip
|
||||
Rectangle {
|
||||
width: nameText.contentWidth + Theme.spacingS * 2
|
||||
height: nameText.contentHeight + Theme.spacingXS * 2
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
radius: Theme.cornerRadiusSmall
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: mouseArea.containsMouse
|
||||
|
||||
StyledText {
|
||||
id: nameText
|
||||
text: Theme.themes[index].name
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
Theme.switchTheme(index, false);
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second row - Red, Cyan, Pink, Amber, Coral
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Repeater {
|
||||
model: 5
|
||||
|
||||
Rectangle {
|
||||
property int themeIndex: index + 5
|
||||
|
||||
width: 32
|
||||
height: 32
|
||||
radius: 16
|
||||
color: themeIndex < Theme.themes.length ? Theme.themes[themeIndex].primary : "transparent"
|
||||
border.color: Theme.outline
|
||||
border.width: Theme.currentThemeIndex === themeIndex ? 2 : 1
|
||||
visible: themeIndex < Theme.themes.length
|
||||
scale: Theme.currentThemeIndex === themeIndex ? 1.1 : 1
|
||||
|
||||
// Theme name tooltip
|
||||
Rectangle {
|
||||
width: nameText2.contentWidth + Theme.spacingS * 2
|
||||
height: nameText2.contentHeight + Theme.spacingXS * 2
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
radius: Theme.cornerRadiusSmall
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: mouseArea2.containsMouse && themeIndex < Theme.themes.length
|
||||
|
||||
StyledText {
|
||||
id: nameText2
|
||||
text: themeIndex < Theme.themes.length ? Theme.themes[themeIndex].name : ""
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea2
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (themeIndex < Theme.themes.length)
|
||||
Theme.switchTheme(themeIndex);
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spacer
|
||||
Item {
|
||||
width: 1
|
||||
height: Theme.spacingM
|
||||
}
|
||||
|
||||
// Auto theme button
|
||||
Rectangle {
|
||||
width: 120
|
||||
height: 40
|
||||
radius: 20
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: {
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12);
|
||||
else
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3);
|
||||
}
|
||||
border.color: {
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.5);
|
||||
else if (Theme.isDynamicTheme)
|
||||
return Theme.primary;
|
||||
else
|
||||
return Theme.outline;
|
||||
}
|
||||
border.width: Theme.isDynamicTheme ? 2 : 1
|
||||
scale: Theme.isDynamicTheme ? 1.1 : (autoMouseArea.containsMouse ? 1.02 : 1)
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: {
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return "error";
|
||||
else
|
||||
return "palette";
|
||||
}
|
||||
size: 16
|
||||
color: {
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return Theme.error;
|
||||
else
|
||||
return Theme.surfaceText;
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (ToastService.wallpaperErrorStatus === "error")
|
||||
return "Error";
|
||||
else if (ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return "No matugen";
|
||||
else
|
||||
return "Auto";
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: {
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return Theme.error;
|
||||
else
|
||||
return Theme.surfaceText;
|
||||
}
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: autoMouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (ToastService.wallpaperErrorStatus === "matugen_missing") {
|
||||
ToastService.showError("matugen not found - install matugen package for dynamic theming");
|
||||
} else if (ToastService.wallpaperErrorStatus === "error") {
|
||||
ToastService.showError("Wallpaper processing failed - check wallpaper path");
|
||||
} else {
|
||||
Theme.switchTheme(10, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tooltip for Auto button
|
||||
Rectangle {
|
||||
width: autoTooltipText.contentWidth + Theme.spacingM * 2
|
||||
height: autoTooltipText.contentHeight + Theme.spacingS * 2
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
radius: Theme.cornerRadiusSmall
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: autoMouseArea.containsMouse && (!Theme.isDynamicTheme || ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
|
||||
StyledText {
|
||||
id: autoTooltipText
|
||||
text: {
|
||||
if (ToastService.wallpaperErrorStatus === "error")
|
||||
return "Wallpaper symlink missing at ~/quickshell/current_wallpaper";
|
||||
else if (ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return "Install matugen package for dynamic themes";
|
||||
else
|
||||
return "Dynamic wallpaper-based colors";
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing") ? Theme.error : Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
wrapMode: Text.WordWrap
|
||||
width: Math.min(implicitWidth, 250)
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Night mode processes
|
||||
Process {
|
||||
id: nightModeEnableProcess
|
||||
command: ["bash", "-c", "if command -v wlsunset > /dev/null; then pkill wlsunset; wlsunset -t 3000 & elif command -v redshift > /dev/null; then pkill redshift; redshift -P -O 3000 & else echo 'No night mode tool available'; fi"]
|
||||
running: false
|
||||
onExited: (exitCode) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("Failed to enable night mode");
|
||||
Prefs.setNightModeEnabled(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: nightModeDisableProcess
|
||||
command: ["bash", "-c", "pkill wlsunset; pkill redshift; if command -v wlsunset > /dev/null; then wlsunset -t 6500 -T 6500 & sleep 1; pkill wlsunset; elif command -v redshift > /dev/null; then redshift -P -O 6500; redshift -x; fi"]
|
||||
running: false
|
||||
onExited: (exitCode) => {
|
||||
if (exitCode !== 0)
|
||||
console.warn("Failed to disable night mode");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user