mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-07 05:55:37 -05:00
554 lines
26 KiB
QML
554 lines
26 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import Quickshell.Io
|
|
import qs.Common
|
|
import qs.Services
|
|
import qs.Widgets
|
|
|
|
ScrollView {
|
|
id: appearanceTab
|
|
|
|
contentWidth: availableWidth
|
|
contentHeight: column.implicitHeight + Theme.spacingXL
|
|
clip: true
|
|
|
|
Column {
|
|
id: column
|
|
width: parent.width
|
|
spacing: Theme.spacingXL
|
|
topPadding: Theme.spacingL
|
|
bottomPadding: Theme.spacingXL
|
|
|
|
// Display Settings Section
|
|
StyledRect {
|
|
width: parent.width
|
|
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
|
|
|
|
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 {
|
|
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
|
|
|
|
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: true
|
|
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: true
|
|
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
|
|
|
|
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");
|
|
}
|
|
}
|
|
} |