mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-03 20:32:07 -04:00
theme(greeter): fix auto theme accent variants & update selections
This commit is contained in:
@@ -1497,6 +1497,20 @@ func checkGreeterStatus() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("\nConfiguration Symlinks:")
|
fmt.Println("\nConfiguration Symlinks:")
|
||||||
|
colorSyncInfo, colorSyncErr := greeter.ResolveGreeterColorSyncInfo(homeDir)
|
||||||
|
if colorSyncErr != nil {
|
||||||
|
fmt.Printf(" ✗ Failed to resolve expected greeter color source: %v\n", colorSyncErr)
|
||||||
|
allGood = false
|
||||||
|
colorSyncInfo = greeter.GreeterColorSyncInfo{
|
||||||
|
SourcePath: filepath.Join(homeDir, ".cache", "DankMaterialShell", "dms-colors.json"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
colorThemeDesc := "Color theme"
|
||||||
|
if colorSyncInfo.UsesDynamicWallpaperOverride {
|
||||||
|
colorThemeDesc = "Color theme (greeter wallpaper override)"
|
||||||
|
}
|
||||||
|
|
||||||
symlinks := []struct {
|
symlinks := []struct {
|
||||||
source string
|
source string
|
||||||
target string
|
target string
|
||||||
@@ -1513,9 +1527,9 @@ func checkGreeterStatus() error {
|
|||||||
desc: "Session state",
|
desc: "Session state",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
source: filepath.Join(homeDir, ".cache", "DankMaterialShell", "dms-colors.json"),
|
source: colorSyncInfo.SourcePath,
|
||||||
target: filepath.Join(cacheDir, "colors.json"),
|
target: filepath.Join(cacheDir, "colors.json"),
|
||||||
desc: "Color theme",
|
desc: colorThemeDesc,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1557,6 +1571,10 @@ func checkGreeterStatus() error {
|
|||||||
fmt.Printf(" ✓ %s: synced correctly\n", link.desc)
|
fmt.Printf(" ✓ %s: synced correctly\n", link.desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if colorSyncInfo.UsesDynamicWallpaperOverride {
|
||||||
|
fmt.Printf(" ℹ Dynamic theme uses greeter override colors from %s\n", colorSyncInfo.SourcePath)
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println("\nGreeter Wallpaper Override:")
|
fmt.Println("\nGreeter Wallpaper Override:")
|
||||||
overridePath := filepath.Join(cacheDir, "greeter_wallpaper_override.jpg")
|
overridePath := filepath.Join(cacheDir, "greeter_wallpaper_override.jpg")
|
||||||
if stat, err := os.Stat(overridePath); err == nil && !stat.IsDir() {
|
if stat, err := os.Stat(overridePath); err == nil && !stat.IsDir() {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -14,6 +15,7 @@ import (
|
|||||||
|
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/config"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/config"
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/distros"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/distros"
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/matugen"
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/internal/utils"
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/utils"
|
||||||
"github.com/sblinch/kdl-go"
|
"github.com/sblinch/kdl-go"
|
||||||
"github.com/sblinch/kdl-go/document"
|
"github.com/sblinch/kdl-go/document"
|
||||||
@@ -1075,6 +1077,7 @@ func SetupDMSGroup(logFunc func(string), sudoPassword string) error {
|
|||||||
}{
|
}{
|
||||||
{filepath.Join(homeDir, ".config", "DankMaterialShell"), "DankMaterialShell config"},
|
{filepath.Join(homeDir, ".config", "DankMaterialShell"), "DankMaterialShell config"},
|
||||||
{filepath.Join(homeDir, ".local", "state", "DankMaterialShell"), "DankMaterialShell state"},
|
{filepath.Join(homeDir, ".local", "state", "DankMaterialShell"), "DankMaterialShell state"},
|
||||||
|
{filepath.Join(homeDir, ".cache", "DankMaterialShell"), "DankMaterialShell cache"},
|
||||||
{filepath.Join(homeDir, ".cache", "quickshell"), "quickshell cache"},
|
{filepath.Join(homeDir, ".cache", "quickshell"), "quickshell cache"},
|
||||||
{filepath.Join(homeDir, ".config", "quickshell"), "quickshell config"},
|
{filepath.Join(homeDir, ".config", "quickshell"), "quickshell config"},
|
||||||
{filepath.Join(homeDir, ".local", "share", "wayland-sessions"), "wayland sessions"},
|
{filepath.Join(homeDir, ".local", "share", "wayland-sessions"), "wayland sessions"},
|
||||||
@@ -1109,6 +1112,217 @@ func SetupDMSGroup(logFunc func(string), sudoPassword string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GreeterColorSyncInfo struct {
|
||||||
|
SourcePath string
|
||||||
|
ThemeName string
|
||||||
|
UsesDynamicWallpaperOverride bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type greeterThemeSyncSettings struct {
|
||||||
|
CurrentThemeName string `json:"currentThemeName"`
|
||||||
|
GreeterWallpaperPath string `json:"greeterWallpaperPath"`
|
||||||
|
MatugenScheme string `json:"matugenScheme"`
|
||||||
|
IconTheme string `json:"iconTheme"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type greeterThemeSyncSession struct {
|
||||||
|
IsLightMode bool `json:"isLightMode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type greeterThemeSyncState struct {
|
||||||
|
ThemeName string
|
||||||
|
GreeterWallpaperPath string
|
||||||
|
ResolvedGreeterWallpaperPath string
|
||||||
|
MatugenScheme string
|
||||||
|
IconTheme string
|
||||||
|
IsLightMode bool
|
||||||
|
UsesDynamicWallpaperOverride bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultGreeterColorsSource(homeDir string) string {
|
||||||
|
return filepath.Join(homeDir, ".cache", "DankMaterialShell", "dms-colors.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
func greeterOverrideColorsStateDir(homeDir string) string {
|
||||||
|
return filepath.Join(homeDir, ".cache", "DankMaterialShell", "greeter-colors")
|
||||||
|
}
|
||||||
|
|
||||||
|
func greeterOverrideColorsSource(homeDir string) string {
|
||||||
|
return filepath.Join(greeterOverrideColorsStateDir(homeDir), "dms-colors.json")
|
||||||
|
}
|
||||||
|
|
||||||
|
func readOptionalJSONFile(path string, dst any) error {
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if strings.TrimSpace(string(data)) == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return json.Unmarshal(data, dst)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readGreeterThemeSyncSettings(homeDir string) (greeterThemeSyncSettings, error) {
|
||||||
|
settings := greeterThemeSyncSettings{
|
||||||
|
CurrentThemeName: "purple",
|
||||||
|
MatugenScheme: "scheme-tonal-spot",
|
||||||
|
IconTheme: "System Default",
|
||||||
|
}
|
||||||
|
settingsPath := filepath.Join(homeDir, ".config", "DankMaterialShell", "settings.json")
|
||||||
|
if err := readOptionalJSONFile(settingsPath, &settings); err != nil {
|
||||||
|
return greeterThemeSyncSettings{}, fmt.Errorf("failed to parse settings at %s: %w", settingsPath, err)
|
||||||
|
}
|
||||||
|
return settings, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readGreeterThemeSyncSession(homeDir string) (greeterThemeSyncSession, error) {
|
||||||
|
session := greeterThemeSyncSession{}
|
||||||
|
sessionPath := filepath.Join(homeDir, ".local", "state", "DankMaterialShell", "session.json")
|
||||||
|
if err := readOptionalJSONFile(sessionPath, &session); err != nil {
|
||||||
|
return greeterThemeSyncSession{}, fmt.Errorf("failed to parse session at %s: %w", sessionPath, err)
|
||||||
|
}
|
||||||
|
return session, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveGreeterThemeSyncState(homeDir string) (greeterThemeSyncState, error) {
|
||||||
|
settings, err := readGreeterThemeSyncSettings(homeDir)
|
||||||
|
if err != nil {
|
||||||
|
return greeterThemeSyncState{}, err
|
||||||
|
}
|
||||||
|
session, err := readGreeterThemeSyncSession(homeDir)
|
||||||
|
if err != nil {
|
||||||
|
return greeterThemeSyncState{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resolvedWallpaperPath := ""
|
||||||
|
if settings.GreeterWallpaperPath != "" {
|
||||||
|
resolvedWallpaperPath = settings.GreeterWallpaperPath
|
||||||
|
if !filepath.IsAbs(resolvedWallpaperPath) {
|
||||||
|
resolvedWallpaperPath = filepath.Join(homeDir, resolvedWallpaperPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
usesDynamicWallpaperOverride := strings.EqualFold(strings.TrimSpace(settings.CurrentThemeName), "dynamic") && resolvedWallpaperPath != ""
|
||||||
|
|
||||||
|
return greeterThemeSyncState{
|
||||||
|
ThemeName: settings.CurrentThemeName,
|
||||||
|
GreeterWallpaperPath: settings.GreeterWallpaperPath,
|
||||||
|
ResolvedGreeterWallpaperPath: resolvedWallpaperPath,
|
||||||
|
MatugenScheme: settings.MatugenScheme,
|
||||||
|
IconTheme: settings.IconTheme,
|
||||||
|
IsLightMode: session.IsLightMode,
|
||||||
|
UsesDynamicWallpaperOverride: usesDynamicWallpaperOverride,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s greeterThemeSyncState) effectiveColorsSource(homeDir string) string {
|
||||||
|
if s.UsesDynamicWallpaperOverride {
|
||||||
|
return greeterOverrideColorsSource(homeDir)
|
||||||
|
}
|
||||||
|
return defaultGreeterColorsSource(homeDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResolveGreeterColorSyncInfo(homeDir string) (GreeterColorSyncInfo, error) {
|
||||||
|
state, err := resolveGreeterThemeSyncState(homeDir)
|
||||||
|
if err != nil {
|
||||||
|
return GreeterColorSyncInfo{}, err
|
||||||
|
}
|
||||||
|
return GreeterColorSyncInfo{
|
||||||
|
SourcePath: state.effectiveColorsSource(homeDir),
|
||||||
|
ThemeName: state.ThemeName,
|
||||||
|
UsesDynamicWallpaperOverride: state.UsesDynamicWallpaperOverride,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ensureGreeterSyncSourceFile(path string) error {
|
||||||
|
sourceDir := filepath.Dir(path)
|
||||||
|
if err := os.MkdirAll(sourceDir, 0o755); err != nil {
|
||||||
|
return fmt.Errorf("failed to create source directory %s: %w", sourceDir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
|
if err := os.WriteFile(path, []byte("{}"), 0o644); err != nil {
|
||||||
|
return fmt.Errorf("failed to create source file %s: %w", path, err)
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
return fmt.Errorf("failed to inspect source file %s: %w", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func syncGreeterDynamicOverrideColors(dmsPath, homeDir string, state greeterThemeSyncState, logFunc func(string)) error {
|
||||||
|
if !state.UsesDynamicWallpaperOverride {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
st, err := os.Stat(state.ResolvedGreeterWallpaperPath)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("configured greeter wallpaper not found at %s: %w", state.ResolvedGreeterWallpaperPath, err)
|
||||||
|
}
|
||||||
|
if st.IsDir() {
|
||||||
|
return fmt.Errorf("configured greeter wallpaper path points to a directory: %s", state.ResolvedGreeterWallpaperPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
mode := matugen.ColorModeDark
|
||||||
|
if state.IsLightMode {
|
||||||
|
mode = matugen.ColorModeLight
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := matugen.Options{
|
||||||
|
StateDir: greeterOverrideColorsStateDir(homeDir),
|
||||||
|
ShellDir: dmsPath,
|
||||||
|
ConfigDir: filepath.Join(homeDir, ".config"),
|
||||||
|
Kind: "image",
|
||||||
|
Value: state.ResolvedGreeterWallpaperPath,
|
||||||
|
Mode: mode,
|
||||||
|
IconTheme: state.IconTheme,
|
||||||
|
MatugenType: state.MatugenScheme,
|
||||||
|
RunUserTemplates: false,
|
||||||
|
ColorsOnly: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = matugen.Run(opts)
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, matugen.ErrNoChanges):
|
||||||
|
logFunc("✓ Greeter dynamic override colors already up to date")
|
||||||
|
return nil
|
||||||
|
case err != nil:
|
||||||
|
return fmt.Errorf("failed to generate greeter dynamic colors from wallpaper override: %w", err)
|
||||||
|
default:
|
||||||
|
logFunc("✓ Generated greeter dynamic colors from wallpaper override")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func syncGreeterColorSource(homeDir, cacheDir string, state greeterThemeSyncState, logFunc func(string), sudoPassword string) error {
|
||||||
|
source := state.effectiveColorsSource(homeDir)
|
||||||
|
if !state.UsesDynamicWallpaperOverride {
|
||||||
|
if err := ensureGreeterSyncSourceFile(source); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if _, err := os.Stat(source); err != nil {
|
||||||
|
return fmt.Errorf("expected generated greeter colors at %s: %w", source, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
target := filepath.Join(cacheDir, "colors.json")
|
||||||
|
_ = runSudoCmd(sudoPassword, "rm", "-f", target)
|
||||||
|
if err := runSudoCmd(sudoPassword, "ln", "-sf", source, target); err != nil {
|
||||||
|
return fmt.Errorf("failed to create symlink for wallpaper based theming (%s -> %s): %w", target, source, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.UsesDynamicWallpaperOverride {
|
||||||
|
logFunc("✓ Synced wallpaper based theming (greeter wallpaper override)")
|
||||||
|
} else {
|
||||||
|
logFunc("✓ Synced wallpaper based theming")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func SyncDMSConfigs(dmsPath, compositor string, logFunc func(string), sudoPassword string, forceAuth bool) error {
|
func SyncDMSConfigs(dmsPath, compositor string, logFunc func(string), sudoPassword string, forceAuth bool) error {
|
||||||
homeDir, err := os.UserHomeDir()
|
homeDir, err := os.UserHomeDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1132,11 +1346,6 @@ func SyncDMSConfigs(dmsPath, compositor string, logFunc func(string), sudoPasswo
|
|||||||
target: filepath.Join(cacheDir, "session.json"),
|
target: filepath.Join(cacheDir, "session.json"),
|
||||||
desc: "state (wallpaper configuration)",
|
desc: "state (wallpaper configuration)",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
source: filepath.Join(homeDir, ".cache", "DankMaterialShell", "dms-colors.json"),
|
|
||||||
target: filepath.Join(cacheDir, "colors.json"),
|
|
||||||
desc: "wallpaper based theming",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, link := range symlinks {
|
for _, link := range symlinks {
|
||||||
@@ -1162,7 +1371,20 @@ func SyncDMSConfigs(dmsPath, compositor string, logFunc func(string), sudoPasswo
|
|||||||
logFunc(fmt.Sprintf("✓ Synced %s", link.desc))
|
logFunc(fmt.Sprintf("✓ Synced %s", link.desc))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := syncGreeterWallpaperOverride(homeDir, cacheDir, logFunc, sudoPassword); err != nil {
|
state, err := resolveGreeterThemeSyncState(homeDir)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to resolve greeter color source: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := syncGreeterDynamicOverrideColors(dmsPath, homeDir, state, logFunc); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := syncGreeterColorSource(homeDir, cacheDir, state, logFunc, sudoPassword); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := syncGreeterWallpaperOverride(cacheDir, logFunc, sudoPassword, state); err != nil {
|
||||||
return fmt.Errorf("greeter wallpaper override sync failed: %w", err)
|
return fmt.Errorf("greeter wallpaper override sync failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1181,23 +1403,9 @@ func SyncDMSConfigs(dmsPath, compositor string, logFunc func(string), sudoPasswo
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func syncGreeterWallpaperOverride(homeDir, cacheDir string, logFunc func(string), sudoPassword string) error {
|
func syncGreeterWallpaperOverride(cacheDir string, logFunc func(string), sudoPassword string, state greeterThemeSyncState) error {
|
||||||
settingsPath := filepath.Join(homeDir, ".config", "DankMaterialShell", "settings.json")
|
|
||||||
data, err := os.ReadFile(settingsPath)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("failed to read settings at %s: %w", settingsPath, err)
|
|
||||||
}
|
|
||||||
var settings struct {
|
|
||||||
GreeterWallpaperPath string `json:"greeterWallpaperPath"`
|
|
||||||
}
|
|
||||||
if err := json.Unmarshal(data, &settings); err != nil {
|
|
||||||
return fmt.Errorf("failed to parse settings at %s: %w", settingsPath, err)
|
|
||||||
}
|
|
||||||
destPath := filepath.Join(cacheDir, "greeter_wallpaper_override.jpg")
|
destPath := filepath.Join(cacheDir, "greeter_wallpaper_override.jpg")
|
||||||
if settings.GreeterWallpaperPath == "" {
|
if state.ResolvedGreeterWallpaperPath == "" {
|
||||||
if err := runSudoCmd(sudoPassword, "rm", "-f", destPath); err != nil {
|
if err := runSudoCmd(sudoPassword, "rm", "-f", destPath); err != nil {
|
||||||
return fmt.Errorf("failed to clear override file %s: %w", destPath, err)
|
return fmt.Errorf("failed to clear override file %s: %w", destPath, err)
|
||||||
}
|
}
|
||||||
@@ -1207,10 +1415,7 @@ func syncGreeterWallpaperOverride(homeDir, cacheDir string, logFunc func(string)
|
|||||||
if err := runSudoCmd(sudoPassword, "rm", "-f", destPath); err != nil {
|
if err := runSudoCmd(sudoPassword, "rm", "-f", destPath); err != nil {
|
||||||
return fmt.Errorf("failed to remove old override file %s: %w", destPath, err)
|
return fmt.Errorf("failed to remove old override file %s: %w", destPath, err)
|
||||||
}
|
}
|
||||||
src := settings.GreeterWallpaperPath
|
src := state.ResolvedGreeterWallpaperPath
|
||||||
if !filepath.IsAbs(src) {
|
|
||||||
src = filepath.Join(homeDir, src)
|
|
||||||
}
|
|
||||||
st, err := os.Stat(src)
|
st, err := os.Stat(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("configured greeter wallpaper not found at %s: %w", src, err)
|
return fmt.Errorf("configured greeter wallpaper not found at %s: %w", src, err)
|
||||||
|
|||||||
98
core/internal/greeter/installer_test.go
Normal file
98
core/internal/greeter/installer_test.go
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package greeter
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func writeTestJSON(t *testing.T, path string, content string) {
|
||||||
|
t.Helper()
|
||||||
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||||
|
t.Fatalf("failed to create parent dir for %s: %v", path, err)
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
||||||
|
t.Fatalf("failed to write %s: %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestResolveGreeterThemeSyncState(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
settingsJSON string
|
||||||
|
sessionJSON string
|
||||||
|
wantSourcePath string
|
||||||
|
wantResolvedWallpaper string
|
||||||
|
wantDynamicOverrideUsed bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "dynamic theme with greeter wallpaper override uses generated greeter colors",
|
||||||
|
settingsJSON: `{
|
||||||
|
"currentThemeName": "dynamic",
|
||||||
|
"greeterWallpaperPath": "Pictures/blue.jpg",
|
||||||
|
"matugenScheme": "scheme-tonal-spot",
|
||||||
|
"iconTheme": "Papirus"
|
||||||
|
}`,
|
||||||
|
sessionJSON: `{"isLightMode":true}`,
|
||||||
|
wantSourcePath: filepath.Join(".cache", "DankMaterialShell", "greeter-colors", "dms-colors.json"),
|
||||||
|
wantResolvedWallpaper: filepath.Join("Pictures", "blue.jpg"),
|
||||||
|
wantDynamicOverrideUsed: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "dynamic theme without override uses desktop colors",
|
||||||
|
settingsJSON: `{
|
||||||
|
"currentThemeName": "dynamic",
|
||||||
|
"greeterWallpaperPath": ""
|
||||||
|
}`,
|
||||||
|
sessionJSON: `{"isLightMode":false}`,
|
||||||
|
wantSourcePath: filepath.Join(".cache", "DankMaterialShell", "dms-colors.json"),
|
||||||
|
wantResolvedWallpaper: "",
|
||||||
|
wantDynamicOverrideUsed: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-dynamic theme keeps desktop colors even with override wallpaper",
|
||||||
|
settingsJSON: `{
|
||||||
|
"currentThemeName": "purple",
|
||||||
|
"greeterWallpaperPath": "/tmp/blue.jpg"
|
||||||
|
}`,
|
||||||
|
sessionJSON: `{"isLightMode":false}`,
|
||||||
|
wantSourcePath: filepath.Join(".cache", "DankMaterialShell", "dms-colors.json"),
|
||||||
|
wantResolvedWallpaper: "/tmp/blue.jpg",
|
||||||
|
wantDynamicOverrideUsed: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
homeDir := t.TempDir()
|
||||||
|
writeTestJSON(t, filepath.Join(homeDir, ".config", "DankMaterialShell", "settings.json"), tt.settingsJSON)
|
||||||
|
writeTestJSON(t, filepath.Join(homeDir, ".local", "state", "DankMaterialShell", "session.json"), tt.sessionJSON)
|
||||||
|
|
||||||
|
state, err := resolveGreeterThemeSyncState(homeDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("resolveGreeterThemeSyncState returned error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := state.effectiveColorsSource(homeDir); got != filepath.Join(homeDir, tt.wantSourcePath) {
|
||||||
|
t.Fatalf("effectiveColorsSource = %q, want %q", got, filepath.Join(homeDir, tt.wantSourcePath))
|
||||||
|
}
|
||||||
|
|
||||||
|
wantResolvedWallpaper := tt.wantResolvedWallpaper
|
||||||
|
if wantResolvedWallpaper != "" && !filepath.IsAbs(wantResolvedWallpaper) {
|
||||||
|
wantResolvedWallpaper = filepath.Join(homeDir, wantResolvedWallpaper)
|
||||||
|
}
|
||||||
|
if state.ResolvedGreeterWallpaperPath != wantResolvedWallpaper {
|
||||||
|
t.Fatalf("ResolvedGreeterWallpaperPath = %q, want %q", state.ResolvedGreeterWallpaperPath, wantResolvedWallpaper)
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.UsesDynamicWallpaperOverride != tt.wantDynamicOverrideUsed {
|
||||||
|
t.Fatalf("UsesDynamicWallpaperOverride = %v, want %v", state.UsesDynamicWallpaperOverride, tt.wantDynamicOverrideUsed)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -100,6 +100,7 @@ type Options struct {
|
|||||||
IconTheme string
|
IconTheme string
|
||||||
MatugenType string
|
MatugenType string
|
||||||
RunUserTemplates bool
|
RunUserTemplates bool
|
||||||
|
ColorsOnly bool
|
||||||
StockColors string
|
StockColors string
|
||||||
SyncModeWithPortal bool
|
SyncModeWithPortal bool
|
||||||
TerminalsAlwaysDark bool
|
TerminalsAlwaysDark bool
|
||||||
@@ -274,6 +275,10 @@ func buildOnce(opts *Options) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.ColorsOnly {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
if isDMSGTKActive(opts.ConfigDir) {
|
if isDMSGTKActive(opts.ConfigDir) {
|
||||||
switch opts.Mode {
|
switch opts.Mode {
|
||||||
case ColorModeLight:
|
case ColorModeLight:
|
||||||
@@ -331,6 +336,10 @@ output_path = '%s'
|
|||||||
|
|
||||||
`, opts.ShellDir, opts.ColorsOutput())
|
`, opts.ShellDir, opts.ColorsOutput())
|
||||||
|
|
||||||
|
if opts.ColorsOnly {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
homeDir, _ := os.UserHomeDir()
|
homeDir, _ := os.UserHomeDir()
|
||||||
for _, tmpl := range templateRegistry {
|
for _, tmpl := range templateRegistry {
|
||||||
if opts.ShouldSkipTemplate(tmpl.ID) {
|
if opts.ShouldSkipTemplate(tmpl.ID) {
|
||||||
@@ -597,10 +606,10 @@ func detectMatugenVersionLocked() (matugenFlags, error) {
|
|||||||
matugenVersionOK = true
|
matugenVersionOK = true
|
||||||
|
|
||||||
if matugenSupportsCOE {
|
if matugenSupportsCOE {
|
||||||
log.Infof("Matugen %s supports --continue-on-error", versionStr)
|
log.Debugf("Matugen %s detected: continue-on-error support enabled", versionStr)
|
||||||
}
|
}
|
||||||
if matugenIsV4 {
|
if matugenIsV4 {
|
||||||
log.Infof("Matugen %s: using v4 flags", versionStr)
|
log.Debugf("Matugen %s detected: using v4 compatibility flags", versionStr)
|
||||||
}
|
}
|
||||||
return matugenFlags{matugenSupportsCOE, matugenIsV4}, nil
|
return matugenFlags{matugenSupportsCOE, matugenIsV4}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package matugen
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
mocks_utils "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/utils"
|
mocks_utils "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/utils"
|
||||||
@@ -392,3 +393,51 @@ func TestSubstituteVars(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildMergedConfigColorsOnly(t *testing.T) {
|
||||||
|
tempDir := t.TempDir()
|
||||||
|
|
||||||
|
shellDir := filepath.Join(tempDir, "shell")
|
||||||
|
configsDir := filepath.Join(shellDir, "matugen", "configs")
|
||||||
|
if err := os.MkdirAll(configsDir, 0o755); err != nil {
|
||||||
|
t.Fatalf("failed to create configs dir: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
baseConfig := "[config]\ncustom_keywords = []\n"
|
||||||
|
if err := os.WriteFile(filepath.Join(configsDir, "base.toml"), []byte(baseConfig), 0o644); err != nil {
|
||||||
|
t.Fatalf("failed to write base config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cfgFile, err := os.CreateTemp(tempDir, "merged-*.toml")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create temp config: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(cfgFile.Name())
|
||||||
|
defer cfgFile.Close()
|
||||||
|
|
||||||
|
opts := &Options{
|
||||||
|
ShellDir: shellDir,
|
||||||
|
ConfigDir: filepath.Join(tempDir, "config"),
|
||||||
|
StateDir: filepath.Join(tempDir, "state"),
|
||||||
|
ColorsOnly: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := buildMergedConfig(opts, cfgFile, filepath.Join(tempDir, "templates")); err != nil {
|
||||||
|
t.Fatalf("buildMergedConfig failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cfgFile.Close(); err != nil {
|
||||||
|
t.Fatalf("failed to close merged config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := os.ReadFile(cfgFile.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read merged config: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
content := string(output)
|
||||||
|
assert.Contains(t, content, "[templates.dank]")
|
||||||
|
assert.Contains(t, content, "output_path = '"+filepath.Join(opts.StateDir, "dms-colors.json")+"'")
|
||||||
|
assert.NotContains(t, content, "[templates.gtk]")
|
||||||
|
assert.False(t, strings.Contains(content, "output_path = 'CONFIG_DIR/"), "colors-only config should not emit app template outputs")
|
||||||
|
}
|
||||||
|
|||||||
@@ -1052,7 +1052,10 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (themeData.variants.options && themeData.variants.options.length > 0) {
|
if (themeData.variants.options && themeData.variants.options.length > 0) {
|
||||||
const selectedVariantId = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, themeData.variants.default) : themeData.variants.default;
|
const isGreeterMode = typeof SessionData !== "undefined" && SessionData.isGreeterMode;
|
||||||
|
const selectedVariantId = isGreeterMode
|
||||||
|
? (typeof GreetdSettings.registryThemeVariants[themeId] === "string" ? GreetdSettings.registryThemeVariants[themeId] : themeData.variants.default)
|
||||||
|
: (typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, themeData.variants.default) : themeData.variants.default);
|
||||||
const variant = findVariant(themeData.variants.options, selectedVariantId);
|
const variant = findVariant(themeData.variants.options, selectedVariantId);
|
||||||
if (variant) {
|
if (variant) {
|
||||||
const variantColors = variant[colorMode] || variant.dark || variant.light || {};
|
const variantColors = variant[colorMode] || variant.dark || variant.light || {};
|
||||||
@@ -1424,8 +1427,13 @@ Singleton {
|
|||||||
const defaults = customThemeRawData.variants.defaults || {};
|
const defaults = customThemeRawData.variants.defaults || {};
|
||||||
const darkDefaults = defaults.dark || {};
|
const darkDefaults = defaults.dark || {};
|
||||||
const lightDefaults = defaults.light || defaults.dark || {};
|
const lightDefaults = defaults.light || defaults.dark || {};
|
||||||
const storedDark = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, darkDefaults, "dark") : darkDefaults;
|
const isGreeterMode = typeof SessionData !== "undefined" && SessionData.isGreeterMode;
|
||||||
const storedLight = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, lightDefaults, "light") : lightDefaults;
|
const storedDark = isGreeterMode
|
||||||
|
? (GreetdSettings.registryThemeVariants[themeId]?.dark || darkDefaults)
|
||||||
|
: (typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, darkDefaults, "dark") : darkDefaults);
|
||||||
|
const storedLight = isGreeterMode
|
||||||
|
? (GreetdSettings.registryThemeVariants[themeId]?.light || lightDefaults)
|
||||||
|
: (typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeMultiVariant(themeId, lightDefaults, "light") : lightDefaults);
|
||||||
const darkFlavorId = storedDark.flavor || darkDefaults.flavor || "";
|
const darkFlavorId = storedDark.flavor || darkDefaults.flavor || "";
|
||||||
const lightFlavorId = storedLight.flavor || lightDefaults.flavor || "";
|
const lightFlavorId = storedLight.flavor || lightDefaults.flavor || "";
|
||||||
const accentId = storedDark.accent || darkDefaults.accent || "";
|
const accentId = storedDark.accent || darkDefaults.accent || "";
|
||||||
@@ -1443,7 +1451,10 @@ Singleton {
|
|||||||
lightTheme = mergeColors(lightTheme, accent[lightFlavor.id] || {});
|
lightTheme = mergeColors(lightTheme, accent[lightFlavor.id] || {});
|
||||||
}
|
}
|
||||||
} else if (customThemeRawData.variants.options) {
|
} else if (customThemeRawData.variants.options) {
|
||||||
const selectedVariantId = typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, customThemeRawData.variants.default) : customThemeRawData.variants.default;
|
const isGreeterMode = typeof SessionData !== "undefined" && SessionData.isGreeterMode;
|
||||||
|
const selectedVariantId = isGreeterMode
|
||||||
|
? (typeof GreetdSettings.registryThemeVariants[themeId] === "string" ? GreetdSettings.registryThemeVariants[themeId] : customThemeRawData.variants.default)
|
||||||
|
: (typeof SettingsData !== "undefined" ? SettingsData.getRegistryThemeVariant(themeId, customThemeRawData.variants.default) : customThemeRawData.variants.default);
|
||||||
const variant = findVariant(customThemeRawData.variants.options, selectedVariantId);
|
const variant = findVariant(customThemeRawData.variants.options, selectedVariantId);
|
||||||
if (variant) {
|
if (variant) {
|
||||||
darkTheme = mergeColors(darkTheme, variant.dark || {});
|
darkTheme = mergeColors(darkTheme, variant.dark || {});
|
||||||
@@ -1771,6 +1782,7 @@ Singleton {
|
|||||||
const colorsPath = SessionData.isGreeterMode ? greetCfgDir + "/colors.json" : stateDir + "/dms-colors.json";
|
const colorsPath = SessionData.isGreeterMode ? greetCfgDir + "/colors.json" : stateDir + "/dms-colors.json";
|
||||||
return colorsPath;
|
return colorsPath;
|
||||||
}
|
}
|
||||||
|
blockLoading: false
|
||||||
watchChanges: !SessionData.isGreeterMode
|
watchChanges: !SessionData.isGreeterMode
|
||||||
|
|
||||||
function parseAndLoadColors() {
|
function parseAndLoadColors() {
|
||||||
|
|||||||
Reference in New Issue
Block a user