mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-09 06:58:29 -04:00
feat(theme): add extract dynamic theme to JSON file (#3009)
* feat(theme): add extract current theme to JSON file
Adds an 'Extract' button in Settings > Theme Color that exports the
current theme (generic/dynamic/custom/registry) to a dual-mode dark+light
JSON file via the DMS file save dialog.
* refactor(theme): simplify extract button to single DankButton
* refactor(theme): move extract button inside dynamic theme section
* fix(theme): address review feedback on extract theme save
* refactor: utilize dankActionButton
---------
(cherry picked from commit bde4decc5d)
This commit is contained in:
committed by
dms-ci[bot]
parent
0313e96e8e
commit
f971b6bcff
@@ -436,6 +436,10 @@ Singleton {
|
|||||||
|
|
||||||
function getMatugenColor(path, fallback) {
|
function getMatugenColor(path, fallback) {
|
||||||
const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark";
|
const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark";
|
||||||
|
return getMatugenColorForMode(colorMode, path, fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMatugenColorForMode(colorMode, path, fallback) {
|
||||||
let cur = matugenColors && matugenColors.colors && matugenColors.colors[colorMode];
|
let cur = matugenColors && matugenColors.colors && matugenColors.colors[colorMode];
|
||||||
for (const part of path.split(".")) {
|
for (const part of path.split(".")) {
|
||||||
if (!cur || typeof cur !== "object" || !(part in cur))
|
if (!cur || typeof cur !== "object" || !(part in cur))
|
||||||
@@ -445,6 +449,82 @@ Singleton {
|
|||||||
return cur || fallback;
|
return cur || fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function extractCurrentTheme(themeName) {
|
||||||
|
var name = themeName || "Extracted Theme";
|
||||||
|
var dark = {};
|
||||||
|
var light = {};
|
||||||
|
|
||||||
|
if (currentTheme === dynamic) {
|
||||||
|
dark = buildExtractedDynamicMode("dark", name + " Dark");
|
||||||
|
light = buildExtractedDynamicMode("light", name + " Light");
|
||||||
|
} else if (currentTheme === custom && customThemeRawData) {
|
||||||
|
var rawDark = customThemeRawData.dark || null;
|
||||||
|
var rawLight = customThemeRawData.light || null;
|
||||||
|
if (rawDark) {
|
||||||
|
dark = JSON.parse(JSON.stringify(rawDark));
|
||||||
|
if (!dark.name)
|
||||||
|
dark.name = name + " Dark";
|
||||||
|
} else if (rawLight) {
|
||||||
|
dark = buildExtractedDynamicMode("dark", name + " Dark");
|
||||||
|
} else {
|
||||||
|
dark = currentThemeData ? JSON.parse(JSON.stringify(currentThemeData)) : {};
|
||||||
|
dark.name = name + " Dark";
|
||||||
|
}
|
||||||
|
if (rawLight) {
|
||||||
|
light = JSON.parse(JSON.stringify(rawLight));
|
||||||
|
if (!light.name)
|
||||||
|
light.name = name + " Light";
|
||||||
|
} else if (rawDark) {
|
||||||
|
light = buildExtractedDynamicMode("light", name + " Light");
|
||||||
|
} else {
|
||||||
|
light = currentThemeData ? JSON.parse(JSON.stringify(currentThemeData)) : {};
|
||||||
|
light.name = name + " Light";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var darkTheme = StockThemes.getThemeByName(currentTheme, false);
|
||||||
|
var lightTheme = StockThemes.getThemeByName(currentTheme, true);
|
||||||
|
dark = darkTheme ? JSON.parse(JSON.stringify(darkTheme)) : {};
|
||||||
|
light = lightTheme ? JSON.parse(JSON.stringify(lightTheme)) : {};
|
||||||
|
dark.name = name + " Dark";
|
||||||
|
light.name = name + " Light";
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSON.stringify({
|
||||||
|
dark: dark,
|
||||||
|
light: light
|
||||||
|
}, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildExtractedDynamicMode(colorMode, name) {
|
||||||
|
return {
|
||||||
|
"name": name,
|
||||||
|
"primary": getMatugenColorForMode(colorMode, "primary", "#42a5f5"),
|
||||||
|
"primaryText": getMatugenColorForMode(colorMode, "on_primary", "#ffffff"),
|
||||||
|
"primaryContainer": getMatugenColorForMode(colorMode, "primary_container", "#1976d2"),
|
||||||
|
"secondary": getMatugenColorForMode(colorMode, "secondary", "#8ab4f8"),
|
||||||
|
"secondaryContainer": getMatugenColorForMode(colorMode, "secondary_container", getMatugenColorForMode(colorMode, "surface_container_high", "#292b2f")),
|
||||||
|
"tertiary": getMatugenColorForMode(colorMode, "tertiary", "#efb8c8"),
|
||||||
|
"tertiaryContainer": getMatugenColorForMode(colorMode, "tertiary_container", getMatugenColorForMode(colorMode, "surface_container_high", "#292b2f")),
|
||||||
|
"surface": getMatugenColorForMode(colorMode, "surface", "#1a1c1e"),
|
||||||
|
"surfaceText": getMatugenColorForMode(colorMode, "on_background", "#e3e8ef"),
|
||||||
|
"surfaceVariant": getMatugenColorForMode(colorMode, "surface_variant", "#44464f"),
|
||||||
|
"surfaceVariantText": getMatugenColorForMode(colorMode, "on_surface_variant", "#c4c7c5"),
|
||||||
|
"surfaceTint": getMatugenColorForMode(colorMode, "surface_tint", "#8ab4f8"),
|
||||||
|
"background": getMatugenColorForMode(colorMode, "background", "#1a1c1e"),
|
||||||
|
"backgroundText": getMatugenColorForMode(colorMode, "on_background", "#e3e8ef"),
|
||||||
|
"outline": getMatugenColorForMode(colorMode, "outline", "#8e918f"),
|
||||||
|
"surfaceContainerLowest": getMatugenColorForMode(colorMode, "surface_container_lowest", "#0e1013"),
|
||||||
|
"surfaceContainerLow": getMatugenColorForMode(colorMode, "surface_container_low", "#181a1d"),
|
||||||
|
"surfaceContainer": getMatugenColorForMode(colorMode, "surface_container", "#1e2023"),
|
||||||
|
"surfaceContainerHigh": getMatugenColorForMode(colorMode, "surface_container_high", "#292b2f"),
|
||||||
|
"surfaceContainerHighest": getMatugenColorForMode(colorMode, "surface_container_highest", "#343740"),
|
||||||
|
"error": getMatugenColorForMode(colorMode, "error", "#F2B8B5"),
|
||||||
|
"warning": "#FF9800",
|
||||||
|
"info": "#2196F3",
|
||||||
|
"success": "#4CAF50"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
readonly property var currentThemeData: {
|
readonly property var currentThemeData: {
|
||||||
if (currentTheme === "custom") {
|
if (currentTheme === "custom") {
|
||||||
return customThemeData || StockThemes.getThemeByName("purple", isLightMode);
|
return customThemeData || StockThemes.getThemeByName("purple", isLightMode);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import QtCore
|
import QtCore
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Modals.FileBrowser
|
import qs.Modals.FileBrowser
|
||||||
@@ -13,6 +14,7 @@ Item {
|
|||||||
id: themeColorsTab
|
id: themeColorsTab
|
||||||
|
|
||||||
property var parentModal: null
|
property var parentModal: null
|
||||||
|
property string pendingExtractJson: ""
|
||||||
readonly property bool connectedFrameModeActive: SettingsData.connectedFrameModeActive
|
readonly property bool connectedFrameModeActive: SettingsData.connectedFrameModeActive
|
||||||
readonly property bool frameModeActive: SettingsData.frameEnabled
|
readonly property bool frameModeActive: SettingsData.frameEnabled
|
||||||
property var cachedIconThemes: SettingsData.availableIconThemes
|
property var cachedIconThemes: SettingsData.availableIconThemes
|
||||||
@@ -564,7 +566,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
width: parent.width - 120 - Theme.spacingM
|
width: parent.width - 120 - Theme.spacingM - 36 - Theme.spacingM
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
@@ -586,6 +588,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
|
id: wallpaperPathText
|
||||||
text: {
|
text: {
|
||||||
if (ToastService.wallpaperErrorStatus === "error")
|
if (ToastService.wallpaperErrorStatus === "error")
|
||||||
return I18n.tr("Wallpaper processing failed", "wallpaper processing error");
|
return I18n.tr("Wallpaper processing failed", "wallpaper processing error");
|
||||||
@@ -603,6 +606,22 @@ Item {
|
|||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
buttonSize: 36
|
||||||
|
iconName: "download"
|
||||||
|
iconSize: Theme.iconSize
|
||||||
|
backgroundColor: Theme.primaryHover
|
||||||
|
iconColor: Theme.primary
|
||||||
|
tooltipText: I18n.tr("Extract theme to JSON", "extract theme tooltip")
|
||||||
|
anchors.bottom: wallpaperPathText.bottom
|
||||||
|
onClicked: {
|
||||||
|
pendingExtractJson = Theme.extractCurrentTheme();
|
||||||
|
saveBrowserLoader.active = true;
|
||||||
|
if (saveBrowserLoader.item)
|
||||||
|
saveBrowserLoader.item.open();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsDropdownRow {
|
SettingsDropdownRow {
|
||||||
@@ -2977,6 +2996,28 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LazyLoader {
|
||||||
|
id: saveBrowserLoader
|
||||||
|
active: false
|
||||||
|
|
||||||
|
FileBrowserSurfaceModal {
|
||||||
|
id: saveBrowser
|
||||||
|
|
||||||
|
browserTitle: I18n.tr("Save Extracted Theme", "extract theme save dialog title")
|
||||||
|
browserIcon: "download"
|
||||||
|
browserType: "default"
|
||||||
|
fileExtensions: ["*.json"]
|
||||||
|
allowStacking: true
|
||||||
|
saveMode: true
|
||||||
|
defaultFileName: "dms-extracted-theme.json"
|
||||||
|
|
||||||
|
onFileSelected: path => {
|
||||||
|
saveExtractedTheme(pendingExtractJson, Paths.strip(path));
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LazyLoader {
|
LazyLoader {
|
||||||
id: themeBrowserLoader
|
id: themeBrowserLoader
|
||||||
active: false
|
active: false
|
||||||
@@ -2992,4 +3033,26 @@ Item {
|
|||||||
if (themeBrowserLoader.item)
|
if (themeBrowserLoader.item)
|
||||||
themeBrowserLoader.item.show();
|
themeBrowserLoader.item.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileView {
|
||||||
|
id: extractSaveFileView
|
||||||
|
blockWrites: true
|
||||||
|
preload: false
|
||||||
|
atomicWrites: true
|
||||||
|
printErrors: true
|
||||||
|
|
||||||
|
onSaved: {
|
||||||
|
ToastService.showInfo(I18n.tr("Theme extracted to: %1", "extract theme success").arg(Paths.strip(extractSaveFileView.path)));
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveFailed: error => {
|
||||||
|
ToastService.showError(I18n.tr("Failed to extract theme", "extract theme error"));
|
||||||
|
log.warn("Failed to write extracted theme to " + extractSaveFileView.path + ": " + error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveExtractedTheme(json, outputPath) {
|
||||||
|
extractSaveFileView.path = outputPath;
|
||||||
|
extractSaveFileView.setText(json);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user