mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-21 10:44:01 -04:00
settings/wallpaper: more restyle to appearance header
This commit is contained in:
@@ -79,6 +79,104 @@ func addVariantsInfo(info *ThemeInfo, variants *themes.ThemeVariants) {
|
||||
}
|
||||
}
|
||||
|
||||
func paletteInfo(theme *themes.Theme) *PaletteInfo {
|
||||
dark, light := defaultSchemes(theme)
|
||||
info := &PaletteInfo{Dark: swatchColors(dark), Light: swatchColors(light)}
|
||||
if info.Dark == nil && info.Light == nil {
|
||||
return nil
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
func defaultSchemes(theme *themes.Theme) (themes.ColorScheme, themes.ColorScheme) {
|
||||
v := theme.Variants
|
||||
if v == nil {
|
||||
return theme.Dark, theme.Light
|
||||
}
|
||||
if v.Type == "multi" {
|
||||
return multiScheme(v, theme.Dark, false), multiScheme(v, theme.Light, true)
|
||||
}
|
||||
for _, opt := range v.Options {
|
||||
if opt.ID == v.Default {
|
||||
return overlay(theme.Dark, opt.Dark), overlay(theme.Light, opt.Light)
|
||||
}
|
||||
}
|
||||
if len(v.Options) > 0 {
|
||||
return overlay(theme.Dark, v.Options[0].Dark), overlay(theme.Light, v.Options[0].Light)
|
||||
}
|
||||
return theme.Dark, theme.Light
|
||||
}
|
||||
|
||||
// variants and flavors often carry surfaces only; the accent colors stay on the base scheme
|
||||
func overlay(base, top themes.ColorScheme) themes.ColorScheme {
|
||||
pick := func(fallback, value string) string {
|
||||
if value != "" {
|
||||
return value
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
base.Primary = pick(base.Primary, top.Primary)
|
||||
base.Secondary = pick(base.Secondary, top.Secondary)
|
||||
base.PrimaryContainer = pick(base.PrimaryContainer, top.PrimaryContainer)
|
||||
base.Info = pick(base.Info, top.Info)
|
||||
base.Error = pick(base.Error, top.Error)
|
||||
base.Warning = pick(base.Warning, top.Warning)
|
||||
return base
|
||||
}
|
||||
|
||||
func multiScheme(v *themes.ThemeVariants, base themes.ColorScheme, light bool) themes.ColorScheme {
|
||||
defaults := map[string]string{}
|
||||
if v.Defaults != nil {
|
||||
if light {
|
||||
defaults = v.Defaults.Light
|
||||
} else {
|
||||
defaults = v.Defaults.Dark
|
||||
}
|
||||
}
|
||||
scheme := base
|
||||
flavorID := defaults["flavor"]
|
||||
for _, f := range v.Flavors {
|
||||
if f.ID != flavorID {
|
||||
continue
|
||||
}
|
||||
if light {
|
||||
scheme = overlay(base, f.Light)
|
||||
} else {
|
||||
scheme = overlay(base, f.Dark)
|
||||
}
|
||||
break
|
||||
}
|
||||
for _, a := range v.Accents {
|
||||
if a.ID != defaults["accent"] {
|
||||
continue
|
||||
}
|
||||
if accent, ok := a.FlavorColors[flavorID]; ok {
|
||||
scheme = overlay(scheme, accent)
|
||||
}
|
||||
break
|
||||
}
|
||||
return scheme
|
||||
}
|
||||
|
||||
func swatchColors(scheme themes.ColorScheme) map[string]string {
|
||||
if scheme.Primary == "" {
|
||||
return nil
|
||||
}
|
||||
colors := map[string]string{"primary": scheme.Primary}
|
||||
for key, value := range map[string]string{
|
||||
"secondary": scheme.Secondary,
|
||||
"primaryContainer": scheme.PrimaryContainer,
|
||||
"info": scheme.Info,
|
||||
"error": scheme.Error,
|
||||
"warning": scheme.Warning,
|
||||
} {
|
||||
if value != "" {
|
||||
colors[key] = value
|
||||
}
|
||||
}
|
||||
return colors
|
||||
}
|
||||
|
||||
func HandleListInstalled(conn *ipc.ConnWriter, req ipc.Request) {
|
||||
manager, err := themes.NewManager()
|
||||
if err != nil {
|
||||
@@ -120,6 +218,7 @@ func HandleListInstalled(conn *ipc.ConnWriter, req ipc.Request) {
|
||||
HasUpdate: hasUpdate,
|
||||
}
|
||||
addVariantsInfo(&info, theme.Variants)
|
||||
info.Palette = paletteInfo(&theme)
|
||||
result = append(result, info)
|
||||
} else {
|
||||
installed, err := manager.GetInstalledTheme(id)
|
||||
@@ -141,6 +240,7 @@ func HandleListInstalled(conn *ipc.ConnWriter, req ipc.Request) {
|
||||
FirstParty: isFirstParty(installed.Author),
|
||||
}
|
||||
addVariantsInfo(&info, installed.Variants)
|
||||
info.Palette = paletteInfo(installed)
|
||||
result = append(result, info)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package themes
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/themes"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestPaletteInfoResolvesDefaultFlavorAndAccent(t *testing.T) {
|
||||
theme := &themes.Theme{
|
||||
Variants: &themes.ThemeVariants{
|
||||
Type: "multi",
|
||||
Defaults: &themes.MultiVariantDefaults{
|
||||
Dark: map[string]string{"flavor": "mocha", "accent": "mauve"},
|
||||
Light: map[string]string{"flavor": "latte", "accent": "mauve"},
|
||||
},
|
||||
Flavors: []themes.ThemeFlavor{
|
||||
{ID: "latte", Light: themes.ColorScheme{Surface: "#eff1f5", Info: "#04a5e5"}},
|
||||
{ID: "mocha", Dark: themes.ColorScheme{Surface: "#1e1e2e", Info: "#89dceb"}},
|
||||
},
|
||||
Accents: []themes.ThemeAccent{
|
||||
{ID: "rosewater", FlavorColors: map[string]themes.ColorScheme{"mocha": {Primary: "#f5e0dc"}}},
|
||||
{ID: "mauve", FlavorColors: map[string]themes.ColorScheme{
|
||||
"mocha": {Primary: "#cba6f7", Secondary: "#f5c2e7"},
|
||||
"latte": {Primary: "#8839ef", Secondary: "#ea76cb"},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
palette := paletteInfo(theme)
|
||||
|
||||
require.NotNil(t, palette)
|
||||
require.Equal(t, map[string]string{"primary": "#cba6f7", "secondary": "#f5c2e7", "info": "#89dceb"}, palette.Dark)
|
||||
require.Equal(t, map[string]string{"primary": "#8839ef", "secondary": "#ea76cb", "info": "#04a5e5"}, palette.Light)
|
||||
}
|
||||
|
||||
func TestPaletteInfoOverlaysDefaultOptionOnBase(t *testing.T) {
|
||||
theme := &themes.Theme{
|
||||
Dark: themes.ColorScheme{Primary: "#000000", Secondary: "#111111"},
|
||||
Light: themes.ColorScheme{Primary: "#eeeeee"},
|
||||
Variants: &themes.ThemeVariants{
|
||||
Default: "ocean",
|
||||
Options: []themes.ThemeVariant{
|
||||
{ID: "forest", Dark: themes.ColorScheme{Primary: "#00ff00"}},
|
||||
{ID: "ocean", Dark: themes.ColorScheme{Surface: "#001020", Secondary: "#0000ff"}, Light: themes.ColorScheme{Primary: "#0000aa"}},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
palette := paletteInfo(theme)
|
||||
|
||||
require.Equal(t, map[string]string{"primary": "#000000", "secondary": "#0000ff"}, palette.Dark)
|
||||
require.Equal(t, map[string]string{"primary": "#0000aa"}, palette.Light)
|
||||
}
|
||||
@@ -35,6 +35,11 @@ type VariantsInfo struct {
|
||||
Accents []AccentInfo `json:"accents,omitempty"`
|
||||
}
|
||||
|
||||
type PaletteInfo struct {
|
||||
Dark map[string]string `json:"dark,omitempty"`
|
||||
Light map[string]string `json:"light,omitempty"`
|
||||
}
|
||||
|
||||
type ThemeInfo struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
@@ -48,5 +53,6 @@ type ThemeInfo struct {
|
||||
HasUpdate bool `json:"hasUpdate,omitempty"`
|
||||
HasVariants bool `json:"hasVariants,omitempty"`
|
||||
Variants *VariantsInfo `json:"variants,omitempty"`
|
||||
Palette *PaletteInfo `json:"palette,omitempty"`
|
||||
WCAG *themes.ThemeWCAG `json:"wcag,omitempty"`
|
||||
}
|
||||
|
||||
@@ -24,13 +24,14 @@ Singleton {
|
||||
|
||||
readonly property var _pinKeys: ["brightnessDevicePins", "wifiNetworkPins", "bluetoothDevicePins", "audioInputDevicePins", "audioOutputDevicePins"]
|
||||
readonly property var _historyKeys: ["browserUsageHistory", "filePickerUsageHistory"]
|
||||
readonly property var _dataKeys: ["wallpaperLastPath", "profileLastPath", "fileBrowserSettings", "processFilterTypes", "pluginViewSort", "pluginViewFilter", "dashFocusCardId", "mediaLyricsOpen"].concat(_pinKeys, _historyKeys)
|
||||
readonly property var _dataKeys: ["wallpaperLastPath", "profileLastPath", "fileBrowserSettings", "processFilterTypes", "pluginViewSort", "pluginViewFilter", "dashFocusCardId", "mediaLyricsOpen", "matugenPreviews"].concat(_pinKeys, _historyKeys)
|
||||
|
||||
property string wallpaperLastPath: ""
|
||||
property string profileLastPath: ""
|
||||
property string pluginViewFilter: "enabled"
|
||||
property string dashFocusCardId: ""
|
||||
property bool mediaLyricsOpen: false
|
||||
property var matugenPreviews: ({})
|
||||
property var pluginViewSort: ({
|
||||
by: "modified",
|
||||
descending: true
|
||||
@@ -182,6 +183,7 @@ Singleton {
|
||||
pluginViewFilter = ["all", "enabled", "disabled", "updates"].includes(cache.pluginViewFilter) ? cache.pluginViewFilter : "enabled";
|
||||
dashFocusCardId = typeof cache.dashFocusCardId === "string" ? cache.dashFocusCardId : "";
|
||||
mediaLyricsOpen = cache.mediaLyricsOpen === true;
|
||||
matugenPreviews = typeof cache.matugenPreviews?.key === "string" ? cache.matugenPreviews : {};
|
||||
const pluginSort = cache.pluginViewSort;
|
||||
pluginViewSort = {
|
||||
by: ["name", "author", "modified"].includes(pluginSort?.by) ? pluginSort.by : "modified",
|
||||
@@ -248,6 +250,7 @@ Singleton {
|
||||
"pluginViewFilter": pluginViewFilter,
|
||||
"dashFocusCardId": dashFocusCardId,
|
||||
"mediaLyricsOpen": mediaLyricsOpen,
|
||||
"matugenPreviews": matugenPreviews,
|
||||
"fileBrowserSettings": fileBrowserSettings,
|
||||
"configVersion": cacheConfigVersion
|
||||
};
|
||||
|
||||
@@ -15,82 +15,17 @@ Item {
|
||||
property var parentModal: null
|
||||
property string pendingExtractJson: ""
|
||||
property var cachedSourceModes: Theme.availableSourceModes.map(option => option.label)
|
||||
property var matugenSchemePreviews: ({})
|
||||
property string matugenPreviewRequestKey: ""
|
||||
property string matugenPreviewLoadedKey: ""
|
||||
readonly property string matugenPreviewSource: SettingsData.matugenSeedColor || Theme.getMatugenColor("source_color", Theme.primary).toString()
|
||||
readonly property string matugenPreviewImage: (!SettingsData.matugenSeedColor && Theme.rawWallpaperPath && !Theme.rawWallpaperPath.startsWith("#")) ? Theme.rawWallpaperPath : ""
|
||||
readonly property string matugenPreviewKey: matugenPreviewSource + "|" + (SettingsData.matugenContrast ?? 0) + "|" + matugenPreviewImage + "|" + SettingsData.matugenSpec
|
||||
readonly property var currentPalette: ThemePalette.pick({
|
||||
"primary": Theme.primary,
|
||||
"secondary": Theme.secondary,
|
||||
"tertiary": Theme.tertiary,
|
||||
"primaryContainer": Theme.primaryContainer,
|
||||
"info": Theme.info,
|
||||
"error": Theme.error,
|
||||
"warning": Theme.warning
|
||||
})
|
||||
property bool matugenPreviewFailed: false
|
||||
readonly property bool matugenPreviewsReady: matugenPreviewLoadedKey === matugenPreviewKey || matugenPreviewFailed || !Theme.matugenAvailable
|
||||
onMatugenPreviewKeyChanged: refreshMatugenSchemePreviews()
|
||||
readonly property string matugenPreviewKey: MatugenPreviewService.key
|
||||
readonly property bool matugenAvailable: Theme.matugenAvailable
|
||||
onMatugenPreviewKeyChanged: MatugenPreviewService.refresh()
|
||||
onMatugenAvailableChanged: MatugenPreviewService.refresh()
|
||||
property var installedRegistryThemes: []
|
||||
readonly property var matugenSchemeOptions: {
|
||||
const mode = SessionData.isLightMode ? "light" : "dark";
|
||||
const options = [];
|
||||
for (const option of Theme.availableMatugenSchemes) {
|
||||
if (option.value === "scheme-smart" && !DMSService.matugenSmartSupported)
|
||||
continue;
|
||||
const colors = (matugenSchemePreviews[option.value] ?? matugenSchemePreviews["scheme-tonal-spot"])?.[mode];
|
||||
// a dms binary older than the tri-color preview returns the primary hex as a plain string
|
||||
const primary = typeof colors === "string" ? colors : (colors?.primary ?? Theme.primary.toString());
|
||||
options.push({
|
||||
"value": option.value,
|
||||
"label": option.label,
|
||||
"primary": primary,
|
||||
"secondary": colors?.secondary ?? primary,
|
||||
"tertiary": colors?.tertiary ?? primary
|
||||
});
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
function refreshMatugenSchemePreviews() {
|
||||
if (!Theme.matugenAvailable)
|
||||
return;
|
||||
const requestKey = matugenPreviewKey;
|
||||
if (requestKey === matugenPreviewLoadedKey || requestKey === matugenPreviewRequestKey)
|
||||
return;
|
||||
matugenPreviewRequestKey = requestKey;
|
||||
matugenPreviewFailed = false;
|
||||
|
||||
const args = [Proc.dmsBin, "matugen", "preview", "--source-color", matugenPreviewSource, "--contrast", String(SettingsData.matugenContrast ?? 0)];
|
||||
if (matugenPreviewImage)
|
||||
args.push("--image", matugenPreviewImage);
|
||||
if (SettingsData.matugenSpec === "2025")
|
||||
args.push("--spec", "2025");
|
||||
Proc.runCommand("", args, (output, exitCode) => {
|
||||
if (requestKey !== themeColorsTab.matugenPreviewRequestKey)
|
||||
return;
|
||||
themeColorsTab.matugenPreviewRequestKey = "";
|
||||
if (exitCode !== 0) {
|
||||
themeColorsTab.matugenPreviewFailed = true;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
themeColorsTab.matugenSchemePreviews = JSON.parse(output.trim());
|
||||
themeColorsTab.matugenPreviewLoadedKey = requestKey;
|
||||
} catch (e) {
|
||||
themeColorsTab.matugenPreviewFailed = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (DMSService.dmsAvailable)
|
||||
DMSService.listInstalledThemes();
|
||||
if (PopoutService.pendingThemeInstall)
|
||||
Qt.callLater(() => showThemeBrowser());
|
||||
refreshMatugenSchemePreviews();
|
||||
MatugenPreviewService.refresh();
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -108,13 +43,6 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Theme
|
||||
function onMatugenAvailableChanged() {
|
||||
themeColorsTab.refreshMatugenSchemePreviews();
|
||||
}
|
||||
}
|
||||
|
||||
SettingsPage {
|
||||
id: mainColumn
|
||||
|
||||
@@ -237,73 +165,9 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
SettingsThemeColorDots {
|
||||
width: parent.width
|
||||
height: genericColorGrid.implicitHeight + Math.ceil(genericColorGrid.dotSize * 0.05)
|
||||
visible: Theme.currentThemeCategory === "generic" && Theme.currentTheme !== Theme.dynamic && Theme.currentThemeName !== "custom"
|
||||
|
||||
Grid {
|
||||
id: genericColorGrid
|
||||
property var colorList: ["blue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral", "monochrome"]
|
||||
property int dotSize: Theme.minimumTouchTargetSize
|
||||
columns: Math.ceil(colorList.length / 2)
|
||||
rowSpacing: Theme.spacingS
|
||||
columnSpacing: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Repeater {
|
||||
model: genericColorGrid.colorList
|
||||
|
||||
Rectangle {
|
||||
required property string modelData
|
||||
property string themeName: modelData
|
||||
readonly property var colors: Theme.getThemeColors(themeName)
|
||||
readonly property var palette: ThemePalette.pick(colors)
|
||||
readonly property bool isActive: Theme.currentThemeName === themeName && Theme.currentTheme !== Theme.dynamic
|
||||
width: genericColorGrid.dotSize
|
||||
height: genericColorGrid.dotSize
|
||||
radius: width / 2
|
||||
color: "transparent"
|
||||
scale: isActive ? 1.1 : 1
|
||||
|
||||
DankPaletteSwatch {
|
||||
anchors.fill: parent
|
||||
primaryColor: parent.palette.primary
|
||||
secondaryColor: parent.palette.secondary
|
||||
tertiaryColor: parent.palette.tertiary
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "check"
|
||||
size: Theme.iconSizeMedium
|
||||
color: Theme.isLightColor(parent.colors.primary) ? Theme.contrastDark : Theme.contrastLight
|
||||
visible: parent.isActive
|
||||
}
|
||||
|
||||
DankTooltipHost {
|
||||
text: parent.colors.name
|
||||
target: parent
|
||||
hoverArea: mouseArea
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: Theme.switchTheme(parent.themeName)
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
@@ -431,10 +295,10 @@ Item {
|
||||
|
||||
SettingsSwatchGrid {
|
||||
id: schemeGrid
|
||||
options: themeColorsTab.matugenSchemeOptions
|
||||
options: MatugenPreviewService.schemeOptions
|
||||
currentValue: SettingsData.matugenScheme
|
||||
enabled: themeColorsTab.matugenPreviewsReady
|
||||
opacity: themeColorsTab.matugenPreviewsReady ? 1 : Theme.pendingOpacity
|
||||
enabled: MatugenPreviewService.ready
|
||||
opacity: MatugenPreviewService.ready ? 1 : Theme.pendingOpacity
|
||||
onSelected: value => SettingsData.setMatugenScheme(value)
|
||||
|
||||
Behavior on opacity {
|
||||
@@ -446,7 +310,7 @@ Item {
|
||||
|
||||
DankSpinner {
|
||||
anchors.centerIn: parent
|
||||
running: !themeColorsTab.matugenPreviewsReady
|
||||
running: !MatugenPreviewService.ready
|
||||
visible: running
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,40 @@ Column {
|
||||
"error": Theme.error,
|
||||
"warning": Theme.warning
|
||||
})
|
||||
readonly property string modeLabel: SessionData.isLightMode ? I18n.tr("Light", "adjective, wallpaper thumbnail label for light mode") : I18n.tr("Dark", "adjective, wallpaper thumbnail label for dark mode")
|
||||
readonly property bool dynamicTheme: Theme.currentTheme === Theme.dynamic && Theme.currentThemeCategory !== "registry"
|
||||
readonly property bool genericTheme: Theme.currentThemeCategory === "generic" && Theme.currentTheme !== Theme.dynamic && Theme.currentThemeName !== "custom"
|
||||
readonly property string themesDir: Quickshell.env("HOME") + "/.config/DankMaterialShell/themes"
|
||||
readonly property var installedRegistryThemes: DMSService.installedThemes
|
||||
readonly property var registryOptions: {
|
||||
const mode = Theme.isLightMode ? "light" : "dark";
|
||||
return installedRegistryThemes.map(theme => {
|
||||
const palette = ThemePalette.pick(theme.palette?.[mode] ?? theme.palette?.dark) ?? {};
|
||||
return {
|
||||
"value": theme.sourceDir || theme.id,
|
||||
"label": theme.name,
|
||||
"primary": palette.primary ?? Theme.primary.toString(),
|
||||
"secondary": palette.secondary,
|
||||
"tertiary": palette.tertiary
|
||||
};
|
||||
});
|
||||
}
|
||||
readonly property string activeRegistryTheme: {
|
||||
if (Theme.currentThemeName !== "custom" || !SettingsData.customThemeFile)
|
||||
return "";
|
||||
for (const theme of installedRegistryThemes) {
|
||||
if (SettingsData.customThemeFile.endsWith((theme.sourceDir || theme.id) + "/theme.json"))
|
||||
return theme.sourceDir || theme.id;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
readonly property bool registryGridShown: !dynamicTheme && !genericTheme && registryOptions.length > 0
|
||||
readonly property bool registryPending: !dynamicTheme && !genericTheme && DMSService.dmsAvailable && !DMSService.installedThemesLoaded
|
||||
readonly property string matugenPreviewKey: MatugenPreviewService.key
|
||||
readonly property bool matugenAvailable: Theme.matugenAvailable
|
||||
onMatugenPreviewKeyChanged: refreshPreviews()
|
||||
onMatugenAvailableChanged: refreshPreviews()
|
||||
onDynamicThemeChanged: refreshPreviews()
|
||||
onVisibleChanged: refreshPreviews()
|
||||
readonly property string colorModeStatus: {
|
||||
if (SettingsData.matugenSmartMode)
|
||||
return I18n.tr("Wallpaper");
|
||||
@@ -58,6 +91,14 @@ Column {
|
||||
WallpaperCyclingService.cyclingActive;
|
||||
SettingsData.detectAvailableIconThemes();
|
||||
SettingsData.detectAvailableCursorThemes();
|
||||
refreshPreviews();
|
||||
if (DMSService.dmsAvailable)
|
||||
DMSService.listInstalledThemes();
|
||||
}
|
||||
|
||||
function refreshPreviews() {
|
||||
if (visible && dynamicTheme)
|
||||
MatugenPreviewService.refresh();
|
||||
}
|
||||
|
||||
function firstScreenName() {
|
||||
@@ -164,89 +205,11 @@ Column {
|
||||
ToastService.showError(I18n.tr("Missing Environment Variables", "qt theme env error title"), I18n.tr("You need to set one of:\nQT_QPA_PLATFORMTHEME=gtk3 OR\nQT_QPA_PLATFORMTHEME=qt6ct OR\nQT_QPA_PLATFORMTHEME=qtengine\nas environment variables, and then restart the shell.\n\nOnly qt6ct requires qt6ct-kde to be installed.", "qt theme env error body"));
|
||||
}
|
||||
|
||||
component QuickTile: Rectangle {
|
||||
id: tile
|
||||
|
||||
property string title: ""
|
||||
property string hint: ""
|
||||
default property alias leading: leadingSlot.data
|
||||
|
||||
signal clicked
|
||||
|
||||
width: parent.width
|
||||
height: Theme.listItemTwoLineHeight
|
||||
radius: Theme.cornerRadiusM
|
||||
color: Theme.foregroundColor(Theme.chipSurface, true)
|
||||
|
||||
activeFocusOnTab: true
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: title
|
||||
Accessible.description: hint
|
||||
Accessible.onPressAction: tile.clicked()
|
||||
Keys.onSpacePressed: tile.clicked()
|
||||
Keys.onReturnPressed: tile.clicked()
|
||||
|
||||
FocusRing {}
|
||||
|
||||
Item {
|
||||
id: leadingSlot
|
||||
width: Theme.avatarSize
|
||||
height: Theme.avatarSize
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: leadingSlot.right
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.right: chevron.left
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: tile.title
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.surfaceText
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: tile.hint
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
id: chevron
|
||||
name: "chevron_right"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceVariantText
|
||||
rotation: I18n.isRtl ? 180 : 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StateLayer {
|
||||
stateColor: Theme.surfaceText
|
||||
cornerRadius: tile.radius
|
||||
onClicked: tile.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
tab: "wallpaper"
|
||||
tags: ["background", "image", "picture", "light", "dark", "mode", "theme", "color", "palette"]
|
||||
title: I18n.tr("Appearance")
|
||||
settingKey: "wallpaper"
|
||||
|
||||
SettingsDropdownRow {
|
||||
tab: "wallpaper"
|
||||
tags: ["monitor", "display", "screen"]
|
||||
@@ -272,72 +235,187 @@ Column {
|
||||
|
||||
SettingsWallpaperThumb {
|
||||
width: hero.thumbWidth
|
||||
height: {
|
||||
const natural = width * SettingsMetrics.wallpaperThumbRatio;
|
||||
if (hero.stacked)
|
||||
return natural;
|
||||
return root.registryPending ? Math.max(natural, side.implicitHeight) : side.implicitHeight;
|
||||
}
|
||||
path: root.currentWallpaper
|
||||
badge: root.perMode ? root.modeLabel : ""
|
||||
onBrowse: root.openBrowser()
|
||||
onPickColor: root.pickColor()
|
||||
onClear: root.clearWallpaper()
|
||||
}
|
||||
|
||||
Column {
|
||||
id: side
|
||||
width: hero.stacked ? hero.width : hero.width - hero.thumbWidth - hero.spacing
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankButtonGroup {
|
||||
Row {
|
||||
id: modeRow
|
||||
width: parent.width
|
||||
fillWidth: true
|
||||
checkEnabled: false
|
||||
model: [
|
||||
{
|
||||
"text": I18n.tr("Light", "adjective, wallpaper thumbnail label for light mode"),
|
||||
"icon": "light_mode"
|
||||
},
|
||||
{
|
||||
"text": I18n.tr("Dark", "adjective, wallpaper thumbnail label for dark mode"),
|
||||
"icon": "dark_mode"
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankButtonGroup {
|
||||
width: parent.width - scheduleButton.width - parent.spacing
|
||||
fillWidth: true
|
||||
checkEnabled: false
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
model: [
|
||||
{
|
||||
"text": I18n.tr("Light", "adjective, wallpaper thumbnail label for light mode"),
|
||||
"icon": "light_mode"
|
||||
},
|
||||
{
|
||||
"text": I18n.tr("Dark", "adjective, wallpaper thumbnail label for dark mode"),
|
||||
"icon": "dark_mode"
|
||||
}
|
||||
]
|
||||
currentIndex: SessionData.isLightMode ? 0 : 1
|
||||
selectionMode: "single"
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected)
|
||||
return;
|
||||
const light = index === 0;
|
||||
if (light === SessionData.isLightMode)
|
||||
return;
|
||||
Theme.screenTransition();
|
||||
Theme.setLightMode(light);
|
||||
}
|
||||
]
|
||||
currentIndex: SessionData.isLightMode ? 0 : 1
|
||||
selectionMode: "single"
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected)
|
||||
return;
|
||||
const light = index === 0;
|
||||
if (light === SessionData.isLightMode)
|
||||
return;
|
||||
Theme.screenTransition();
|
||||
Theme.setLightMode(light);
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: scheduleButton
|
||||
iconName: "schedule"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Accessible.name: I18n.tr("Dark mode")
|
||||
tooltipText: root.colorModeStatus
|
||||
onClicked: root.parentModal?.navigateTo("theme_schedule")
|
||||
}
|
||||
}
|
||||
|
||||
QuickTile {
|
||||
title: I18n.tr("Dark mode")
|
||||
hint: root.colorModeStatus
|
||||
onClicked: root.parentModal?.navigateTo("theme_schedule")
|
||||
SettingsSwatchGrid {
|
||||
width: parent.width
|
||||
visible: root.dynamicTheme
|
||||
compact: true
|
||||
options: MatugenPreviewService.schemeOptions
|
||||
currentValue: SettingsData.matugenScheme
|
||||
enabled: Theme.matugenAvailable && MatugenPreviewService.ready
|
||||
opacity: MatugenPreviewService.ready ? 1 : Theme.pendingOpacity
|
||||
onSelected: value => SettingsData.setMatugenScheme(value)
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "schedule"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QuickTile {
|
||||
title: I18n.tr("Theme & colors")
|
||||
hint: Theme.currentThemeLabel
|
||||
onClicked: root.parentModal?.navigateTo("theme")
|
||||
SettingsThemeColorDots {
|
||||
width: parent.width
|
||||
visible: root.genericTheme
|
||||
}
|
||||
|
||||
SettingsSwatchGrid {
|
||||
width: parent.width
|
||||
visible: root.registryGridShown
|
||||
compact: true
|
||||
maxHeight: hero.stacked ? 0 : hero.thumbWidth * SettingsMetrics.wallpaperThumbRatio - modeRow.height - side.spacing
|
||||
options: root.registryOptions
|
||||
currentValue: root.activeRegistryTheme
|
||||
onSelected: value => {
|
||||
SettingsData.set("customThemeFile", root.themesDir + "/" + value + "/theme.json");
|
||||
Theme.switchTheme("custom", true, true);
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: themeTile
|
||||
width: parent.width
|
||||
visible: !root.dynamicTheme && !root.genericTheme && !root.registryGridShown && !root.registryPending
|
||||
height: hero.stacked ? Theme.listItemTwoLineHeight : Math.max(Theme.listItemTwoLineHeight, hero.thumbWidth * SettingsMetrics.wallpaperThumbRatio - modeRow.height - side.spacing)
|
||||
radius: Theme.cornerRadiusM
|
||||
color: Theme.foregroundColor(Theme.chipSurface, true)
|
||||
|
||||
activeFocusOnTab: visible
|
||||
Accessible.role: Accessible.Button
|
||||
Accessible.name: I18n.tr("Theme & colors")
|
||||
Accessible.description: Theme.currentThemeLabel
|
||||
Accessible.onPressAction: root.parentModal?.navigateTo("theme")
|
||||
Keys.onSpacePressed: root.parentModal?.navigateTo("theme")
|
||||
Keys.onReturnPressed: root.parentModal?.navigateTo("theme")
|
||||
|
||||
FocusRing {}
|
||||
|
||||
DankPaletteSwatch {
|
||||
anchors.fill: parent
|
||||
id: themeSwatch
|
||||
width: Theme.avatarSize
|
||||
height: Theme.avatarSize
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
primaryColor: root.themePalette.primary
|
||||
secondaryColor: root.themePalette.secondary
|
||||
tertiaryColor: root.themePalette.tertiary
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.left: themeSwatch.right
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.right: themeChevron.left
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXXS
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: I18n.tr("Theme & colors")
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Theme.fontWeightMedium
|
||||
color: Theme.surfaceText
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
StyledText {
|
||||
width: parent.width
|
||||
text: Theme.currentThemeLabel
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
id: themeChevron
|
||||
name: "chevron_right"
|
||||
size: Theme.iconSize
|
||||
color: Theme.surfaceVariantText
|
||||
rotation: I18n.isRtl ? 180 : 0
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StateLayer {
|
||||
stateColor: Theme.surfaceText
|
||||
cornerRadius: themeTile.radius
|
||||
onClicked: root.parentModal?.navigateTo("theme")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SettingsNavRow {
|
||||
tab: "wallpaper"
|
||||
tags: ["theme", "color", "palette", "matugen", "dynamic", "custom", "registry"]
|
||||
settingKey: "themeNav"
|
||||
iconName: "format_paint"
|
||||
title: I18n.tr("Theme & colors")
|
||||
hint: I18n.tr("Choose and install themes", "theme and colors row hint")
|
||||
onClicked: root.parentModal?.navigateTo("theme")
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
|
||||
@@ -10,17 +10,22 @@ Flow {
|
||||
|
||||
property var options: []
|
||||
property string currentValue: ""
|
||||
property real minTileWidth: SettingsMetrics.swatchTileMinWidth
|
||||
property bool compact: false
|
||||
property real maxHeight: 0
|
||||
property real minTileWidth: compact ? Theme.minimumTouchTargetSize + Theme.spacingM : SettingsMetrics.swatchTileMinWidth
|
||||
signal selected(string value)
|
||||
|
||||
readonly property int columns: Math.max(1, Math.floor((width + spacing) / (minTileWidth + spacing)))
|
||||
readonly property real tileWidth: Math.floor((width - spacing * (columns - 1)) / columns)
|
||||
readonly property real compactTileHeight: Theme.minimumTouchTargetSize + Theme.spacingS * 2
|
||||
readonly property int maxRows: maxHeight > 0 && compact ? Math.max(1, Math.floor((maxHeight + spacing) / (compactTileHeight + spacing))) : 0
|
||||
readonly property var shownOptions: maxRows > 0 ? options.slice(0, columns * maxRows) : options
|
||||
|
||||
width: parent?.width ?? 0
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: root.options
|
||||
model: root.shownOptions
|
||||
|
||||
Rectangle {
|
||||
id: tile
|
||||
@@ -29,7 +34,7 @@ Flow {
|
||||
readonly property bool isActive: root.currentValue === modelData.value
|
||||
|
||||
width: root.tileWidth
|
||||
height: swatch.height + label.implicitHeight + Theme.spacingS * 3
|
||||
height: root.compact ? root.compactTileHeight : swatch.height + label.implicitHeight + Theme.spacingS * 3
|
||||
radius: Theme.cornerRadiusM
|
||||
color: Theme.floatingWindowNestedSurface
|
||||
border.width: isActive ? Theme.outlineWidthFocused : Theme.outlineWidth
|
||||
@@ -64,8 +69,15 @@ Flow {
|
||||
tertiaryColor: tile.modelData.tertiary ?? tile.modelData.secondary ?? tile.modelData.primary
|
||||
}
|
||||
|
||||
DankTooltipHost {
|
||||
text: root.compact ? tile.modelData.label : null
|
||||
target: tile
|
||||
hoverArea: tileMouse
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: label
|
||||
visible: !root.compact
|
||||
anchors.top: swatch.bottom
|
||||
anchors.topMargin: Theme.spacingS
|
||||
anchors.left: parent.left
|
||||
@@ -74,7 +86,7 @@ Flow {
|
||||
anchors.rightMargin: Theme.spacingXS
|
||||
text: tile.modelData.label
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: tile.isActive ? Theme.fontWeightMedium : Theme.fontWeightNormal
|
||||
font.weight: tile.isActive ? Theme.fontWeightMedium : Theme.fontWeight
|
||||
color: tile.isActive ? Theme.primary : Theme.surfaceText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
wrapMode: Text.WordWrap
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
import "../../../Common/ThemePalette.js" as ThemePalette
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
readonly property var colorList: ["blue", "purple", "green", "orange", "red", "cyan", "pink", "amber", "coral", "monochrome"]
|
||||
readonly property int dotSize: Theme.minimumTouchTargetSize
|
||||
|
||||
implicitHeight: grid.implicitHeight + Math.ceil(dotSize * 0.05)
|
||||
|
||||
Grid {
|
||||
id: grid
|
||||
columns: Math.ceil(root.colorList.length / 2)
|
||||
rowSpacing: Theme.spacingS
|
||||
columnSpacing: Theme.spacingS
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Repeater {
|
||||
model: root.colorList
|
||||
|
||||
Rectangle {
|
||||
required property string modelData
|
||||
readonly property var colors: Theme.getThemeColors(modelData)
|
||||
readonly property var palette: ThemePalette.pick(colors)
|
||||
readonly property bool isActive: Theme.currentThemeName === modelData && Theme.currentTheme !== Theme.dynamic
|
||||
width: root.dotSize
|
||||
height: root.dotSize
|
||||
radius: width / 2
|
||||
color: "transparent"
|
||||
scale: isActive ? 1.1 : 1
|
||||
|
||||
DankPaletteSwatch {
|
||||
anchors.fill: parent
|
||||
primaryColor: parent.palette.primary
|
||||
secondaryColor: parent.palette.secondary
|
||||
tertiaryColor: parent.palette.tertiary
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "check"
|
||||
size: Theme.iconSizeMedium
|
||||
color: Theme.isLightColor(parent.colors.primary) ? Theme.contrastDark : Theme.contrastLight
|
||||
visible: parent.isActive
|
||||
}
|
||||
|
||||
DankTooltipHost {
|
||||
text: parent.colors.name
|
||||
target: parent
|
||||
hoverArea: mouseArea
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: Theme.switchTheme(parent.modelData)
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import qs.Widgets
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string badge: ""
|
||||
property string path: ""
|
||||
property string placeholderIcon: "image"
|
||||
property string emptyText: I18n.tr("Not set", "wallpaper not set label")
|
||||
@@ -111,20 +110,28 @@ Rectangle {
|
||||
|
||||
Rectangle {
|
||||
id: chip
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: Theme.spacingS
|
||||
width: Math.min(chipText.implicitWidth + Theme.spacingS * 2, parent.width - Theme.spacingS * 2)
|
||||
// sized from unelided metrics: the elided text's own implicitWidth shrinks with the chip and collapses it
|
||||
width: Math.min(chipMetrics.advanceWidth + Theme.spacingS * 2, parent.width - Theme.spacingS * 2)
|
||||
height: chipText.implicitHeight + Theme.spacingXS * 2
|
||||
radius: Theme.cornerRadiusS
|
||||
color: Theme.withAlpha(Theme.scrimColor, Theme.scrimAlpha)
|
||||
|
||||
TextMetrics {
|
||||
id: chipMetrics
|
||||
font: chipText.font
|
||||
text: chipMetrics.text
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: chipText
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
text: root.badge !== "" ? root.badge + " · " + root.fileName : root.fileName
|
||||
text: chipMetrics.text
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.contrastLight
|
||||
elide: Text.ElideMiddle
|
||||
|
||||
@@ -27,6 +27,7 @@ Singleton {
|
||||
property var registries: []
|
||||
property var availableThemes: []
|
||||
property var installedThemes: []
|
||||
property bool installedThemesLoaded: false
|
||||
property bool isConnected: false
|
||||
readonly property bool isConnecting: requestSocket.connected && !requestSocket.linkUp
|
||||
property bool subscribeConnected: false
|
||||
@@ -672,6 +673,7 @@ Singleton {
|
||||
sendRequest("themes.listInstalled", null, response => {
|
||||
if (response.result) {
|
||||
installedThemes = response.result;
|
||||
installedThemesLoaded = true;
|
||||
installedThemesReceived(response.result);
|
||||
}
|
||||
if (callback) {
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property var previews: CacheData.matugenPreviews.previews ?? ({})
|
||||
property string requestKey: ""
|
||||
property string loadedKey: CacheData.matugenPreviews.key ?? ""
|
||||
property bool failed: false
|
||||
|
||||
readonly property string source: SettingsData.matugenSeedColor || Theme.getMatugenColor("source_color", Theme.primary).toString()
|
||||
readonly property string image: (!SettingsData.matugenSeedColor && Theme.rawWallpaperPath && !Theme.rawWallpaperPath.startsWith("#")) ? Theme.rawWallpaperPath : ""
|
||||
readonly property string key: source + "|" + (SettingsData.matugenContrast ?? 0) + "|" + image + "|" + SettingsData.matugenSpec
|
||||
readonly property bool ready: loadedKey === key || failed || !Theme.matugenAvailable
|
||||
readonly property var schemeOptions: {
|
||||
const mode = SessionData.isLightMode ? "light" : "dark";
|
||||
const options = [];
|
||||
for (const option of Theme.availableMatugenSchemes) {
|
||||
if (option.value === "scheme-smart" && !DMSService.matugenSmartSupported)
|
||||
continue;
|
||||
const colors = (previews[option.value] ?? previews["scheme-tonal-spot"])?.[mode];
|
||||
// a dms binary older than the tri-color preview returns the primary hex as a plain string
|
||||
const primary = typeof colors === "string" ? colors : (colors?.primary ?? Theme.primary.toString());
|
||||
options.push({
|
||||
"value": option.value,
|
||||
"label": option.label,
|
||||
"primary": primary,
|
||||
"secondary": colors?.secondary ?? primary,
|
||||
"tertiary": colors?.tertiary ?? primary
|
||||
});
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
if (!Theme.matugenAvailable)
|
||||
return;
|
||||
const wanted = key;
|
||||
if (wanted === loadedKey || wanted === requestKey)
|
||||
return;
|
||||
requestKey = wanted;
|
||||
failed = false;
|
||||
|
||||
const args = [Proc.dmsBin, "matugen", "preview", "--source-color", source, "--contrast", String(SettingsData.matugenContrast ?? 0)];
|
||||
if (image)
|
||||
args.push("--image", image);
|
||||
if (SettingsData.matugenSpec === "2025")
|
||||
args.push("--spec", "2025");
|
||||
Proc.runCommand("", args, (output, exitCode) => {
|
||||
if (wanted !== root.requestKey)
|
||||
return;
|
||||
root.requestKey = "";
|
||||
if (exitCode !== 0) {
|
||||
root.failed = true;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
root.previews = JSON.parse(output.trim());
|
||||
root.loadedKey = wanted;
|
||||
CacheData.matugenPreviews = {
|
||||
"key": wanted,
|
||||
"previews": root.previews
|
||||
};
|
||||
CacheData.saveCache();
|
||||
} catch (e) {
|
||||
root.failed = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -130,7 +130,8 @@
|
||||
"tint",
|
||||
"wallpaper"
|
||||
],
|
||||
"page": "personalization"
|
||||
"page": "personalization",
|
||||
"icon": "schedule"
|
||||
},
|
||||
{
|
||||
"section": "_hub_applications",
|
||||
@@ -712,34 +713,6 @@
|
||||
],
|
||||
"page": "personalization"
|
||||
},
|
||||
{
|
||||
"section": "colorMode",
|
||||
"label": "Dark mode",
|
||||
"tabIndex": -1,
|
||||
"category": "Wallpaper & colors",
|
||||
"keywords": [
|
||||
"background",
|
||||
"bg",
|
||||
"color",
|
||||
"colors",
|
||||
"colour",
|
||||
"colours",
|
||||
"dark",
|
||||
"dark mode",
|
||||
"desktop",
|
||||
"hue",
|
||||
"image",
|
||||
"light",
|
||||
"mode",
|
||||
"night",
|
||||
"palette",
|
||||
"picture",
|
||||
"theme",
|
||||
"tint",
|
||||
"wallpaper"
|
||||
],
|
||||
"page": "personalization"
|
||||
},
|
||||
{
|
||||
"section": "iconThemeDark",
|
||||
"label": "Dark mode theme",
|
||||
@@ -2131,6 +2104,67 @@
|
||||
],
|
||||
"icon": "memory"
|
||||
},
|
||||
{
|
||||
"section": "colorMode",
|
||||
"label": "Theme & colors",
|
||||
"tabIndex": -1,
|
||||
"category": "Wallpaper & colors",
|
||||
"keywords": [
|
||||
"appearance",
|
||||
"background",
|
||||
"bg",
|
||||
"color",
|
||||
"colors",
|
||||
"colour",
|
||||
"colours",
|
||||
"dark",
|
||||
"desktop",
|
||||
"hue",
|
||||
"image",
|
||||
"light",
|
||||
"look",
|
||||
"mode",
|
||||
"palette",
|
||||
"picture",
|
||||
"style",
|
||||
"theme",
|
||||
"tint",
|
||||
"wallpaper"
|
||||
],
|
||||
"page": "personalization",
|
||||
"icon": "schedule"
|
||||
},
|
||||
{
|
||||
"section": "themeNav",
|
||||
"label": "Theme & colors",
|
||||
"tabIndex": -1,
|
||||
"category": "Wallpaper & colors",
|
||||
"keywords": [
|
||||
"appearance",
|
||||
"background",
|
||||
"bg",
|
||||
"color",
|
||||
"colors",
|
||||
"colour",
|
||||
"colours",
|
||||
"custom",
|
||||
"desktop",
|
||||
"dynamic",
|
||||
"hue",
|
||||
"image",
|
||||
"look",
|
||||
"matugen",
|
||||
"palette",
|
||||
"picture",
|
||||
"registry",
|
||||
"style",
|
||||
"theme",
|
||||
"tint",
|
||||
"wallpaper"
|
||||
],
|
||||
"page": "personalization",
|
||||
"icon": "format_paint"
|
||||
},
|
||||
{
|
||||
"section": "focusRingWidth",
|
||||
"label": "Thickness",
|
||||
|
||||
Reference in New Issue
Block a user