mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-24 03:57:46 -04:00
feat(theme): add support for matugen smart mode and type (#3109)
* feat(theme): add support for matugen smart mode and type * add another dry run to get smart type preview * fix too much keywords in search index * revert dont extract translations * feat gate "Auto From Wallpaper" toggle row and the available matugen scheme for the pallete drop down * re-extract settings search index * make portal sync no longer disables matugen smart mode * make sure cosmic theme mode also follow change from smart mode * add translator context for Auto (Light Mode) / Auto (Dark Mode) / Auto From Wallpaper * fix: gate matugen smart mode checks on the dynamic theme so stock themes keep portal sync and fix tile labels in control center
This commit is contained in:
1 parent
b7034fcadb
commit
42080db61b
15 files changed
+305
-20
No files matched your search
@@ -63,9 +63,9 @@ func init() {
|
||||
cmd.Flags().String("config-dir", "", "User config directory")
|
||||
cmd.Flags().String("kind", "image", "Source type: image or hex")
|
||||
cmd.Flags().String("value", "", "Wallpaper path or hex color")
|
||||
cmd.Flags().String("mode", "dark", "Color mode: dark or light")
|
||||
cmd.Flags().String("mode", "dark", "Color mode: dark, light, or smart (smart requires matugen 4.2+ and an image source)")
|
||||
cmd.Flags().String("icon-theme", "System Default", "Icon theme name")
|
||||
cmd.Flags().String("matugen-type", "scheme-tonal-spot", "Matugen scheme type")
|
||||
cmd.Flags().String("matugen-type", "scheme-tonal-spot", "Matugen scheme type (supports scheme-smart on matugen 4.2+)")
|
||||
cmd.Flags().Bool("run-user-templates", true, "Run user matugen templates")
|
||||
cmd.Flags().String("stock-colors", "", "Stock theme colors JSON")
|
||||
cmd.Flags().Bool("sync-mode-with-portal", false, "Sync color scheme with GNOME portal")
|
||||
@@ -77,6 +77,7 @@ func init() {
|
||||
matugenQueueCmd.Flags().Bool("wait", true, "Wait for completion")
|
||||
matugenQueueCmd.Flags().Duration("timeout", 90*time.Second, "Timeout for waiting")
|
||||
matugenPreviewCmd.Flags().String("source-color", "", "Source color used to generate previews")
|
||||
matugenPreviewCmd.Flags().String("image", "", "Wallpaper image used to resolve the scheme-smart preview")
|
||||
matugenPreviewCmd.Flags().Float64("contrast", 0, "Contrast value from -1 to 1 (0 = standard)")
|
||||
matugenQtengineCmd.Flags().String("config-dir", "", "User config directory")
|
||||
matugenQtengineCmd.Flags().String("icon-theme", "", "Icon theme name")
|
||||
@@ -221,8 +222,9 @@ func runMatugenCheck(cmd *cobra.Command, args []string) {
|
||||
|
||||
func runMatugenPreview(cmd *cobra.Command, args []string) {
|
||||
sourceColor, _ := cmd.Flags().GetString("source-color")
|
||||
imagePath, _ := cmd.Flags().GetString("image")
|
||||
contrast, _ := cmd.Flags().GetFloat64("contrast")
|
||||
previews, err := matugen.PreviewSchemes(sourceColor, contrast)
|
||||
previews, err := matugen.PreviewSchemes(sourceColor, contrast, imagePath)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to generate Matugen previews: %v", err)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ type ColorMode string
|
||||
const (
|
||||
ColorModeDark ColorMode = "dark"
|
||||
ColorModeLight ColorMode = "light"
|
||||
ColorModeSmart ColorMode = "smart"
|
||||
)
|
||||
|
||||
type TemplateKind int
|
||||
@@ -94,6 +95,7 @@ var (
|
||||
matugenVersionOK bool
|
||||
matugenSupportsCOE bool
|
||||
matugenIsV4 bool
|
||||
matugenIsV42 bool
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
@@ -139,16 +141,17 @@ var previewSchemeTypes = []string{
|
||||
"scheme-rainbow",
|
||||
}
|
||||
|
||||
func PreviewSchemes(sourceColor string, contrast float64) (map[string]SchemePreview, error) {
|
||||
func PreviewSchemes(sourceColor string, contrast float64, imagePath string) (map[string]SchemePreview, error) {
|
||||
if sourceColor == "" {
|
||||
return nil, fmt.Errorf("source color is required")
|
||||
}
|
||||
|
||||
previews := make(map[string]SchemePreview, len(previewSchemeTypes))
|
||||
previews := make(map[string]SchemePreview, len(previewSchemeTypes)+1)
|
||||
for _, schemeType := range previewSchemeTypes {
|
||||
output, err := runMatugenDryRun(&Options{
|
||||
Kind: "hex",
|
||||
Value: sourceColor,
|
||||
Mode: ColorModeDark,
|
||||
MatugenType: schemeType,
|
||||
Contrast: contrast,
|
||||
})
|
||||
@@ -163,9 +166,39 @@ func PreviewSchemes(sourceColor string, contrast float64) (map[string]SchemePrev
|
||||
}
|
||||
previews[schemeType] = SchemePreview{Dark: dark, Light: light}
|
||||
}
|
||||
|
||||
previews["scheme-smart"] = smartSchemePreview(previews["scheme-tonal-spot"], contrast, imagePath)
|
||||
return previews, nil
|
||||
}
|
||||
|
||||
func smartSchemePreview(fallback SchemePreview, contrast float64, imagePath string) SchemePreview {
|
||||
if imagePath == "" {
|
||||
return fallback
|
||||
}
|
||||
flags, err := detectMatugenVersion()
|
||||
if err != nil || !flags.isV42 {
|
||||
return fallback
|
||||
}
|
||||
output, err := runMatugenDryRun(&Options{
|
||||
Kind: "image",
|
||||
Value: imagePath,
|
||||
Mode: ColorModeDark,
|
||||
MatugenType: "scheme-smart",
|
||||
Contrast: contrast,
|
||||
})
|
||||
if err != nil {
|
||||
log.Warnf("Smart scheme preview failed falling back to tonal-spot: %v", err)
|
||||
return fallback
|
||||
}
|
||||
dark := extractMatugenColor(output, "primary", "dark")
|
||||
light := extractMatugenColor(output, "primary", "light")
|
||||
if dark == "" || light == "" {
|
||||
log.Warn("Smart scheme preview failed falling back to tonal-spot: primary colors missing from matugen output")
|
||||
return fallback
|
||||
}
|
||||
return SchemePreview{Dark: dark, Light: light}
|
||||
}
|
||||
|
||||
func (o *Options) ColorsOutput() string {
|
||||
return filepath.Join(o.StateDir, "dms-colors.json")
|
||||
}
|
||||
@@ -280,6 +313,14 @@ func Run(opts Options) error {
|
||||
func buildOnce(opts *Options) (bool, error) {
|
||||
defer os.Remove(opts.colorsStaging())
|
||||
|
||||
flags, err := detectMatugenVersion()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if err := resolveSmartMode(opts, flags); err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
cfgFile, err := os.CreateTemp("", "matugen-config-*.toml")
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("failed to create temp config: %w", err)
|
||||
@@ -757,6 +798,7 @@ func extractTOMLSection(content, startMarker, endMarker string) string {
|
||||
type matugenFlags struct {
|
||||
supportsCOE bool
|
||||
isV4 bool
|
||||
isV42 bool
|
||||
}
|
||||
|
||||
func detectMatugenVersion() (matugenFlags, error) {
|
||||
@@ -764,12 +806,17 @@ func detectMatugenVersion() (matugenFlags, error) {
|
||||
defer matugenVersionMu.Unlock()
|
||||
|
||||
if matugenVersionOK {
|
||||
return matugenFlags{matugenSupportsCOE, matugenIsV4}, nil
|
||||
return matugenFlags{matugenSupportsCOE, matugenIsV4, matugenIsV42}, nil
|
||||
}
|
||||
|
||||
return detectMatugenVersionLocked()
|
||||
}
|
||||
|
||||
func SupportsSmart() bool {
|
||||
flags, err := detectMatugenVersion()
|
||||
return err == nil && flags.isV42
|
||||
}
|
||||
|
||||
func redetectMatugenVersion(old matugenFlags) (matugenFlags, bool) {
|
||||
matugenVersionMu.Lock()
|
||||
defer matugenVersionMu.Unlock()
|
||||
@@ -779,7 +826,7 @@ func redetectMatugenVersion(old matugenFlags) (matugenFlags, bool) {
|
||||
if err != nil {
|
||||
return old, false
|
||||
}
|
||||
changed := flags.supportsCOE != old.supportsCOE || flags.isV4 != old.isV4
|
||||
changed := flags.supportsCOE != old.supportsCOE || flags.isV4 != old.isV4 || flags.isV42 != old.isV42
|
||||
return flags, changed
|
||||
}
|
||||
|
||||
@@ -811,6 +858,7 @@ func detectMatugenVersionLocked() (matugenFlags, error) {
|
||||
|
||||
matugenSupportsCOE = major > 3 || (major == 3 && minor >= 1)
|
||||
matugenIsV4 = major >= 4
|
||||
matugenIsV42 = major > 4 || (major == 4 && minor >= 2)
|
||||
matugenVersionOK = true
|
||||
|
||||
if matugenSupportsCOE {
|
||||
@@ -819,7 +867,7 @@ func detectMatugenVersionLocked() (matugenFlags, error) {
|
||||
if matugenIsV4 {
|
||||
log.Debugf("Matugen %s detected: using v4 compatibility flags", versionStr)
|
||||
}
|
||||
return matugenFlags{matugenSupportsCOE, matugenIsV4}, nil
|
||||
return matugenFlags{matugenSupportsCOE, matugenIsV4, matugenIsV42}, nil
|
||||
}
|
||||
|
||||
func buildMatugenArgs(baseArgs []string, flags matugenFlags) []string {
|
||||
@@ -896,7 +944,7 @@ func execDryRun(opts *Options, flags matugenFlags) (string, error) {
|
||||
default:
|
||||
baseArgs = []string{opts.Kind, opts.Value}
|
||||
}
|
||||
baseArgs = append(baseArgs, "-m", "dark", "-t", opts.MatugenType, "--json", "hex", "--dry-run")
|
||||
baseArgs = append(baseArgs, "-m", string(opts.Mode), "-t", opts.MatugenType, "--json", "hex", "--dry-run")
|
||||
baseArgs = appendContrastArg(baseArgs, opts.Contrast)
|
||||
if flags.isV4 {
|
||||
baseArgs = append(baseArgs, "--source-color-index", "0", "--old-json-output")
|
||||
@@ -940,6 +988,44 @@ func extractMatugenColor(jsonStr, colorName, variant string) string {
|
||||
return variantData
|
||||
}
|
||||
|
||||
func extractTopLevelString(jsonStr, key string) string {
|
||||
var data map[string]any
|
||||
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
|
||||
return ""
|
||||
}
|
||||
if val, ok := data[key].(string); ok {
|
||||
return val
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func resolveSmartMode(opts *Options, flags matugenFlags) error {
|
||||
if opts.MatugenType == "scheme-smart" && !flags.isV42 {
|
||||
return fmt.Errorf("scheme-smart requires matugen 4.2+")
|
||||
}
|
||||
if opts.Mode != ColorModeSmart {
|
||||
return nil
|
||||
}
|
||||
if !flags.isV42 {
|
||||
return fmt.Errorf("smart mode requires matugen 4.2+")
|
||||
}
|
||||
if opts.Kind != "image" || opts.StockColors != "" {
|
||||
opts.Mode = ColorModeDark
|
||||
return nil
|
||||
}
|
||||
output, err := runMatugenDryRun(opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("smart mode resolution failed: %w", err)
|
||||
}
|
||||
resolved := extractTopLevelString(output, "mode")
|
||||
if resolved != string(ColorModeLight) && resolved != string(ColorModeDark) {
|
||||
return fmt.Errorf("smart mode resolution returned unexpected mode %q", resolved)
|
||||
}
|
||||
log.Infof("Smart mode resolved to %s", resolved)
|
||||
opts.Mode = ColorMode(resolved)
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractNestedColor(jsonStr, colorName, variant string) string {
|
||||
var data map[string]any
|
||||
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
|
||||
|
||||
@@ -970,3 +970,96 @@ func TestSyncQtengineConfigBumpsMtime(t *testing.T) {
|
||||
}
|
||||
assert.Equal(t, string(before), string(after))
|
||||
}
|
||||
|
||||
func TestExtractTopLevelString(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
jsonStr string
|
||||
key string
|
||||
want string
|
||||
}{
|
||||
{name: "returns top-level string key", jsonStr: `{"mode":"light","colors":{}}`, key: "mode", want: "light"},
|
||||
{name: "empty for missing key", jsonStr: `{"mode":"dark"}`, key: "is_dark_mode", want: ""},
|
||||
{name: "empty for non-string value", jsonStr: `{"mode":42}`, key: "mode", want: ""},
|
||||
{name: "empty for invalid json", jsonStr: `{mode`, key: "mode", want: ""},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
assert.Equal(t, tc.want, extractTopLevelString(tc.jsonStr, tc.key))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveSmartMode(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mode ColorMode
|
||||
matugenType string
|
||||
kind string
|
||||
stockColors string
|
||||
isV42 bool
|
||||
wantErr string
|
||||
wantMode ColorMode
|
||||
}{
|
||||
{
|
||||
name: "concrete mode passes through untouched",
|
||||
mode: ColorModeLight,
|
||||
kind: "image",
|
||||
isV42: true,
|
||||
wantMode: ColorModeLight,
|
||||
},
|
||||
{
|
||||
name: "smart mode errors on old matugen",
|
||||
mode: ColorModeSmart,
|
||||
kind: "image",
|
||||
isV42: false,
|
||||
wantErr: "smart mode requires matugen 4.2+",
|
||||
},
|
||||
{
|
||||
name: "scheme-smart errors on old matugen",
|
||||
mode: ColorModeDark,
|
||||
matugenType: "scheme-smart",
|
||||
kind: "image",
|
||||
isV42: false,
|
||||
wantErr: "scheme-smart requires matugen 4.2+",
|
||||
},
|
||||
{
|
||||
name: "smart falls back to dark for non-image kind",
|
||||
mode: ColorModeSmart,
|
||||
kind: "hex",
|
||||
isV42: true,
|
||||
wantMode: ColorModeDark,
|
||||
},
|
||||
{
|
||||
name: "smart falls back to dark for stock colors",
|
||||
mode: ColorModeSmart,
|
||||
kind: "image",
|
||||
stockColors: `{"primary":{}}`,
|
||||
isV42: true,
|
||||
wantMode: ColorModeDark,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
opts := &Options{
|
||||
Mode: tc.mode,
|
||||
MatugenType: tc.matugenType,
|
||||
Kind: tc.kind,
|
||||
StockColors: tc.stockColors,
|
||||
}
|
||||
if opts.MatugenType == "" {
|
||||
opts.MatugenType = "scheme-tonal-spot"
|
||||
}
|
||||
|
||||
err := resolveSmartMode(opts, matugenFlags{isV42: tc.isV42})
|
||||
if tc.wantErr != "" {
|
||||
assert.ErrorContains(t, err, tc.wantErr)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.wantMode, opts.Mode)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,8 @@ func handleMatugenQueue(conn *models.Conn, req models.Request) {
|
||||
func handleMatugenStatus(conn *models.Conn, req models.Request) {
|
||||
queue := matugen.GetQueue()
|
||||
models.Respond(conn, req.ID, map[string]bool{
|
||||
"running": queue.IsRunning(),
|
||||
"pending": queue.HasPending(),
|
||||
"running": queue.IsRunning(),
|
||||
"pending": queue.HasPending(),
|
||||
"smartSupported": matugen.SupportsSmart(),
|
||||
})
|
||||
}
|
||||
@@ -141,6 +141,7 @@ While the core colors above are required, you can also customize these optional
|
||||
- `scheme-monochrome` - Monochromatic color schemes
|
||||
- `scheme-neutral` - Neutral, subdued color schemes
|
||||
- `scheme-rainbow` - Rainbow-like color schemes
|
||||
- `scheme-smart` - Automatically picks the variant based on the wallpaper (requires matugen 4.2+)
|
||||
- `scheme-tonal-spot` - Tonal spot color schemes (default)
|
||||
|
||||
## Setting Custom Theme
|
||||
|
||||
@@ -611,9 +611,10 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function setLightMode(lightMode) {
|
||||
function setLightMode(lightMode, skipWallpaperSync) {
|
||||
isSwitchingMode = true;
|
||||
syncWallpaperForCurrentMode(lightMode);
|
||||
if (!skipWallpaperSync)
|
||||
syncWallpaperForCurrentMode(lightMode);
|
||||
isLightMode = lightMode;
|
||||
saveSettings();
|
||||
Qt.callLater(() => {
|
||||
|
||||
@@ -165,6 +165,7 @@ Singleton {
|
||||
property string customThemeFile: ""
|
||||
property var registryThemeVariants: ({})
|
||||
property string matugenScheme: "scheme-tonal-spot"
|
||||
property bool matugenSmartMode: false
|
||||
property real matugenContrast: 0
|
||||
property bool runUserMatugenTemplates: true
|
||||
property string matugenTargetMonitor: ""
|
||||
@@ -2732,6 +2733,12 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function setMatugenSmartMode(enabled) {
|
||||
if (matugenSmartMode === enabled)
|
||||
return;
|
||||
set("matugenSmartMode", enabled);
|
||||
}
|
||||
|
||||
function setMatugenContrast(value) {
|
||||
if (matugenContrast === value)
|
||||
return;
|
||||
|
||||
@@ -361,6 +361,10 @@ Singleton {
|
||||
"value": "scheme-rainbow",
|
||||
"label": I18n.tr("Rainbow", "matugen color scheme option"),
|
||||
"description": I18n.tr("Diverse palette spanning the full spectrum.")
|
||||
}), ({
|
||||
"value": "scheme-smart",
|
||||
"label": I18n.tr("Smart", "matugen color scheme option"),
|
||||
"description": I18n.tr("Automatically picks the scheme variant based on the wallpaper.")
|
||||
})]
|
||||
|
||||
function getMatugenScheme(value) {
|
||||
@@ -1198,6 +1202,11 @@ Singleton {
|
||||
}
|
||||
|
||||
function setLightMode(light, savePrefs = true, enableTransition = false) {
|
||||
if (typeof SettingsData !== "undefined" && SettingsData.matugenSmartMode) {
|
||||
SettingsData.matugenSmartMode = false;
|
||||
SettingsData.saveSettings();
|
||||
}
|
||||
|
||||
if (enableTransition) {
|
||||
screenTransition();
|
||||
lightModeTransitionTimer.lightMode = light;
|
||||
@@ -1525,7 +1534,7 @@ Singleton {
|
||||
const desired = {
|
||||
"kind": kind,
|
||||
"value": value,
|
||||
"mode": isLight ? "light" : "dark",
|
||||
"mode": (typeof SettingsData !== "undefined" && SettingsData.matugenSmartMode && kind === "image" && !stockColors) ? "smart" : (isLight ? "light" : "dark"),
|
||||
"iconTheme": iconTheme || "System Default",
|
||||
"matugenType": matugenType || "scheme-tonal-spot",
|
||||
"runUserTemplates": (typeof SettingsData !== "undefined") ? SettingsData.runUserMatugenTemplates : true
|
||||
@@ -2110,6 +2119,13 @@ Singleton {
|
||||
const colorsText = dynamicColorsFileView.text();
|
||||
if (colorsText) {
|
||||
root.matugenColors = JSON.parse(colorsText);
|
||||
if (typeof SettingsData !== "undefined" && SettingsData.matugenSmartMode && currentTheme === dynamic && root.matugenColors && root.matugenColors.mode && typeof SessionData !== "undefined" && !SessionData.isSwitchingMode) {
|
||||
const resolvedLight = root.matugenColors.mode === "light";
|
||||
if (SessionData.isLightMode !== resolvedLight) {
|
||||
SessionData.setLightMode(resolvedLight, true);
|
||||
SettingsData.updateCosmicThemeMode(resolvedLight);
|
||||
}
|
||||
}
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.clearWallpaperError();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ var SPEC = {
|
||||
customThemeFile: { def: "" },
|
||||
registryThemeVariants: { def: {} },
|
||||
matugenScheme: { def: "scheme-tonal-spot", onChange: "regenSystemThemes" },
|
||||
matugenSmartMode: { def: false, onChange: "regenSystemThemes" },
|
||||
matugenContrast: { def: 0, onChange: "regenSystemThemes" },
|
||||
runUserMatugenTemplates: { def: true, onChange: "regenSystemThemes" },
|
||||
matugenTargetMonitor: { def: "", onChange: "regenSystemThemes" },
|
||||
|
||||
@@ -743,8 +743,11 @@ Column {
|
||||
switch (widgetData.id || "") {
|
||||
case "nightMode":
|
||||
return I18n.tr("Night Mode");
|
||||
case "darkMode":
|
||||
case "darkMode": {
|
||||
if (SettingsData.matugenSmartMode && Theme.currentTheme === Theme.dynamic)
|
||||
return SessionData.isLightMode ? I18n.tr("Auto (Light Mode)", "dark mode toggle label when matugen smart mode resolved light") : I18n.tr("Auto (Dark Mode)", "dark mode toggle label when matugen smart mode resolved dark");
|
||||
return I18n.tr("Dark Mode");
|
||||
}
|
||||
case "idleInhibitor":
|
||||
return SessionService.idleInhibited ? I18n.tr("Keeping Awake") : I18n.tr("Keep Awake");
|
||||
default:
|
||||
|
||||
@@ -20,9 +20,11 @@ Item {
|
||||
readonly property bool frameModeActive: SettingsData.frameEnabled
|
||||
property var cachedIconThemes: SettingsData.availableIconThemes
|
||||
property var cachedCursorThemes: SettingsData.availableCursorThemes
|
||||
property var cachedMatugenSchemes: Theme.availableMatugenSchemes.map(option => option.label)
|
||||
readonly property bool matugenSmartCapable: Theme.matugenAvailable && DMSService.matugenSmartSupported
|
||||
property var cachedMatugenSchemes: Theme.availableMatugenSchemes.filter(option => DMSService.matugenSmartSupported || option.value !== "scheme-smart").map(option => option.label)
|
||||
property var matugenSchemePreviews: ({})
|
||||
property string matugenPreviewSource: ""
|
||||
property string matugenPreviewImage: ""
|
||||
property real matugenPreviewContrast: 0
|
||||
property string matugenPreviewRequestKey: ""
|
||||
property var installedRegistryThemes: []
|
||||
@@ -34,7 +36,7 @@ Item {
|
||||
const mode = SessionData.isLightMode ? "light" : "dark";
|
||||
for (var i = 0; i < Theme.availableMatugenSchemes.length; i++) {
|
||||
const option = Theme.availableMatugenSchemes[i];
|
||||
const preview = matugenSchemePreviews[option.value];
|
||||
const preview = matugenSchemePreviews[option.value] || matugenSchemePreviews["scheme-tonal-spot"];
|
||||
if (preview?.[mode])
|
||||
map[option.label] = preview[mode];
|
||||
}
|
||||
@@ -284,14 +286,18 @@ Item {
|
||||
return;
|
||||
const sourceColor = Theme.getMatugenColor("source_color", Theme.primary).toString();
|
||||
const contrast = SettingsData.matugenContrast ?? 0;
|
||||
const requestKey = sourceColor + "|" + contrast;
|
||||
if (sourceColor === matugenPreviewSource && contrast === matugenPreviewContrast && Object.keys(matugenSchemePreviews).length > 0)
|
||||
const imagePath = (Theme.rawWallpaperPath && !Theme.rawWallpaperPath.startsWith("#")) ? Theme.rawWallpaperPath : "";
|
||||
const requestKey = sourceColor + "|" + contrast + "|" + imagePath;
|
||||
if (sourceColor === matugenPreviewSource && contrast === matugenPreviewContrast && imagePath === matugenPreviewImage && Object.keys(matugenSchemePreviews).length > 0)
|
||||
return;
|
||||
if (requestKey === matugenPreviewRequestKey)
|
||||
return;
|
||||
matugenPreviewRequestKey = requestKey;
|
||||
|
||||
Proc.runCommand("", [Proc.dmsBin, "matugen", "preview", "--source-color", sourceColor, "--contrast", contrast.toString()], (output, exitCode) => {
|
||||
const args = [Proc.dmsBin, "matugen", "preview", "--source-color", sourceColor, "--contrast", contrast.toString()];
|
||||
if (imagePath)
|
||||
args.push("--image", imagePath);
|
||||
Proc.runCommand("", args, (output, exitCode) => {
|
||||
if (requestKey !== themeColorsTab.matugenPreviewRequestKey)
|
||||
return;
|
||||
if (exitCode !== 0) {
|
||||
@@ -301,6 +307,7 @@ Item {
|
||||
try {
|
||||
themeColorsTab.matugenSchemePreviews = JSON.parse(output.trim());
|
||||
themeColorsTab.matugenPreviewSource = sourceColor;
|
||||
themeColorsTab.matugenPreviewImage = imagePath;
|
||||
themeColorsTab.matugenPreviewContrast = contrast;
|
||||
} catch (e) {
|
||||
themeColorsTab.matugenPreviewRequestKey = "";
|
||||
@@ -1313,12 +1320,31 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
tab: "theme"
|
||||
tags: ["matugen", "smart", "wallpaper", "auto", "mode"]
|
||||
settingKey: "matugenSmartMode"
|
||||
text: I18n.tr("Auto From Wallpaper", "toggle that lets wallpaper brightness decide light/dark mode")
|
||||
description: I18n.tr("Dark or light mode follows the wallpaper brightness")
|
||||
checked: SettingsData.matugenSmartMode
|
||||
visible: matugenSmartCapable
|
||||
enabled: Theme.currentTheme === Theme.dynamic
|
||||
opacity: enabled ? 1 : 0.4
|
||||
onToggled: checked => {
|
||||
if (checked && SessionData.themeModeAutoEnabled)
|
||||
SessionData.setThemeModeAutoEnabled(false);
|
||||
SettingsData.setMatugenSmartMode(checked);
|
||||
}
|
||||
}
|
||||
|
||||
DankToggle {
|
||||
id: themeModeAutoToggle
|
||||
width: parent.width
|
||||
text: I18n.tr("Automatic Control")
|
||||
checked: SessionData.themeModeAutoEnabled
|
||||
onToggled: checked => {
|
||||
if (checked && SettingsData.matugenSmartMode)
|
||||
SettingsData.setMatugenSmartMode(false);
|
||||
SessionData.setThemeModeAutoEnabled(checked);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ Singleton {
|
||||
property bool isConnected: false
|
||||
readonly property bool isConnecting: requestSocket.connected && !requestSocket.linkUp
|
||||
property bool subscribeConnected: false
|
||||
property bool matugenSmartSupported: false
|
||||
|
||||
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
|
||||
|
||||
@@ -150,6 +151,7 @@ Singleton {
|
||||
root.isConnected = true;
|
||||
root.connectionStateChanged();
|
||||
subscribeSocket.connected = true;
|
||||
root.refreshMatugenStatus();
|
||||
return;
|
||||
}
|
||||
root.isConnected = false;
|
||||
@@ -212,6 +214,13 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function refreshMatugenStatus() {
|
||||
sendRequest("matugen.status", null, response => {
|
||||
if (!response.error && response.result)
|
||||
matugenSmartSupported = response.result.smartSupported === true;
|
||||
});
|
||||
}
|
||||
|
||||
function sendSubscribeRequest() {
|
||||
const request = {
|
||||
"method": "subscribe",
|
||||
|
||||
@@ -91,6 +91,8 @@ Singleton {
|
||||
return false;
|
||||
if (typeof SessionData !== "undefined" && SessionData.themeModeAutoEnabled)
|
||||
return false;
|
||||
if (SettingsData.matugenSmartMode && typeof Theme !== "undefined" && Theme.currentTheme === Theme.dynamic)
|
||||
return false;
|
||||
return typeof Theme !== "undefined";
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"color14": {"dark": "{{dank16.color14.dark.hex}}", "light": "{{dank16.color14.light.hex}}", "default": "{{dank16.color14.default.hex}}"},
|
||||
"color15": {"dark": "{{dank16.color15.dark.hex}}", "light": "{{dank16.color15.light.hex}}", "default": "{{dank16.color15.default.hex}}"}
|
||||
},
|
||||
"mode": "{{mode}}",
|
||||
"colors": {
|
||||
"dark": {
|
||||
"background": "{{colors.background.dark.hex}}",
|
||||
|
||||
@@ -3564,6 +3564,42 @@
|
||||
"icon": "apps",
|
||||
"description": "Sync dark mode with settings portals for system-wide theme hints"
|
||||
},
|
||||
{
|
||||
"section": "matugenSmartMode",
|
||||
"label": "Auto From Wallpaper",
|
||||
"tabIndex": 10,
|
||||
"category": "Theme & Colors",
|
||||
"keywords": [
|
||||
"appearance",
|
||||
"auto",
|
||||
"background",
|
||||
"backlight",
|
||||
"bg",
|
||||
"bright",
|
||||
"brightness",
|
||||
"colors",
|
||||
"dark",
|
||||
"dark mode",
|
||||
"day",
|
||||
"desktop",
|
||||
"dim",
|
||||
"follows",
|
||||
"image",
|
||||
"light",
|
||||
"light mode",
|
||||
"look",
|
||||
"matugen",
|
||||
"mode",
|
||||
"night",
|
||||
"picture",
|
||||
"scheme",
|
||||
"smart",
|
||||
"style",
|
||||
"theme",
|
||||
"wallpaper"
|
||||
],
|
||||
"description": "Dark or light mode follows the wallpaper brightness"
|
||||
},
|
||||
{
|
||||
"section": "cursorHideAfterInactive",
|
||||
"label": "Auto-Hide Timeout",
|
||||
|
||||
Reference in new issue
Block a user