mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
feat(settings): add hooks to settings window
This commit is contained in:
@@ -704,6 +704,7 @@
|
||||
"appearance": "Appearance",
|
||||
"desktop": "Desktop",
|
||||
"dock": "Dock",
|
||||
"hooks": "Hooks",
|
||||
"panels": "Panels",
|
||||
"notifications": "Notifications",
|
||||
"backdrop": "Backdrop",
|
||||
@@ -727,6 +728,7 @@
|
||||
"focus-styling": "Focus Styling",
|
||||
"general": "General",
|
||||
"grouping": "Grouping",
|
||||
"lifecycle": "Lifecycle",
|
||||
"interface": "Interface",
|
||||
"launcher": "Launcher",
|
||||
"layout": "Layout",
|
||||
@@ -739,6 +741,7 @@
|
||||
"overview": "Overview",
|
||||
"pinned-apps": "Pinned Apps",
|
||||
"profile": "Profile",
|
||||
"power": "Power",
|
||||
"screen-corners": "Screen Corners",
|
||||
"security": "Security",
|
||||
"shape": "Shape",
|
||||
@@ -1546,6 +1549,71 @@
|
||||
"description": "Color temperature at night (Kelvin)"
|
||||
}
|
||||
},
|
||||
"hooks": {
|
||||
"events": {
|
||||
"started": {
|
||||
"label": "On Started",
|
||||
"description": "Command to run after Noctalia starts"
|
||||
},
|
||||
"wallpaper_changed": {
|
||||
"label": "On Wallpaper Changed",
|
||||
"description": "Command to run when the wallpaper changes"
|
||||
},
|
||||
"colors_changed": {
|
||||
"label": "On Colors Changed",
|
||||
"description": "Command to run when the active color palette changes"
|
||||
},
|
||||
"session_locked": {
|
||||
"label": "On Session Locked",
|
||||
"description": "Command to run when the session is locked"
|
||||
},
|
||||
"session_unlocked": {
|
||||
"label": "On Session Unlocked",
|
||||
"description": "Command to run after the session is unlocked"
|
||||
},
|
||||
"logging_out": {
|
||||
"label": "On Logout",
|
||||
"description": "Command to run before logging out"
|
||||
},
|
||||
"rebooting": {
|
||||
"label": "On Reboot",
|
||||
"description": "Command to run before rebooting"
|
||||
},
|
||||
"shutting_down": {
|
||||
"label": "On Shutdown",
|
||||
"description": "Command to run before shutdown"
|
||||
},
|
||||
"wifi_enabled": {
|
||||
"label": "On Wi-Fi Enabled",
|
||||
"description": "Command to run when Wi-Fi is enabled"
|
||||
},
|
||||
"wifi_disabled": {
|
||||
"label": "On Wi-Fi Disabled",
|
||||
"description": "Command to run when Wi-Fi is disabled"
|
||||
},
|
||||
"bluetooth_enabled": {
|
||||
"label": "On Bluetooth Enabled",
|
||||
"description": "Command to run when Bluetooth is enabled"
|
||||
},
|
||||
"bluetooth_disabled": {
|
||||
"label": "On Bluetooth Disabled",
|
||||
"description": "Command to run when Bluetooth is disabled"
|
||||
},
|
||||
"battery_state_changed": {
|
||||
"label": "On Battery State Changed",
|
||||
"description": "Command to run when charging state changes"
|
||||
},
|
||||
"battery_under_threshold": {
|
||||
"label": "On Battery Under Threshold",
|
||||
"description": "Command to run when battery percent drops under the configured threshold"
|
||||
}
|
||||
},
|
||||
"command-placeholder": "shell command or script path",
|
||||
"battery-low-threshold": {
|
||||
"label": "Battery Low Threshold",
|
||||
"description": "Percent threshold for the low-battery hook (0 disables it)"
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
"daemon": {
|
||||
"label": "Notification Daemon",
|
||||
|
||||
@@ -648,7 +648,8 @@ namespace settings {
|
||||
return wrap;
|
||||
};
|
||||
|
||||
const auto makeText = [&](const std::string& value, const std::string& placeholder, std::vector<std::string> path) {
|
||||
const auto makeText = [&](const std::string& value, const std::string& placeholder, std::vector<std::string> path,
|
||||
float width = 0.0f) {
|
||||
auto input = std::make_unique<Input>();
|
||||
input->setValue(value);
|
||||
input->setPlaceholder(placeholder.empty() ? i18n::tr("settings.controls.list.add-entry-placeholder")
|
||||
@@ -656,7 +657,8 @@ namespace settings {
|
||||
input->setFontSize(Style::fontSizeBody * scale);
|
||||
input->setControlHeight(Style::controlHeight * scale);
|
||||
input->setHorizontalPadding(Style::spaceSm * scale);
|
||||
input->setSize(190.0f * scale, Style::controlHeight * scale);
|
||||
const float inputWidth = (width > 0.0f ? width : 190.0f) * scale;
|
||||
input->setSize(inputWidth, Style::controlHeight * scale);
|
||||
input->setOnSubmit([setOverride = ctx.setOverride, path](const std::string& v) { setOverride(path, v); });
|
||||
return input;
|
||||
};
|
||||
@@ -1182,7 +1184,7 @@ namespace settings {
|
||||
return makeSlider(control.value, control.minValue, control.maxValue, control.step, entry.path,
|
||||
control.integerValue, control.linkedCommit);
|
||||
} else if constexpr (std::is_same_v<T, TextSetting>) {
|
||||
return makeText(control.value, control.placeholder, entry.path);
|
||||
return makeText(control.value, control.placeholder, entry.path, control.width);
|
||||
} else if constexpr (std::is_same_v<T, OptionalNumberSetting>) {
|
||||
return makeOptionalNumber(control, entry.path);
|
||||
} else if constexpr (std::is_same_v<T, ColorSetting>) {
|
||||
@@ -1250,8 +1252,10 @@ namespace settings {
|
||||
bool integerValue) -> std::unique_ptr<Node> {
|
||||
return makeSlider(value, minValue, maxValue, step, std::move(path), integerValue);
|
||||
},
|
||||
.makeText = [&](const std::string& value, const std::string& placeholder, std::vector<std::string> path)
|
||||
-> std::unique_ptr<Node> { return makeText(value, placeholder, std::move(path)); },
|
||||
.makeText = [&](const std::string& value, const std::string& placeholder,
|
||||
std::vector<std::string> path) -> std::unique_ptr<Node> {
|
||||
return makeText(value, placeholder, std::move(path));
|
||||
}, // width not used in search
|
||||
.makeColorRolePicker = [&](const ColorRolePickerSetting& setting, std::vector<std::string> path)
|
||||
-> std::unique_ptr<Node> { return makeColorRolePicker(setting, std::move(path)); },
|
||||
.makeListBlock = [&](Flex& section, const SettingEntry& entry,
|
||||
|
||||
@@ -222,6 +222,8 @@ namespace settings {
|
||||
return "layout-board";
|
||||
if (section == "services")
|
||||
return "stack-2";
|
||||
if (section == "hooks")
|
||||
return "link";
|
||||
if (section == "notifications")
|
||||
return "bell";
|
||||
if (section == "bar")
|
||||
@@ -750,6 +752,68 @@ namespace settings {
|
||||
{"nightlight", "temperature_night"}, std::move(nightSlider), "wlsunset kelvin"));
|
||||
}
|
||||
|
||||
// Hooks
|
||||
auto hookGroup = [](HookKind kind) -> std::string {
|
||||
switch (kind) {
|
||||
case HookKind::Started:
|
||||
case HookKind::SessionLocked:
|
||||
case HookKind::SessionUnlocked:
|
||||
case HookKind::LoggingOut:
|
||||
case HookKind::Rebooting:
|
||||
case HookKind::ShuttingDown:
|
||||
return "lifecycle";
|
||||
case HookKind::WallpaperChanged:
|
||||
case HookKind::ColorsChanged:
|
||||
return "theme";
|
||||
case HookKind::WifiEnabled:
|
||||
case HookKind::WifiDisabled:
|
||||
case HookKind::BluetoothEnabled:
|
||||
case HookKind::BluetoothDisabled:
|
||||
return "network";
|
||||
case HookKind::BatteryStateChanged:
|
||||
case HookKind::BatteryUnderThreshold:
|
||||
return "power";
|
||||
case HookKind::Count:
|
||||
break;
|
||||
}
|
||||
return "general";
|
||||
};
|
||||
|
||||
auto hookTags = [](HookKind kind) -> std::string {
|
||||
std::string tags = "hook command script exec event trigger";
|
||||
if (kind == HookKind::BatteryUnderThreshold || kind == HookKind::BatteryStateChanged) {
|
||||
tags += " battery power";
|
||||
}
|
||||
if (kind == HookKind::WallpaperChanged || kind == HookKind::ColorsChanged) {
|
||||
tags += " wallpaper colors theme";
|
||||
}
|
||||
if (kind == HookKind::WifiEnabled || kind == HookKind::WifiDisabled || kind == HookKind::BluetoothEnabled ||
|
||||
kind == HookKind::BluetoothDisabled) {
|
||||
tags += " network wifi bluetooth";
|
||||
}
|
||||
if (kind == HookKind::SessionLocked || kind == HookKind::SessionUnlocked || kind == HookKind::LoggingOut ||
|
||||
kind == HookKind::Rebooting || kind == HookKind::ShuttingDown || kind == HookKind::Started) {
|
||||
tags += " session startup";
|
||||
}
|
||||
return tags;
|
||||
};
|
||||
|
||||
for (const auto& kind : kHookKinds) {
|
||||
const auto index = static_cast<std::size_t>(kind.value);
|
||||
const std::string key(kind.key);
|
||||
const std::string baseKey = "settings.schema.hooks.events." + key;
|
||||
const std::string hookCmd = cfg.hooks.commands[index].empty() ? "" : cfg.hooks.commands[index][0];
|
||||
entries.push_back(makeEntry(
|
||||
"hooks", hookGroup(kind.value), tr(baseKey + ".label"), tr(baseKey + ".description"), {"hooks", key},
|
||||
TextSetting{hookCmd, tr("settings.schema.hooks.command-placeholder"), 320.0f}, hookTags(kind.value)));
|
||||
}
|
||||
|
||||
entries.push_back(makeEntry(
|
||||
"hooks", "power", tr("settings.schema.hooks.battery-low-threshold.label"),
|
||||
tr("settings.schema.hooks.battery-low-threshold.description"), {"hooks", "battery_low_percent_threshold"},
|
||||
SliderSetting{static_cast<float>(cfg.hooks.batteryLowPercentThreshold), 0.0f, 100.0f, 1.0f, true},
|
||||
"battery threshold hook trigger"));
|
||||
|
||||
// Notifications
|
||||
entries.push_back(makeEntry("notifications", "general", tr("settings.schema.notifications.daemon.label"),
|
||||
tr("settings.schema.notifications.daemon.description"),
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace settings {
|
||||
struct TextSetting {
|
||||
std::string value;
|
||||
std::string placeholder;
|
||||
float width = 0.0f; // 0 = use default
|
||||
};
|
||||
|
||||
struct OptionalNumberSetting {
|
||||
|
||||
Reference in New Issue
Block a user