Feat: LLM Chat and Nightlight shader #155

Open
zach wants to merge 21 commits from feat/llm-chat-tab into main
20 changed files with 329 additions and 110 deletions
Showing only changes of commit dbb51ceadd - Show all commits
-1
View File
@@ -30,7 +30,6 @@ Flickable {
onTriggered: {
root.doneFakeFlick = false;
root.returnToBounds();
}
}
}
+5 -10
View File
@@ -13,21 +13,17 @@ import qs.Paths
Singleton {
id: root
readonly property M3Palette current: M3Palette {
}
readonly property M3Palette current: M3Palette {}
property bool currentLight
property string flavour
readonly property bool light: showPreview ? previewLight : currentLight
readonly property M3Palette palette: showPreview ? preview : current
readonly property M3Palette preview: M3Palette {
}
readonly property M3Palette preview: M3Palette {}
property bool previewLight
property string scheme
property bool showPreview
readonly property M3TPalette tPalette: M3TPalette {
}
readonly property Transparency transparency: Transparency {
}
readonly property M3TPalette tPalette: M3TPalette {}
readonly property Transparency transparency: Transparency {}
readonly property alias wallLuminance: analyser.luminance
function alterColor(c: color, a: real, layer: int): color {
@@ -112,8 +108,7 @@ Singleton {
function setMode(mode: string): void {
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
Config.general.color.mode = mode;
Config.save();
Config.colors.mode = mode;
}
function swapRG(c: color): color {
+7 -7
View File
@@ -9,13 +9,13 @@ Singleton {
id: root
readonly property bool enabled: service.enabled
readonly property int end: Config.general.color.scheduleHyprsunsetEnd
readonly property int end: Config.display.nightlight.scheduleEnd
property bool manualToggle: false
readonly property int start: Config.general.color.scheduleHyprsunsetStart
readonly property int temp: Config.general.color.hyprsunsetTemp
readonly property int start: Config.display.nightlight.scheduleStart
readonly property int temp: Config.display.nightlight.temp
function checkStartup(): void {
if (!Config.general.color.scheduleHyprsunset)
if (!Config.display.nightlight.schedule)
return;
service.apply();
@@ -29,11 +29,11 @@ Singleton {
NightlightManager {
id: service
activeAuto: Config.general.color.scheduleHyprsunset
activeAuto: Config.display.nightlight.schedule
endTime: root.end
startTime: root.start
temp: root.temp
fadeDuration: Config.general.color.nativeFadeDuration / 1000
useNativeNightlight: Config.general.color.useNativeNightlight
fadeDuration: Config.display.nightlight.fadeDuration / 1000
useNativeNightlight: Config.display.nightlight.useNative
}
}
+6 -6
View File
@@ -11,14 +11,14 @@ import qs.Services
Singleton {
id: root
readonly property int darkEnd: Config.general.color.scheduleDarkEnd
readonly property int darkStart: Config.general.color.scheduleDarkStart
readonly property bool enabled: Config.general.color.scheduleDark && Config.general.color.schemeGeneration
readonly property int darkEnd: Config.colors.scheduleDarkEnd
readonly property int darkStart: Config.colors.scheduleDarkStart
readonly property bool enabled: Config.colors.scheduleDark && Config.colors.schemeGen
function applyDarkMode() {
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", "dark"]);
Config.general.color.mode = "dark";
Config.colors.mode = "dark";
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-dark'"]);
@@ -30,13 +30,13 @@ Singleton {
function applyLightMode() {
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", "light"]);
Config.general.color.mode = "light";
Config.colors.mode = "light";
Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", "'prefer-light'"]);
Quickshell.execDetached(["sh", "-c", `sed -i 's/color_scheme_path=\\(.*\\)Dark.colors/color_scheme_path=\\1Light.colors/' ${Paths.home}/.config/qt6ct/qt6ct.conf`]);
if (Config.general.color.neovimColors)
if (Config.colors.neovimColors)
Quickshell.execDetached(["sed", "-i", "'s/\\(vim.cmd.colorscheme \\).*/\\1\"onelight\"/'", "~/.config/nvim/lua/config/load-colorscheme.lua"]);
}
+3 -3
View File
@@ -38,7 +38,7 @@ Searcher {
previewPath = path;
showPreview = true;
if (Config.general.color.schemeGeneration)
if (Config.colors.schemeGen)
previewColorsProc.running = true;
}
@@ -62,8 +62,8 @@ Searcher {
WallpaperPath.currentWallpaperPath = path;
Quickshell.screens.forEach(n => setCrop(n.name, Qt.rect(0, 0, 1, 1), 1.0));
Quickshell.execDetached(["zshell-cli", "wallpaper", "lockscreen", "--input-image", `${root.actualCurrent}`, "--output-path", `${Paths.state}/lockscreen_bg.png`, "--blur-amount", `${Config.lock.blurAmount}`]);
if (Config.general.color.schemeGeneration)
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.general.color.mode}`]);
if (Config.colors.schemeGen)
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--image-path", `${root.actualCurrent}`, "--scheme", `${Config.colors.schemeType}`, "--mode", `${Config.colors.mode}`]);
}
function stopPreview(): void {
+11 -11
View File
@@ -43,17 +43,17 @@ Item {
Component.onCompleted: root.loadPage(root.sState.currentPageIdx)
CustomRect {
anchors.fill: parent
color: Qt.alpha(Colors.palette.m3shadow, 0.3)
opacity: root.sState.dimmed ? 1 : 0
visible: opacity > 0
z: 0
Behavior on opacity {
Anim {}
}
}
// CustomRect {
// anchors.fill: parent
// color: Qt.alpha(Colors.palette.m3shadow, 0.3)
// opacity: root.sState.dimmed ? 1 : 0
// visible: opacity > 0
// z: 0
//
// Behavior on opacity {
// Anim {}
// }
// }
}
Connections {
+2 -2
View File
@@ -202,12 +202,12 @@ PageBase {
}
ToggleRow {
checked: Config.general.color.smart
checked: Config.colors.smart
settingAnchor: "services-smart-color-scheme"
subtext: qsTr("Derive theme mode from the wallpaper")
text: qsTr("Smart color scheme")
onToggled: Config.general.color.smart = checked
onToggled: Config.colors.smart = checked
}
SelectRow {
@@ -73,15 +73,15 @@ PageBase {
ToggleRow {
text: qsTr("Dynamic colors")
first: true
subtext: qsTr("Automatic color scheme based on wallpaper is %1").arg(Config.general.color.schemeGeneration ? "enabled" : "disabled")
checked: Config.general.color.schemeGeneration
subtext: qsTr("Automatic color scheme based on wallpaper is %1").arg(Config.colors.schemeGen ? "enabled" : "disabled")
checked: Config.colors.schemeGen
settingAnchor: "colors-fonts-dynamic-colors"
onToggled: {
Config.general.color.schemeGeneration = checked;
Config.colors.schemeGen = checked;
if (checked)
Colors.setMode(Config.general.color.mode);
Colors.setMode(Config.colors.mode);
}
}
@@ -89,7 +89,7 @@ PageBase {
settingAnchor: "colors-fonts-preset-scheme"
model: root.schemes
acceptLabel: qsTr("Confirm")
enabled: !Config.general.color.schemeGeneration
enabled: !Config.colors.schemeGen
header: qsTr("Select scheme")
rowButton.activeItem: root.schemes.find(s => {
var regex = new RegExp(Config.colors.presets.name, "i");
@@ -157,7 +157,7 @@ PageBase {
}
// qmlformat on
acceptLabel: qsTr("Confirm")
enabled: !Config.general.color.schemeGeneration && model.length > 1
enabled: !Config.colors.schemeGen && model.length > 1
header: qsTr("Select variant")
rowButton.activeItem: {
const v = Config.colors.presets.variant ?? "";
@@ -210,7 +210,7 @@ PageBase {
}
// qmlformat on
acceptLabel: qsTr("Confirm")
enabled: !Config.general.color.schemeGeneration && model.length > 1
enabled: !Config.colors.schemeGen && model.length > 1
header: qsTr("Select accent")
rowButton.activeItem: {
const a = Config.colors.presets.accent ?? "";
+62 -21
View File
@@ -96,20 +96,21 @@ PageBase {
TimeDialogSelect {
readonly property string endTime: {
var d = new Date(0, 0, 0, 0, 0, 0, 0);
d.setMinutes(Config.general.color.scheduleDarkEnd);
d.setMinutes(Config.colors.scheduleDarkEnd);
return Qt.formatTime(d, "hh:mm AP");
}
readonly property string startTime: {
var d = new Date(0, 0, 0, 0, 0, 0, 0);
d.setMinutes(Config.general.color.scheduleDarkStart);
d.setMinutes(Config.colors.scheduleDarkStart);
return Qt.formatTime(d, "hh:mm AP");
}
rowButton.checked: Config.general.color.scheduleDark
rowButton.onToggled: Config.general.color.scheduleDark = rowButton.checked
start: Config.general.color.scheduleDarkStart
end: Config.general.color.scheduleDarkEnd
rowButton.checked: Config.colors.scheduleDark
rowButton.onToggled: Config.colors.scheduleDark = rowButton.checked
start: Config.colors.scheduleDarkStart
end: Config.colors.scheduleDarkEnd
first: true
last: true
settingAnchor: "style-schedule-dark-mode"
acceptLabel: qsTr("Apply")
rootParent: root.flickable
@@ -122,8 +123,8 @@ PageBase {
}
onAccepted: {
Config.general.color.scheduleDarkStart = startCurrent;
Config.general.color.scheduleDarkEnd = endCurrent;
Config.colors.scheduleDarkStart = startCurrent;
Config.colors.scheduleDarkEnd = endCurrent;
ModeScheduler.checkStartup();
}
}
@@ -131,37 +132,77 @@ PageBase {
TimeDialogSelect {
readonly property string endTime: {
var d = new Date(0, 0, 0, 0, 0, 0, 0);
d.setMinutes(Config.general.color.scheduleHyprsunsetEnd);
d.setMinutes(Config.display.nightlight.scheduleEnd);
return Qt.formatTime(d, "hh:mm AP");
}
readonly property string startTime: {
var d = new Date(0, 0, 0, 0, 0, 0, 0);
d.setMinutes(Config.general.color.scheduleHyprsunsetStart);
d.setMinutes(Config.display.nightlight.scheduleStart);
return Qt.formatTime(d, "hh:mm AP");
}
Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing
rowButton.checked: Config.general.color.scheduleHyprsunset
rowButton.onToggled: Config.general.color.scheduleHyprsunset = rowButton.checked
start: Config.general.color.scheduleHyprsunsetStart
end: Config.general.color.scheduleHyprsunsetEnd
last: true
settingAnchor: "style-schedule-hyprsunset"
rowButton.checked: Config.display.nightlight.schedule
rowButton.onToggled: Config.display.nightlight.schedule = rowButton.checked
start: Config.display.nightlight.scheduleStart
end: Config.display.nightlight.scheduleEnd
first: true
settingAnchor: "style-schedule-nightlight"
acceptLabel: qsTr("Apply")
rootParent: root.flickable
header: qsTr("Select time")
subtext: qsTr("Hyprsunset will turn on at %1, and turn off at %2.").arg(startTime).arg(endTime)
label: qsTr("Schedule hyprsunset")
subtext: qsTr("Nightlight will turn on at %1, and turn off at %2.").arg(startTime).arg(endTime)
label: qsTr("Schedule nightlight")
onOpenChanged: {
root.sState.dimmed = open;
}
onAccepted: {
Config.general.color.scheduleHyprsunsetStart = startCurrent;
Config.general.color.scheduleHyprsunsetEnd = endCurrent;
Config.display.nightlight.scheduleStart = startCurrent;
Config.display.nightlight.scheduleEnd = endCurrent;
Hyprsunset.checkStartup();
}
}
ToggleRow {
Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing
checked: Config.display.nightlight.useNative
settingAnchor: "display-nightlight-useNative"
text: qsTr("Use native")
subtext: qsTr("Use native shader nightlight for more features")
onToggled: Config.display.nightlight.useNative = checked
}
SpinRow {
Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing
from: 2000
settingAnchor: "display-nightlight-temp"
stepSize: 100
subtext: qsTr("How warm/orange the screen will be. Lower is warmer (Kelvin)")
text: qsTr("Temperature")
to: 6500
value: Config.display.nightlight.temp
onMoved: v => Config.display.nightlight.temp = v
}
SpinRow {
Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing
from: 0
settingAnchor: "display-nightlight-fade-duration"
enabled: Config.display.nightlight.useNative
last: true
stepSize: 1
subtext: qsTr("How long it takes for the gradual nightlight to finish (s)")
text: qsTr("Fade duration")
to: 60 * 5
value: Config.display.nightlight.fadeDuration / 1000
onMoved: v => Config.display.nightlight.fadeDuration = v * 1000
}
}
}
+2
View File
@@ -5,6 +5,7 @@ qml_module(ZShell-config
configobject.hpp configobject.cpp
configlist.hpp configlist.cpp
config.hpp config.cpp
migration.hpp migration.cpp
anim.hpp anim.cpp
tokens.hpp
appearance.hpp
@@ -13,6 +14,7 @@ qml_module(ZShell-config
clipboard.hpp
colors.hpp
dashboard.hpp
display.hpp
dock.hpp
general.hpp
launcher.hpp
+7
View File
@@ -22,6 +22,13 @@ class Colors : public ConfigObject {
CONFIG_SUBOBJECT(Presets, presets)
CFG_PROPERTY(QString, schemeType, QStringLiteral("fidelity"))
CFG_PROPERTY(bool, scheduleDark, false)
CFG_PROPERTY(int, scheduleDarkEnd, 600)
CFG_PROPERTY(int, scheduleDarkStart, 1140)
CFG_PROPERTY(bool, schemeGen, true)
CFG_PROPERTY(bool, neovimColors, false)
CFG_PROPERTY(QString, mode, QStringLiteral("dark"))
CFG_PROPERTY(bool, smart, false)
public:
explicit Colors(QObject* parent = nullptr)
+13 -5
View File
@@ -6,11 +6,13 @@
#include "clipboard.hpp"
#include "colors.hpp"
#include "dashboard.hpp"
#include "display.hpp"
#include "dock.hpp"
#include "general.hpp"
#include "launcher.hpp"
#include "llm.hpp"
#include "lock.hpp"
#include "migration.hpp"
#include "notifs.hpp"
#include "osd.hpp"
#include "screenshot.hpp"
@@ -44,6 +46,7 @@ Config::Config(QObject* parent)
, m_clipboard(new Clipboard(this))
, m_colors(new Colors(this))
, m_dashboard(new Dashboard(this))
, m_display(new Display(this))
, m_dock(new Dock(this))
, m_general(new General(this))
, m_launcher(new Launcher(this))
@@ -111,11 +114,14 @@ void Config::loadSync() {
QJsonObject before;
bool existed = false;
bool migrated = false;
if (f.open(QIODevice::ReadOnly)) {
const auto doc = QJsonDocument::fromJson(f.readAll());
if (doc.isObject()) {
before = doc.object();
const QJsonObject raw = doc.object();
before = ConfigMigrations::apply(raw);
migrated = before != raw;
existed = true;
} else {
qInfo() << "Config: existing config at" << filePath()
@@ -130,7 +136,7 @@ void Config::loadSync() {
m_loading = false;
const auto after = toJson().toObject();
if (!existed || after != before) saveNow();
if (!existed || migrated || after != before) saveNow();
}
void Config::updateWatch() {
@@ -176,16 +182,18 @@ void Config::loadAsync() {
if (f.open(QIODevice::ReadOnly)) {
const auto doc = QJsonDocument::fromJson(f.readAll());
const bool valid = doc.isObject();
const QJsonObject before = valid ? doc.object() : QJsonObject();
const QJsonObject raw = valid ? doc.object() : QJsonObject();
const QJsonObject before = ConfigMigrations::apply(raw);
const bool migrated = valid && before != raw;
QMetaObject::invokeMethod(
this,
[this, valid, before]() {
[this, valid, migrated, before]() {
loadFromJson(QJsonValue(before));
m_loading = false;
const auto after = toJson().toObject();
if (!valid || after != before) saveNow();
if (!valid || migrated || after != before) saveNow();
if (m_reloadPending) m_reloadTimer.start();
},
+3
View File
@@ -21,6 +21,7 @@ class Bar;
class Clipboard;
class Colors;
class Dashboard;
class Display;
class Dock;
class General;
class Launcher;
@@ -44,6 +45,7 @@ class Config : public ConfigObject {
Q_MOC_INCLUDE("clipboard.hpp")
Q_MOC_INCLUDE("colors.hpp")
Q_MOC_INCLUDE("dashboard.hpp")
Q_MOC_INCLUDE("display.hpp")
Q_MOC_INCLUDE("dock.hpp")
Q_MOC_INCLUDE("general.hpp")
Q_MOC_INCLUDE("launcher.hpp")
@@ -62,6 +64,7 @@ class Config : public ConfigObject {
CONFIG_SUBOBJECT(Clipboard, clipboard)
CONFIG_SUBOBJECT(Colors, colors)
CONFIG_SUBOBJECT(Dashboard, dashboard)
CONFIG_SUBOBJECT(Display, display)
CONFIG_SUBOBJECT(Dock, dock)
CONFIG_SUBOBJECT(General, general)
CONFIG_SUBOBJECT(Launcher, launcher)
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include "configobject.hpp"
#include <qqmlintegration.h>
namespace ZShell::config {
class Nightlight : public ConfigObject {
Q_OBJECT
QML_ANONYMOUS
CFG_PROPERTY(bool, schedule, true)
CFG_PROPERTY(int, scheduleStart, 1200)
CFG_PROPERTY(int, scheduleEnd, 570)
CFG_PROPERTY(bool, useNative, true)
CFG_PROPERTY(int, fadeDuration, 2000)
CFG_PROPERTY(int, temp, 2600)
public:
explicit Nightlight(QObject* parent = nullptr) : ConfigObject(parent) {}
};
class Display : public ConfigObject {
Q_OBJECT
QML_ANONYMOUS
CONFIG_SUBOBJECT(Nightlight, nightlight)
public:
explicit Display(QObject* parent = nullptr)
: ConfigObject(parent), m_nightlight(new Nightlight(this)) {}
};
} // namespace ZShell::config
-24
View File
@@ -91,28 +91,6 @@ class Battery : public ConfigObject {
explicit Battery(QObject* parent = nullptr) : ConfigObject(parent) {}
};
class ColorSettings : public ConfigObject {
Q_OBJECT
QML_ANONYMOUS
CFG_PROPERTY(int, hyprsunsetTemp, 2600)
CFG_PROPERTY(QString, mode, QStringLiteral("dark"))
CFG_PROPERTY(bool, neovimColors, false)
CFG_PROPERTY(bool, useNativeNightlight, true)
CFG_PROPERTY(int, nativeFadeDuration, 2000)
CFG_PROPERTY(bool, scheduleDark, false)
CFG_PROPERTY(int, scheduleDarkEnd, 600)
CFG_PROPERTY(int, scheduleDarkStart, 1140)
CFG_PROPERTY(bool, scheduleHyprsunset, true)
CFG_PROPERTY(int, scheduleHyprsunsetEnd, 570)
CFG_PROPERTY(int, scheduleHyprsunsetStart, 1200)
CFG_PROPERTY(bool, schemeGeneration, true)
CFG_PROPERTY(bool, smart, false)
public:
explicit ColorSettings(QObject* parent = nullptr) : ConfigObject(parent) {}
};
class Idle : public ConfigObject {
Q_OBJECT
QML_ANONYMOUS
@@ -137,7 +115,6 @@ class General : public ConfigObject {
CONFIG_SUBOBJECT(Apps, apps)
CONFIG_SUBOBJECT(Battery, battery)
CONFIG_SUBOBJECT(ColorSettings, color)
CFG_PROPERTY(QString, dateFormat, QStringLiteral("ddd d MMM - hh:mm:ss"))
CFG_PROPERTY(bool, desktopIcons, true)
CONFIG_SUBOBJECT(Idle, idle)
@@ -153,7 +130,6 @@ class General : public ConfigObject {
: ConfigObject(parent)
, m_apps(new Apps(this))
, m_battery(new Battery(this))
, m_color(new ColorSettings(this))
, m_idle(new Idle(this)) {}
};
+123
View File
@@ -0,0 +1,123 @@
#include "migration.hpp"
#include <QDebug>
namespace ZShell::config {
namespace {
// A stored value is "missing" if the path does not resolve to an entry.
// Note: default-constructed QJsonValue is Null, not Undefined.
bool isMissing(const QJsonValue& v) {
return v.isUndefined() || v.isNull();
}
QJsonValue valueAt(const QJsonObject& obj, const QStringList& path) {
QJsonObject cur = obj;
for (int i = 0; i < path.size() - 1; ++i) {
if (!cur.value(path.at(i)).isObject()) return QJsonValue::Undefined;
cur = cur.value(path.at(i)).toObject();
}
const QString key = path.last();
if (!cur.contains(key)) return QJsonValue::Undefined;
return cur.value(key);
}
QJsonObject placeAt(QJsonObject obj, QStringList path, const QJsonValue& value) {
const QString head = path.takeFirst();
if (path.isEmpty()) {
obj[head] = value;
return obj;
}
QJsonObject child = obj.value(head).isObject() ? obj.value(head).toObject()
: QJsonObject();
obj[head] = placeAt(child, path, value);
return obj;
}
// Removes `path` from `obj`. Returns true if a value was removed.
// Parent objects left empty are removed as well.
bool removeAt(QJsonObject& obj, const QStringList& path) {
const QString head = path.first();
if (path.size() == 1) {
if (!obj.contains(head)) return false;
obj.remove(head);
return true;
}
if (!obj.value(head).isObject()) return false;
QJsonObject child = obj.value(head).toObject();
const bool removed = removeAt(child, path.mid(1));
if (child.isEmpty())
obj.remove(head);
else
obj[head] = child;
return removed;
}
} // namespace
const QList<ConfigMigrationRule>& ConfigMigrations::rules() {
static const QList<ConfigMigrationRule> s_rules = {
migrate(
"general.color.scheduleHyprsunset", "display.nightlight.schedule"),
migrate(
"general.color.scheduleHyprsunsetStart",
"display.nightlight.scheduleStart"),
migrate(
"general.color.scheduleHyprsunsetEnd",
"display.nightlight.scheduleEnd"),
migrate("general.color.scheduleDark", "colors.scheduleDark"),
migrate("general.color.scheduleDarkStart", "colors.scheduleDarkStart"),
migrate("general.color.scheduleDarkEnd", "colors.scheduleDarkEnd"),
migrate("general.color.schemeGeneration", "colors.schemeGen"),
migrate(
"general.color.useNativeNightlight",
"display.nightlight.useNative"),
migrate(
"general.color.nativeFadeDuration",
"display.nightlight.fadeDuration"),
migrate("general.color.hyprsunsetTemp", "display.nightlight.temp"),
migrate("general.color.neovimColors", "colors.neovimColors"),
migrate("general.color.mode", "colors.mode"),
migrate("general.color.smart", "colors.smart"),
};
return s_rules;
}
QJsonObject ConfigMigrations::apply(const QJsonObject& json) {
QJsonObject obj = json;
for (const auto& rule : rules()) {
const QStringList from =
rule.from.split(QLatin1Char('.'), Qt::SkipEmptyParts);
const QStringList to =
rule.to.split(QLatin1Char('.'), Qt::SkipEmptyParts);
if (from.isEmpty() || to.isEmpty()) continue;
const QJsonValue oldValue = valueAt(obj, from);
if (isMissing(oldValue)) continue;
const bool targetExists = !isMissing(valueAt(obj, to));
if (!targetExists) obj = placeAt(obj, to, oldValue);
if (removeAt(obj, from)) {
qInfo() << "Config migration:" << rule.from << "->" << rule.to
<< (targetExists ? "(target already set, old value dropped)"
: "(value moved)");
}
}
return obj;
}
} // namespace ZShell::config
+38
View File
@@ -0,0 +1,38 @@
#pragma once
#include <QJsonObject>
#include <QStringList>
namespace ZShell::config {
// A single migration rule: move the value stored at the dotted `from` path
// to the dotted `to` path, then delete the old key (and any parent objects
// left empty).
//
// Rules are applied to the raw JSON file on every load, before the schema
// loads it. They are idempotent: once the old key is gone the rule never
// fires again, so no version stamping is needed. Old rules can stay in the
// table forever.
//
// WARNING: the target path must exist in the schema (i.e. a ConfigObject
// property somewhere in the tree). If it does not, the migrated value is
// loaded as an unknown key and silently dropped on the next save.
struct ConfigMigrationRule {
QString from;
QString to;
};
// Helper for writing rules: migrate("general.color.foo", "display.bar.foo")
inline ConfigMigrationRule migrate(const QString& from, const QString& to) {
return {from, to};
}
class ConfigMigrations {
public:
[[nodiscard]] static const QList<ConfigMigrationRule>& rules();
// Applies all rules to `json`, returning the migrated object.
[[nodiscard]] static QJsonObject apply(const QJsonObject& json);
};
} // namespace ZShell::config
@@ -10,7 +10,6 @@ namespace ZShell::services {
namespace {
constexpr const char* NL_EVENT = "zshell-nightlight";
constexpr int NEUTRAL_KELVIN = 6500;
constexpr int RECONNECT_MS = 2000;
} // namespace
@@ -404,7 +403,6 @@ void NightlightManager::handleEventLine(const QByteArray& line) {
if (line.left(sep) != NL_EVENT) return;
// data = enabled,animating,last,current
const auto fields = line.mid(sep + 2).split(',');
if (fields.size() < 4) return;
+5 -9
View File
@@ -13,21 +13,17 @@ import qs.Paths
Singleton {
id: root
readonly property M3Palette current: M3Palette {
}
readonly property M3Palette current: M3Palette {}
property bool currentLight
property string flavour
readonly property bool light: showPreview ? previewLight : currentLight
readonly property M3Palette palette: showPreview ? preview : current
readonly property M3Palette preview: M3Palette {
}
readonly property M3Palette preview: M3Palette {}
property bool previewLight
property string scheme
property bool showPreview
readonly property M3TPalette tPalette: M3TPalette {
}
readonly property Transparency transparency: Transparency {
}
readonly property M3TPalette tPalette: M3TPalette {}
readonly property Transparency transparency: Transparency {}
readonly property alias wallLuminance: analyser.luminance
function alterColor(c: color, a: real, layer: int): color {
@@ -112,7 +108,7 @@ Singleton {
function setMode(mode: string): void {
Quickshell.execDetached(["zshell-cli", "scheme", "generate", "--mode", mode]);
Config.general.color.mode = mode;
Config.colors.mode = mode;
}
function swapRG(c: color): color {
+2 -2
View File
@@ -625,8 +625,8 @@ def generate(
scheme_type = config["colors"].get("schemeType", "fruit-salad")
scheme = scheme or scheme_type
assert isinstance(scheme, str)
config_mode = config["general"]["color"]["mode"]
smart = bool(config["general"]["color"].get("smart", False))
config_mode = config["colors"]["mode"]
smart = bool(config["colors"].get("smart", False))
scheme_class = get_scheme_class(scheme)
p_variant = "default"