mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-08 06:25:37 -05:00
Add catpuccin theme + material 3 components
- Update DankToggle to be more representative of m3 design - Add DankButtonGroup to represent a m3 button group
This commit is contained in:
@@ -1,12 +1,121 @@
|
||||
// Stock theme definitions for DankMaterialShell
|
||||
// Separated from Theme.qml to keep that file clean
|
||||
|
||||
const CatppuccinMocha = {
|
||||
surface: "#45475a",
|
||||
surfaceText: "#cdd6f4",
|
||||
surfaceVariant: "#45475a",
|
||||
surfaceVariantText: "#a6adc8",
|
||||
background: "#1e1e2e",
|
||||
backgroundText: "#cdd6f4",
|
||||
outline: "#6c7086",
|
||||
surfaceContainer: "#313244",
|
||||
surfaceContainerHigh: "#585b70"
|
||||
}
|
||||
|
||||
const CatppuccinLatte = {
|
||||
surface: "#bcc0cc",
|
||||
surfaceText: "#4c4f69",
|
||||
surfaceVariant: "#bcc0cc",
|
||||
surfaceVariantText: "#6c6f85",
|
||||
background: "#eff1f5",
|
||||
backgroundText: "#4c4f69",
|
||||
outline: "#9ca0b0",
|
||||
surfaceContainer: "#ccd0da",
|
||||
surfaceContainerHigh: "#acb0be"
|
||||
}
|
||||
|
||||
const CatppuccinVariants = {
|
||||
"cat-rosewater": {
|
||||
name: "Rosewater",
|
||||
dark: { primary: "#f5e0dc", secondary: "#f2cdcd", primaryText: "#1e1e2e", primaryContainer: "#8b6b5e", surfaceTint: "#f5e0dc" },
|
||||
light: { primary: "#dc8a78", secondary: "#dd7878", primaryText: "#ffffff", primaryContainer: "#f4d2ca", surfaceTint: "#dc8a78" }
|
||||
},
|
||||
"cat-flamingo": {
|
||||
name: "Flamingo",
|
||||
dark: { primary: "#f2cdcd", secondary: "#f5e0dc", primaryText: "#1e1e2e", primaryContainer: "#885d62", surfaceTint: "#f2cdcd" },
|
||||
light: { primary: "#dd7878", secondary: "#dc8a78", primaryText: "#ffffff", primaryContainer: "#f4caca", surfaceTint: "#dd7878" }
|
||||
},
|
||||
"cat-pink": {
|
||||
name: "Pink",
|
||||
dark: { primary: "#f5c2e7", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#8b537a", surfaceTint: "#f5c2e7" },
|
||||
light: { primary: "#ea76cb", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#f7c9e7", surfaceTint: "#ea76cb" }
|
||||
},
|
||||
"cat-mauve": {
|
||||
name: "Mauve",
|
||||
dark: { primary: "#cba6f7", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#61378a", surfaceTint: "#cba6f7" },
|
||||
light: { primary: "#8839ef", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#e4d3ff", surfaceTint: "#8839ef" }
|
||||
},
|
||||
"cat-red": {
|
||||
name: "Red",
|
||||
dark: { primary: "#f38ba8", secondary: "#eba0ac", primaryText: "#1e1e2e", primaryContainer: "#891c3b", surfaceTint: "#f38ba8" },
|
||||
light: { primary: "#d20f39", secondary: "#e64553", primaryText: "#ffffff", primaryContainer: "#f1b8c4", surfaceTint: "#d20f39" }
|
||||
},
|
||||
"cat-maroon": {
|
||||
name: "Maroon",
|
||||
dark: { primary: "#eba0ac", secondary: "#f38ba8", primaryText: "#1e1e2e", primaryContainer: "#81313f", surfaceTint: "#eba0ac" },
|
||||
light: { primary: "#e64553", secondary: "#d20f39", primaryText: "#ffffff", primaryContainer: "#f4c3c8", surfaceTint: "#e64553" }
|
||||
},
|
||||
"cat-peach": {
|
||||
name: "Peach",
|
||||
dark: { primary: "#fab387", secondary: "#f9e2af", primaryText: "#1e1e2e", primaryContainer: "#90441a", surfaceTint: "#fab387" },
|
||||
light: { primary: "#fe640b", secondary: "#df8e1d", primaryText: "#ffffff", primaryContainer: "#ffddcc", surfaceTint: "#fe640b" }
|
||||
},
|
||||
"cat-yellow": {
|
||||
name: "Yellow",
|
||||
dark: { primary: "#f9e2af", secondary: "#a6e3a1", primaryText: "#1e1e2e", primaryContainer: "#8f7342", surfaceTint: "#f9e2af" },
|
||||
light: { primary: "#df8e1d", secondary: "#40a02b", primaryText: "#ffffff", primaryContainer: "#fff3cc", surfaceTint: "#df8e1d" }
|
||||
},
|
||||
"cat-green": {
|
||||
name: "Green",
|
||||
dark: { primary: "#a6e3a1", secondary: "#94e2d5", primaryText: "#1e1e2e", primaryContainer: "#3c7534", surfaceTint: "#a6e3a1" },
|
||||
light: { primary: "#40a02b", secondary: "#179299", primaryText: "#ffffff", primaryContainer: "#d4f5d4", surfaceTint: "#40a02b" }
|
||||
},
|
||||
"cat-teal": {
|
||||
name: "Teal",
|
||||
dark: { primary: "#94e2d5", secondary: "#89dceb", primaryText: "#1e1e2e", primaryContainer: "#2a7468", surfaceTint: "#94e2d5" },
|
||||
light: { primary: "#179299", secondary: "#04a5e5", primaryText: "#ffffff", primaryContainer: "#ccf2f2", surfaceTint: "#179299" }
|
||||
},
|
||||
"cat-sky": {
|
||||
name: "Sky",
|
||||
dark: { primary: "#89dceb", secondary: "#74c7ec", primaryText: "#1e1e2e", primaryContainer: "#196e7e", surfaceTint: "#89dceb" },
|
||||
light: { primary: "#04a5e5", secondary: "#209fb5", primaryText: "#ffffff", primaryContainer: "#ccebff", surfaceTint: "#04a5e5" }
|
||||
},
|
||||
"cat-sapphire": {
|
||||
name: "Sapphire",
|
||||
dark: { primary: "#74c7ec", secondary: "#89b4fa", primaryText: "#1e1e2e", primaryContainer: "#0a597f", surfaceTint: "#74c7ec" },
|
||||
light: { primary: "#209fb5", secondary: "#1e66f5", primaryText: "#ffffff", primaryContainer: "#d0f0f5", surfaceTint: "#209fb5" }
|
||||
},
|
||||
"cat-blue": {
|
||||
name: "Blue",
|
||||
dark: { primary: "#89b4fa", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#19468d", surfaceTint: "#89b4fa" },
|
||||
light: { primary: "#1e66f5", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#ccd9ff", surfaceTint: "#1e66f5" }
|
||||
},
|
||||
"cat-lavender": {
|
||||
name: "Lavender",
|
||||
dark: { primary: "#b4befe", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#4a5091", surfaceTint: "#b4befe" },
|
||||
light: { primary: "#7287fd", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#dde1ff", surfaceTint: "#7287fd" }
|
||||
}
|
||||
}
|
||||
|
||||
function getCatppuccinTheme(variant, isLight = false) {
|
||||
const variantData = CatppuccinVariants[variant]
|
||||
if (!variantData) return null
|
||||
|
||||
const baseColors = isLight ? CatppuccinLatte : CatppuccinMocha
|
||||
const accentColors = isLight ? variantData.light : variantData.dark
|
||||
|
||||
return Object.assign({
|
||||
name: `${variantData.name}${isLight ? ' Light' : ''}`
|
||||
}, baseColors, accentColors)
|
||||
}
|
||||
|
||||
const StockThemes = {
|
||||
DARK: {
|
||||
blue: {
|
||||
name: "Blue",
|
||||
primary: "#42a5f5",
|
||||
primaryText: "#ffffff",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#1976d2",
|
||||
secondary: "#8ab4f8",
|
||||
surface: "#1a1c1e",
|
||||
@@ -23,7 +132,7 @@ const StockThemes = {
|
||||
deepBlue: {
|
||||
name: "Deep Blue",
|
||||
primary: "#0061a4",
|
||||
primaryText: "#ffffff",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#004881",
|
||||
secondary: "#42a5f5",
|
||||
surface: "#1a1c1e",
|
||||
@@ -57,7 +166,7 @@ const StockThemes = {
|
||||
green: {
|
||||
name: "Green",
|
||||
primary: "#4caf50",
|
||||
primaryText: "#ffffff",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#388e3c",
|
||||
secondary: "#81c995",
|
||||
surface: "#0f1411",
|
||||
@@ -74,7 +183,7 @@ const StockThemes = {
|
||||
orange: {
|
||||
name: "Orange",
|
||||
primary: "#ff6d00",
|
||||
primaryText: "#ffffff",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#e65100",
|
||||
secondary: "#ffb74d",
|
||||
surface: "#1c1410",
|
||||
@@ -91,7 +200,7 @@ const StockThemes = {
|
||||
red: {
|
||||
name: "Red",
|
||||
primary: "#f44336",
|
||||
primaryText: "#ffffff",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#d32f2f",
|
||||
secondary: "#f28b82",
|
||||
surface: "#1c1011",
|
||||
@@ -108,7 +217,7 @@ const StockThemes = {
|
||||
cyan: {
|
||||
name: "Cyan",
|
||||
primary: "#00bcd4",
|
||||
primaryText: "#ffffff",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#0097a7",
|
||||
secondary: "#4dd0e1",
|
||||
surface: "#0f1617",
|
||||
@@ -125,7 +234,7 @@ const StockThemes = {
|
||||
pink: {
|
||||
name: "Pink",
|
||||
primary: "#e91e63",
|
||||
primaryText: "#ffffff",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#c2185b",
|
||||
secondary: "#f8bbd9",
|
||||
surface: "#1a1014",
|
||||
@@ -159,7 +268,7 @@ const StockThemes = {
|
||||
coral: {
|
||||
name: "Coral",
|
||||
primary: "#ffb4ab",
|
||||
primaryText: "#5f1412",
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#8c1d18",
|
||||
secondary: "#f9dedc",
|
||||
surface: "#1a1110",
|
||||
@@ -348,6 +457,17 @@ const StockThemes = {
|
||||
}
|
||||
}
|
||||
|
||||
const ThemeCategories = {
|
||||
GENERIC: {
|
||||
name: "Generic",
|
||||
variants: ["blue", "deepBlue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral"]
|
||||
},
|
||||
CATPPUCCIN: {
|
||||
name: "Catppuccin",
|
||||
variants: Object.keys(CatppuccinVariants)
|
||||
}
|
||||
}
|
||||
|
||||
const ThemeNames = {
|
||||
BLUE: "blue",
|
||||
DEEP_BLUE: "deepBlue",
|
||||
@@ -366,15 +486,30 @@ function isStockTheme(themeName) {
|
||||
return Object.keys(StockThemes.DARK).includes(themeName)
|
||||
}
|
||||
|
||||
function isCatppuccinVariant(themeName) {
|
||||
return Object.keys(CatppuccinVariants).includes(themeName)
|
||||
}
|
||||
|
||||
function getAvailableThemes(isLight = false) {
|
||||
return isLight ? StockThemes.LIGHT : StockThemes.DARK
|
||||
}
|
||||
|
||||
function getThemeByName(themeName, isLight = false) {
|
||||
if (isCatppuccinVariant(themeName)) {
|
||||
return getCatppuccinTheme(themeName, isLight)
|
||||
}
|
||||
const themes = getAvailableThemes(isLight)
|
||||
return themes[themeName] || themes.blue
|
||||
}
|
||||
|
||||
function getAllThemeNames() {
|
||||
return Object.keys(StockThemes.DARK)
|
||||
}
|
||||
|
||||
function getCatppuccinVariantNames() {
|
||||
return Object.keys(CatppuccinVariants)
|
||||
}
|
||||
|
||||
function getThemeCategories() {
|
||||
return ThemeCategories
|
||||
}
|
||||
@@ -15,6 +15,7 @@ Singleton {
|
||||
id: root
|
||||
|
||||
property string currentTheme: "blue"
|
||||
property string currentThemeCategory: "generic"
|
||||
property bool isLightMode: false
|
||||
|
||||
readonly property string dynamic: "dynamic"
|
||||
@@ -207,14 +208,22 @@ Singleton {
|
||||
function switchTheme(themeName, savePrefs = true) {
|
||||
if (themeName === dynamic) {
|
||||
currentTheme = dynamic
|
||||
currentThemeCategory = "dynamic"
|
||||
extractColors()
|
||||
} else if (themeName === "custom") {
|
||||
currentTheme = "custom"
|
||||
currentThemeCategory = "custom"
|
||||
if (typeof SettingsData !== "undefined" && SettingsData.customThemeFile) {
|
||||
loadCustomThemeFromFile(SettingsData.customThemeFile)
|
||||
}
|
||||
} else {
|
||||
currentTheme = themeName
|
||||
// Determine category based on theme name
|
||||
if (StockThemes.isCatppuccinVariant(themeName)) {
|
||||
currentThemeCategory = "catppuccin"
|
||||
} else {
|
||||
currentThemeCategory = "generic"
|
||||
}
|
||||
}
|
||||
if (savePrefs && typeof SettingsData !== "undefined")
|
||||
SettingsData.setTheme(currentTheme)
|
||||
@@ -260,6 +269,31 @@ Singleton {
|
||||
return StockThemes.getThemeByName(themeName, isLightMode)
|
||||
}
|
||||
|
||||
function switchThemeCategory(category, defaultTheme) {
|
||||
currentThemeCategory = category
|
||||
switchTheme(defaultTheme)
|
||||
}
|
||||
|
||||
function getCatppuccinColor(variantName) {
|
||||
const catColors = {
|
||||
"cat-rosewater": "#f5e0dc", "cat-flamingo": "#f2cdcd", "cat-pink": "#f5c2e7", "cat-mauve": "#cba6f7",
|
||||
"cat-red": "#f38ba8", "cat-maroon": "#eba0ac", "cat-peach": "#fab387", "cat-yellow": "#f9e2af",
|
||||
"cat-green": "#a6e3a1", "cat-teal": "#94e2d5", "cat-sky": "#89dceb", "cat-sapphire": "#74c7ec",
|
||||
"cat-blue": "#89b4fa", "cat-lavender": "#b4befe"
|
||||
}
|
||||
return catColors[variantName] || "#cba6f7"
|
||||
}
|
||||
|
||||
function getCatppuccinVariantName(variantName) {
|
||||
const catNames = {
|
||||
"cat-rosewater": "Rosewater", "cat-flamingo": "Flamingo", "cat-pink": "Pink", "cat-mauve": "Mauve",
|
||||
"cat-red": "Red", "cat-maroon": "Maroon", "cat-peach": "Peach", "cat-yellow": "Yellow",
|
||||
"cat-green": "Green", "cat-teal": "Teal", "cat-sky": "Sky", "cat-sapphire": "Sapphire",
|
||||
"cat-blue": "Blue", "cat-lavender": "Lavender"
|
||||
}
|
||||
return catNames[variantName] || "Unknown"
|
||||
}
|
||||
|
||||
function loadCustomTheme(themeData) {
|
||||
if (themeData.dark || themeData.light) {
|
||||
const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark"
|
||||
|
||||
@@ -80,7 +80,7 @@ Rectangle {
|
||||
width: parent.width - Theme.spacingS * 2
|
||||
height: 44
|
||||
radius: Theme.cornerRadius
|
||||
color: isActive ? Theme.surfaceContainerHigh : tabMouseArea.containsMouse ? Theme.surfaceHover : "transparent"
|
||||
color: isActive ? Theme.primaryContainer : tabMouseArea.containsMouse ? Theme.surfaceHover : "transparent"
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
@@ -91,14 +91,14 @@ Rectangle {
|
||||
DankIcon {
|
||||
name: modelData.icon || ""
|
||||
size: Theme.iconSize - 2
|
||||
color: parent.parent.isActive ? Theme.primary : Theme.surfaceText
|
||||
color: parent.parent.isActive ? Theme.surfaceText : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.text || ""
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: parent.parent.isActive ? Theme.primary : Theme.surfaceText
|
||||
color: parent.parent.isActive ? Theme.surfaceText : Theme.surfaceText
|
||||
font.weight: parent.parent.isActive ? Font.Medium : Font.Normal
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
@@ -99,6 +100,7 @@ Item {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingXL
|
||||
|
||||
|
||||
// Theme Color
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
@@ -142,7 +144,15 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: "Current Theme: " + (Theme.currentTheme === Theme.dynamic ? "Dynamic" : Theme.getThemeColors(Theme.currentThemeName).name)
|
||||
text: {
|
||||
if (Theme.currentTheme === Theme.dynamic) {
|
||||
return "Current Theme: Dynamic"
|
||||
} else if (Theme.currentThemeCategory === "catppuccin") {
|
||||
return "Current Theme: Catppuccin " + Theme.getThemeColors(Theme.currentThemeName).name
|
||||
} else {
|
||||
return "Current Theme: " + Theme.getThemeColors(Theme.currentThemeName).name
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -153,20 +163,10 @@ Item {
|
||||
text: {
|
||||
if (Theme.currentTheme === Theme.dynamic)
|
||||
return "Wallpaper-based dynamic colors"
|
||||
|
||||
var descriptions = {
|
||||
"blue": "Material blue inspired by modern interfaces",
|
||||
"deepBlue": "Deep blue inspired by material 3",
|
||||
"purple": "Rich purple tones for elegance",
|
||||
"green": "Natural green for productivity",
|
||||
"orange": "Energetic orange for creativity",
|
||||
"red": "Bold red for impact",
|
||||
"cyan": "Cool cyan for tranquility",
|
||||
"pink": "Vibrant pink for expression",
|
||||
"amber": "Warm amber for comfort",
|
||||
"coral": "Soft coral for gentle warmth"
|
||||
}
|
||||
return descriptions[Theme.currentThemeName] || "Select a theme"
|
||||
else if (Theme.currentThemeCategory === "catppuccin")
|
||||
return "Soothing pastel theme inspired by Catppuccin"
|
||||
else
|
||||
return "Material Design inspired color themes"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
@@ -178,392 +178,477 @@ Item {
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: Theme.spacingS
|
||||
spacing: Theme.spacingM
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Repeater {
|
||||
model: Theme.availableThemeNames.slice(0, 5)
|
||||
|
||||
Rectangle {
|
||||
property string themeName: modelData
|
||||
width: 32
|
||||
height: 32
|
||||
radius: 16
|
||||
color: Theme.getThemeColors(themeName).primary
|
||||
border.color: Theme.outline
|
||||
border.width: (Theme.currentThemeName === themeName
|
||||
&& Theme.currentTheme !== Theme.dynamic) ? 2 : 1
|
||||
scale: (Theme.currentThemeName === themeName
|
||||
&& Theme.currentTheme !== Theme.dynamic) ? 1.1 : 1
|
||||
|
||||
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.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: mouseArea.containsMouse
|
||||
|
||||
StyledText {
|
||||
id: nameText
|
||||
|
||||
text: Theme.getThemeColors(themeName).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(themeName)
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
DankButtonGroup {
|
||||
property int currentThemeIndex: {
|
||||
if (Theme.currentTheme === Theme.dynamic) return 2
|
||||
if (Theme.currentThemeName === "custom") return 3
|
||||
if (Theme.currentThemeCategory === "catppuccin") return 1
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Repeater {
|
||||
model: Theme.availableThemeNames.slice(5, 10)
|
||||
|
||||
Rectangle {
|
||||
property string themeName: modelData
|
||||
|
||||
width: 32
|
||||
height: 32
|
||||
radius: 16
|
||||
color: Theme.getThemeColors(themeName).primary
|
||||
border.color: Theme.outline
|
||||
border.width: Theme.currentThemeName === themeName ? 2 : 1
|
||||
visible: true
|
||||
scale: Theme.currentThemeName === themeName ? 1.1 : 1
|
||||
|
||||
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.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: mouseArea2.containsMouse
|
||||
|
||||
StyledText {
|
||||
id: nameText2
|
||||
|
||||
text: Theme.getThemeColors(themeName).name
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea2
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
Theme.switchTheme(themeName)
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 1
|
||||
height: Theme.spacingM
|
||||
}
|
||||
|
||||
Row {
|
||||
model: ["Generic", "Catppuccin", "Auto", "Custom"]
|
||||
currentIndex: currentThemeIndex
|
||||
selectionMode: "single"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingL
|
||||
|
||||
Rectangle {
|
||||
width: 120
|
||||
height: 40
|
||||
radius: 20
|
||||
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.currentThemeName === "dynamic")
|
||||
return Theme.primary
|
||||
else
|
||||
return Theme.outline
|
||||
}
|
||||
border.width: (Theme.currentThemeName === "dynamic") ? 2 : 1
|
||||
scale: (Theme.currentThemeName === "dynamic") ? 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(Theme.dynamic)
|
||||
}
|
||||
}
|
||||
|
||||
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.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: autoMouseArea.containsMouse
|
||||
&& (Theme.currentTheme !== Theme.dynamic
|
||||
|| ToastService.wallpaperErrorStatus === "error"
|
||||
|| ToastService.wallpaperErrorStatus
|
||||
=== "matugen_missing")
|
||||
|
||||
StyledText {
|
||||
id: autoTooltipText
|
||||
|
||||
text: {
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected) return
|
||||
switch (index) {
|
||||
case 0: Theme.switchThemeCategory("generic", "blue"); break
|
||||
case 1: Theme.switchThemeCategory("catppuccin", "cat-mauve"); break
|
||||
case 2:
|
||||
if (ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return "Install matugen package for dynamic themes"
|
||||
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
|
||||
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
|
||||
Theme.switchTheme(Theme.dynamic)
|
||||
break
|
||||
case 3:
|
||||
if (Theme.currentThemeName !== "custom") {
|
||||
Theme.switchTheme("custom")
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 120
|
||||
height: 40
|
||||
radius: 20
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
border.color: (Theme.currentThemeName === "custom") ? Theme.primary : Theme.outline
|
||||
border.width: (Theme.currentThemeName === "custom") ? 2 : 1
|
||||
scale: (Theme.currentThemeName === "custom") ? 1.1 : (customMouseArea.containsMouse ? 1.02 : 1)
|
||||
Column {
|
||||
spacing: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: Theme.currentThemeCategory === "generic" && Theme.currentTheme !== Theme.dynamic && Theme.currentThemeName !== "custom"
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "folder_open"
|
||||
size: 16
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Custom"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: customMouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
fileBrowserModal.open()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: customTooltipText.contentWidth + Theme.spacingM * 2
|
||||
height: customTooltipText.contentHeight + Theme.spacingS * 2
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
radius: Theme.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
spacing: Theme.spacingM
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: customMouseArea.containsMouse
|
||||
|
||||
StyledText {
|
||||
id: customTooltipText
|
||||
text: {
|
||||
if (Theme.currentThemeName === "custom")
|
||||
return SettingsData.customThemeFile || "Custom theme loaded"
|
||||
else
|
||||
return "Load custom theme from JSON file"
|
||||
Repeater {
|
||||
model: ["blue", "deepBlue", "purple", "green", "orange"]
|
||||
|
||||
Rectangle {
|
||||
property string themeName: modelData
|
||||
width: 32
|
||||
height: 32
|
||||
radius: 16
|
||||
color: Theme.getThemeColors(themeName).primary
|
||||
border.color: Theme.outline
|
||||
border.width: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 2 : 1
|
||||
scale: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 1.1 : 1
|
||||
|
||||
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.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: mouseArea.containsMouse
|
||||
|
||||
StyledText {
|
||||
id: nameText
|
||||
text: Theme.getThemeColors(themeName).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(themeName)
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: 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
|
||||
}
|
||||
}
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
Repeater {
|
||||
model: ["red", "cyan", "pink", "amber", "coral"]
|
||||
|
||||
Rectangle {
|
||||
property string themeName: modelData
|
||||
width: 32
|
||||
height: 32
|
||||
radius: 16
|
||||
color: Theme.getThemeColors(themeName).primary
|
||||
border.color: Theme.outline
|
||||
border.width: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 2 : 1
|
||||
scale: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 1.1 : 1
|
||||
|
||||
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.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: mouseArea2.containsMouse
|
||||
|
||||
StyledText {
|
||||
id: nameText2
|
||||
text: Theme.getThemeColors(themeName).name
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea2
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
Theme.switchTheme(themeName)
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
spacing: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: Theme.currentThemeCategory === "catppuccin" && Theme.currentTheme !== Theme.dynamic && Theme.currentThemeName !== "custom"
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Repeater {
|
||||
model: ["cat-rosewater", "cat-flamingo", "cat-pink", "cat-mauve", "cat-red", "cat-maroon", "cat-peach"]
|
||||
|
||||
Rectangle {
|
||||
property string themeName: modelData
|
||||
width: 32
|
||||
height: 32
|
||||
radius: 16
|
||||
color: Theme.getCatppuccinColor(themeName)
|
||||
border.color: Theme.outline
|
||||
border.width: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 2 : 1
|
||||
scale: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 1.1 : 1
|
||||
|
||||
Rectangle {
|
||||
width: nameTextCat.contentWidth + Theme.spacingS * 2
|
||||
height: nameTextCat.contentHeight + Theme.spacingXS * 2
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
radius: Theme.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: mouseAreaCat.containsMouse
|
||||
|
||||
StyledText {
|
||||
id: nameTextCat
|
||||
text: Theme.getCatppuccinVariantName(themeName)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseAreaCat
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
Theme.switchTheme(themeName)
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingM
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Repeater {
|
||||
model: ["cat-yellow", "cat-green", "cat-teal", "cat-sky", "cat-sapphire", "cat-blue", "cat-lavender"]
|
||||
|
||||
Rectangle {
|
||||
property string themeName: modelData
|
||||
width: 32
|
||||
height: 32
|
||||
radius: 16
|
||||
color: Theme.getCatppuccinColor(themeName)
|
||||
border.color: Theme.outline
|
||||
border.width: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 2 : 1
|
||||
scale: (Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic) ? 1.1 : 1
|
||||
|
||||
Rectangle {
|
||||
width: nameTextCat2.contentWidth + Theme.spacingS * 2
|
||||
height: nameTextCat2.contentHeight + Theme.spacingXS * 2
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
radius: Theme.cornerRadius
|
||||
anchors.bottom: parent.top
|
||||
anchors.bottomMargin: Theme.spacingXS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: mouseAreaCat2.containsMouse
|
||||
|
||||
StyledText {
|
||||
id: nameTextCat2
|
||||
text: Theme.getCatppuccinVariantName(themeName)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseAreaCat2
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
Theme.switchTheme(themeName)
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
visible: Theme.currentTheme === Theme.dynamic
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
StyledRect {
|
||||
width: 120
|
||||
height: 90
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceVariant
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
|
||||
CachingImage {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
source: Theme.wallpaperPath ? "file://" + Theme.wallpaperPath : ""
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
visible: Theme.wallpaperPath && !Theme.wallpaperPath.startsWith("#")
|
||||
layer.enabled: true
|
||||
layer.effect: MultiEffect {
|
||||
maskEnabled: true
|
||||
maskSource: autoWallpaperMask
|
||||
maskThresholdMin: 0.5
|
||||
maskSpreadAtMin: 1
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
radius: Theme.cornerRadius - 1
|
||||
color: Theme.wallpaperPath && Theme.wallpaperPath.startsWith("#") ? Theme.wallpaperPath : "transparent"
|
||||
visible: Theme.wallpaperPath && Theme.wallpaperPath.startsWith("#")
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: autoWallpaperMask
|
||||
anchors.fill: parent
|
||||
anchors.margins: 1
|
||||
radius: Theme.cornerRadius - 1
|
||||
color: "black"
|
||||
visible: false
|
||||
layer.enabled: true
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: {
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return "error"
|
||||
else
|
||||
return "palette"
|
||||
}
|
||||
size: Theme.iconSizeLarge
|
||||
color: {
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return Theme.error
|
||||
else
|
||||
return Theme.surfaceVariantText
|
||||
}
|
||||
visible: !Theme.wallpaperPath
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - 120 - Theme.spacingM
|
||||
spacing: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (ToastService.wallpaperErrorStatus === "error")
|
||||
return "Wallpaper Error"
|
||||
else if (ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return "Matugen Missing"
|
||||
else if (Theme.wallpaperPath)
|
||||
return Theme.wallpaperPath.split('/').pop()
|
||||
else
|
||||
return "No wallpaper selected"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
elide: Text.ElideMiddle
|
||||
maximumLineCount: 1
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (ToastService.wallpaperErrorStatus === "error")
|
||||
return "Wallpaper processing failed"
|
||||
else if (ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return "Install matugen package for dynamic theming"
|
||||
else if (Theme.wallpaperPath)
|
||||
return Theme.wallpaperPath
|
||||
else
|
||||
return "Dynamic colors from wallpaper"
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: {
|
||||
if (ToastService.wallpaperErrorStatus === "error" || ToastService.wallpaperErrorStatus === "matugen_missing")
|
||||
return Theme.error
|
||||
else
|
||||
return Theme.surfaceVariantText
|
||||
}
|
||||
elide: Text.ElideMiddle
|
||||
maximumLineCount: 2
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
visible: Theme.currentThemeName === "custom"
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankActionButton {
|
||||
buttonSize: 48
|
||||
iconName: "folder_open"
|
||||
iconSize: Theme.iconSize
|
||||
backgroundColor: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
iconColor: Theme.primary
|
||||
onClicked: fileBrowserModal.open()
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - 48 - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: SettingsData.customThemeFile ? SettingsData.customThemeFile.split('/').pop() : "No custom theme file"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
elide: Text.ElideMiddle
|
||||
maximumLineCount: 1
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: SettingsData.customThemeFile || "Click to select a custom theme JSON file"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
elide: Text.ElideMiddle
|
||||
maximumLineCount: 1
|
||||
width: parent.width
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // Close Row
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
185
Widgets/DankButtonGroup.qml
Normal file
185
Widgets/DankButtonGroup.qml
Normal file
@@ -0,0 +1,185 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Row {
|
||||
id: root
|
||||
|
||||
property var model: []
|
||||
property int currentIndex: -1
|
||||
property string selectionMode: "single"
|
||||
property bool multiSelect: selectionMode === "multi"
|
||||
|
||||
signal selectionChanged(int index, bool selected)
|
||||
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
function isSelected(index) {
|
||||
if (multiSelect) {
|
||||
return repeater.itemAt(index)?.selected || false
|
||||
}
|
||||
return index === currentIndex
|
||||
}
|
||||
|
||||
function selectItem(index) {
|
||||
if (multiSelect) {
|
||||
const item = repeater.itemAt(index)
|
||||
if (item) {
|
||||
item.selected = !item.selected
|
||||
selectionChanged(index, item.selected)
|
||||
}
|
||||
} else {
|
||||
const oldIndex = currentIndex
|
||||
currentIndex = index
|
||||
selectionChanged(index, true)
|
||||
if (oldIndex !== index && oldIndex >= 0) {
|
||||
selectionChanged(oldIndex, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: root.model
|
||||
|
||||
delegate: Rectangle {
|
||||
id: segment
|
||||
|
||||
property bool selected: multiSelect ? false : (index === root.currentIndex)
|
||||
property bool hovered: mouseArea.containsMouse
|
||||
property bool pressed: mouseArea.pressed
|
||||
property bool isFirst: index === 0
|
||||
property bool isLast: index === repeater.count - 1
|
||||
property bool prevSelected: index > 0 ? root.isSelected(index - 1) : false
|
||||
property bool nextSelected: index < repeater.count - 1 ? root.isSelected(index + 1) : false
|
||||
|
||||
width: Math.max(contentItem.implicitWidth + Theme.spacingL * 2, 64) + (selected ? 4 : 0)
|
||||
height: 40
|
||||
|
||||
color: selected ? Theme.primaryContainer : Theme.primary
|
||||
border.color: "transparent"
|
||||
border.width: 0
|
||||
|
||||
topLeftRadius: (isFirst || selected) ? Theme.cornerRadius : 4
|
||||
bottomLeftRadius: (isFirst || selected) ? Theme.cornerRadius : 4
|
||||
topRightRadius: (isLast || selected) ? Theme.cornerRadius : 4
|
||||
bottomRightRadius: (isLast || selected) ? Theme.cornerRadius : 4
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on topLeftRadius {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on topRightRadius {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on bottomLeftRadius {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on bottomRightRadius {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: stateLayer
|
||||
anchors.fill: parent
|
||||
topLeftRadius: parent.topLeftRadius
|
||||
bottomLeftRadius: parent.bottomLeftRadius
|
||||
topRightRadius: parent.topRightRadius
|
||||
bottomRightRadius: parent.bottomRightRadius
|
||||
color: {
|
||||
if (pressed) return selected ? Theme.primaryPressed : Theme.surfacePressed
|
||||
if (hovered) return selected ? Theme.primaryHover : Theme.surfaceHover
|
||||
return "transparent"
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shorterDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: contentItem
|
||||
anchors.centerIn: parent
|
||||
implicitWidth: contentRow.implicitWidth
|
||||
implicitHeight: contentRow.implicitHeight
|
||||
|
||||
Row {
|
||||
id: contentRow
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
id: checkIcon
|
||||
name: "check"
|
||||
size: Theme.iconSizeSmall
|
||||
color: segment.selected ? Theme.surfaceText : Theme.primaryText
|
||||
visible: segment.selected
|
||||
opacity: segment.selected ? 1 : 0
|
||||
scale: segment.selected ? 1 : 0.6
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: buttonText
|
||||
text: typeof modelData === "string" ? modelData : modelData.text || ""
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: segment.selected ? Font.Medium : Font.Normal
|
||||
color: segment.selected ? Theme.surfaceText : Theme.primaryText
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: root.selectItem(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import qs.Widgets
|
||||
Item {
|
||||
id: toggle
|
||||
|
||||
// API
|
||||
property bool checked: false
|
||||
property bool enabled: true
|
||||
property bool toggling: false
|
||||
@@ -17,13 +18,15 @@ Item {
|
||||
|
||||
readonly property bool showText: text && !hideText
|
||||
|
||||
width: showText ? parent.width : 48
|
||||
height: showText ? 60 : 24
|
||||
readonly property int trackWidth: 52
|
||||
readonly property int trackHeight: 30
|
||||
readonly property int insetCircle: 24
|
||||
|
||||
width: showText ? parent.width : trackWidth
|
||||
height: showText ? 60 : trackHeight
|
||||
|
||||
function handleClick() {
|
||||
if (!enabled) {
|
||||
return
|
||||
}
|
||||
if (!enabled) return
|
||||
checked = !checked
|
||||
clicked()
|
||||
toggled(checked)
|
||||
@@ -31,7 +34,6 @@ Item {
|
||||
|
||||
StyledRect {
|
||||
id: background
|
||||
|
||||
anchors.fill: parent
|
||||
radius: showText ? Theme.cornerRadius : 0
|
||||
color: showText ? Theme.surfaceHover : "transparent"
|
||||
@@ -80,26 +82,35 @@ Item {
|
||||
StyledRect {
|
||||
id: toggleTrack
|
||||
|
||||
width: text ? 48 : parent.width
|
||||
height: text ? 24 : parent.height
|
||||
width: showText ? trackWidth : Math.max(parent.width, trackWidth)
|
||||
height: showText ? trackHeight : Math.max(parent.height, trackHeight)
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: text ? Theme.spacingM : 0
|
||||
anchors.rightMargin: showText ? Theme.spacingM : 0
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
radius: height / 2
|
||||
|
||||
color: (checked && enabled) ? Theme.primary : Theme.surfaceVariantAlpha
|
||||
opacity: toggling ? 0.6 : (enabled ? 1 : 0.4)
|
||||
|
||||
StyledRect {
|
||||
id: toggleHandle
|
||||
border.color: (!checked || !enabled) ? Theme.outline : "transparent"
|
||||
|
||||
width: 20
|
||||
height: 20
|
||||
radius: 10
|
||||
color: Theme.surface
|
||||
readonly property int pad: Math.round((height - thumb.width) / 2)
|
||||
readonly property int edgeLeft: pad
|
||||
readonly property int edgeRight: width - thumb.width - pad
|
||||
|
||||
StyledRect {
|
||||
id: thumb
|
||||
|
||||
width: (checked && enabled) ? insetCircle : insetCircle - 4
|
||||
height: (checked && enabled) ? insetCircle : insetCircle - 4
|
||||
radius: width / 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
x: (checked && enabled) ? parent.width - width - 2 : 2
|
||||
border.color: Qt.rgba(0, 0, 0, 0.1)
|
||||
border.width: 1
|
||||
|
||||
color: (checked && enabled) ? Theme.surface : Theme.outline
|
||||
border.color: (checked && enabled) ? Theme.outline : Theme.outline
|
||||
border.width: (checked && enabled) ? 1 : 2
|
||||
|
||||
x: (checked && enabled) ? toggleTrack.edgeRight : toggleTrack.edgeLeft
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
@@ -108,6 +119,48 @@ Item {
|
||||
easing.bezierCurve: Appearance.anim.curves.emphasizedDecel
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Appearance.anim.durations.normal
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Appearance.anim.curves.emphasized
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation {
|
||||
duration: Appearance.anim.durations.normal
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Appearance.anim.curves.emphasized
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
id: checkIcon
|
||||
anchors.centerIn: parent
|
||||
name: "check"
|
||||
size: 20
|
||||
color: Theme.surfaceText
|
||||
filled: true
|
||||
opacity: checked && enabled ? 1 : 0
|
||||
scale: checked && enabled ? 1 : 0.6
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
}
|
||||
}
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasized
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StateLayer {
|
||||
|
||||
Reference in New Issue
Block a user