224 lines
4.8 KiB
QML
224 lines
4.8 KiB
QML
pragma ComponentBehavior: Bound
|
|
|
|
import Quickshell
|
|
import QtQuick
|
|
import QtQuick.Layouts
|
|
import QtQml.Models
|
|
import qs.Components
|
|
import qs.Config
|
|
import qs.Helpers
|
|
|
|
Item {
|
|
id: root
|
|
|
|
property bool dragActive: false
|
|
property real dragHeight: 0
|
|
property real dragStartX: 0
|
|
property real dragStartY: 0
|
|
property real dragX: 0
|
|
property real dragY: 0
|
|
property var draggedModelData: null
|
|
property string draggedUid: ""
|
|
property bool dropAnimating: false
|
|
readonly property bool highlighted: SettingsHighlight.highlightedSetting === name
|
|
required property string name
|
|
required property var object
|
|
property var pendingCommitEntries: []
|
|
required property string setting
|
|
property int uidCounter: 0
|
|
property var visualEntries: []
|
|
|
|
function ensureVisualEntries() {
|
|
if (!root.dragActive && !root.dropAnimating)
|
|
root.rebuildVisualEntries();
|
|
}
|
|
|
|
function iconForId(id) {
|
|
switch (id) {
|
|
case "workspaces":
|
|
return "dashboard";
|
|
case "audio":
|
|
return "volume_up";
|
|
case "media":
|
|
return "play_arrow";
|
|
case "resources":
|
|
return "monitoring";
|
|
case "updates":
|
|
return "system_update";
|
|
case "dash":
|
|
return "space_dashboard";
|
|
case "spacer":
|
|
return "horizontal_rule";
|
|
case "activeWindow":
|
|
return "web_asset";
|
|
case "tray":
|
|
return "widgets";
|
|
case "upower":
|
|
return "battery_full";
|
|
case "network":
|
|
return "wifi";
|
|
case "clock":
|
|
return "schedule";
|
|
case "notifBell":
|
|
return "notifications";
|
|
default:
|
|
return "drag_indicator";
|
|
}
|
|
}
|
|
|
|
function indexForUid(uid) {
|
|
for (let i = 0; i < root.visualEntries.length; i++) {
|
|
if (root.visualEntries[i].uid === uid)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
function labelForId(id) {
|
|
switch (id) {
|
|
case "workspaces":
|
|
return qsTr("Workspaces");
|
|
case "audio":
|
|
return qsTr("Audio");
|
|
case "media":
|
|
return qsTr("Media");
|
|
case "resources":
|
|
return qsTr("Resources");
|
|
case "updates":
|
|
return qsTr("Updates");
|
|
case "dash":
|
|
return qsTr("Dash");
|
|
case "spacer":
|
|
return qsTr("Spacer");
|
|
case "activeWindow":
|
|
return qsTr("Title");
|
|
case "tray":
|
|
return qsTr("Tray");
|
|
case "upower":
|
|
return qsTr("Power");
|
|
case "network":
|
|
return qsTr("Network");
|
|
case "clock":
|
|
return qsTr("Clock");
|
|
case "notifBell":
|
|
return qsTr("Notifs");
|
|
case "hyprsunset":
|
|
return qsTr("Night light");
|
|
default:
|
|
return id;
|
|
}
|
|
}
|
|
|
|
function rebuildVisualEntries() {
|
|
const entries = root.object[root.setting] ?? [];
|
|
const next = [];
|
|
|
|
for (let i = 0; i < entries.length; i++) {
|
|
const entry = entries[i];
|
|
let existing = null;
|
|
|
|
for (let j = 0; j < root.visualEntries.length; j++) {
|
|
if (root.visualEntries[j].entry === entry) {
|
|
existing = root.visualEntries[j];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (existing)
|
|
next.push(existing);
|
|
else
|
|
next.push({
|
|
uid: `entry-${root.uidCounter++}`,
|
|
entry
|
|
});
|
|
}
|
|
|
|
root.visualEntries = next;
|
|
}
|
|
|
|
function updateEntry(index, value) {
|
|
const list = [...root.object[root.setting]];
|
|
const entry = list[index];
|
|
entry.enabled = value;
|
|
list[index] = entry;
|
|
root.object[root.setting] = list;
|
|
Config.save();
|
|
}
|
|
|
|
Layout.fillWidth: true
|
|
implicitHeight: layout.implicitHeight
|
|
|
|
Component.onCompleted: root.rebuildVisualEntries()
|
|
|
|
CustomRect {
|
|
anchors.fill: parent
|
|
anchors.margins: -Appearance.padding.smaller
|
|
color: DynamicColors.palette.m3primaryContainer
|
|
opacity: root.highlighted ? 0.5 : 0
|
|
radius: Appearance.rounding.small
|
|
z: -1
|
|
|
|
Behavior on opacity {
|
|
Anim {
|
|
duration: Appearance.anim.durations.normal
|
|
}
|
|
}
|
|
}
|
|
|
|
RowLayout {
|
|
id: layout
|
|
|
|
anchors.fill: parent
|
|
|
|
// spacing: Appearance.spacing.smaller
|
|
|
|
DelegateModel {
|
|
id: visualModel
|
|
|
|
delegate: entryDelegate
|
|
|
|
model: ScriptModel {
|
|
objectProp: "uid"
|
|
values: root.visualEntries
|
|
}
|
|
}
|
|
|
|
Repeater {
|
|
delegate: entryDelegate
|
|
model: visualModel
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: entryDelegate
|
|
|
|
IconButton {
|
|
required property int index
|
|
required property var modelData
|
|
|
|
Layout.fillWidth: true
|
|
Layout.preferredWidth: implicitWidth + (stateLayer.pressed ? 18 : internalChecked ? 7 : 0)
|
|
checked: modelData.entry.enabled ?? true
|
|
font: Appearance.font.family.sans
|
|
// icon: root.iconForId(modelData.entry.id)
|
|
icon: root.labelForId(modelData.entry.id)
|
|
inactiveColour: DynamicColors.layer(DynamicColors.palette.m3surfaceContainerHighest, 2)
|
|
radius: stateLayer.pressed ? 6 / 2 : internalChecked ? 6 : 8
|
|
radiusAnim.duration: MaterialEasing.expressiveEffectsTime
|
|
radiusAnim.easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
toggle: true
|
|
visible: !["spacer", "upower", "dash", "audio"].some(prefix => modelData.entry.id.startsWith(prefix))
|
|
|
|
Behavior on Layout.preferredWidth {
|
|
Anim {
|
|
duration: MaterialEasing.expressiveEffectsTime
|
|
easing.bezierCurve: MaterialEasing.expressiveEffects
|
|
}
|
|
}
|
|
|
|
onClicked: root.updateEntry(index, internalChecked)
|
|
}
|
|
}
|
|
}
|