diff options
| author | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-05-03 14:32:53 +1000 |
|---|---|---|
| committer | 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> | 2025-05-03 14:32:53 +1000 |
| commit | 5978db658c541d4acf4de4a14139232f4a57284c (patch) | |
| tree | 754eeff62e09569ead024f89cc638a002a12c923 | |
| parent | launcher: fix scrollbar (diff) | |
| download | caelestia-shell-5978db658c541d4acf4de4a14139232f4a57284c.tar.gz caelestia-shell-5978db658c541d4acf4de4a14139232f4a57284c.tar.bz2 caelestia-shell-5978db658c541d4acf4de4a14139232f4a57284c.zip | |
feat: launcher actions
| -rw-r--r-- | config/LauncherConfig.qml | 4 | ||||
| -rw-r--r-- | modules/launcher/ActionItem.qml | 59 | ||||
| -rw-r--r-- | modules/launcher/Actions.qml | 127 | ||||
| -rw-r--r-- | modules/launcher/AppItem.qml | 2 | ||||
| -rw-r--r-- | modules/launcher/AppList.qml | 86 | ||||
| -rw-r--r-- | modules/launcher/Content.qml | 12 |
6 files changed, 277 insertions, 13 deletions
diff --git a/config/LauncherConfig.qml b/config/LauncherConfig.qml index caa3bc5..2bf465d 100644 --- a/config/LauncherConfig.qml +++ b/config/LauncherConfig.qml @@ -5,9 +5,11 @@ import QtQuick Singleton { readonly property int maxShown: 8 + readonly property string actionPrefix: ">" readonly property Sizes sizes: Sizes {} component Sizes: QtObject { - property int width: 600 + readonly property int width: 600 + readonly property int itemHeight: 57 } } diff --git a/modules/launcher/ActionItem.qml b/modules/launcher/ActionItem.qml new file mode 100644 index 0000000..06a9342 --- /dev/null +++ b/modules/launcher/ActionItem.qml @@ -0,0 +1,59 @@ +import "root:/widgets" +import "root:/config" +import Quickshell +import QtQuick + +PaddedRect { + id: root + + required property Actions.Action modelData + required property var list + + implicitWidth: ListView.view.width + implicitHeight: LauncherConfig.sizes.itemHeight + padding: [Appearance.padding.smaller, Appearance.padding.larger] + + StateLayer { + radius: Appearance.rounding.normal + + function onClicked(): void { + root.modelData.onClicked(root.list); + } + } + + MaterialIcon { + id: icon + + text: root.modelData.icon + font.pointSize: Appearance.font.size.extraLarge + + anchors.verticalCenter: parent.verticalCenter + } + + Item { + anchors.left: icon.right + anchors.leftMargin: Appearance.spacing.larger + anchors.verticalCenter: icon.verticalCenter + + implicitWidth: parent.width - icon.width + implicitHeight: childrenRect.height + + StyledText { + id: name + + text: root.modelData.name + font.pointSize: Appearance.font.size.normal + } + + StyledText { + text: root.modelData.desc + font.pointSize: Appearance.font.size.small + color: Appearance.alpha(Appearance.colours.m3outline, true) + + elide: Text.ElideRight + width: root.width - icon.width - Appearance.rounding.normal * 2 + + anchors.top: name.bottom + } + } +} diff --git a/modules/launcher/Actions.qml b/modules/launcher/Actions.qml new file mode 100644 index 0000000..4323bff --- /dev/null +++ b/modules/launcher/Actions.qml @@ -0,0 +1,127 @@ +pragma Singleton + +import "root:/utils/scripts/fuzzysort.js" as Fuzzy +import "root:/config" +import Quickshell +import Quickshell.Io +import QtQuick + +Singleton { + id: root + + readonly property list<Action> list: [ + Action { + name: qsTr("Scheme") + desc: qsTr("Change the current colour scheme") + icon: "palette" + + function onClicked(list: AppList): void { + root.autocomplete(list, "scheme"); + } + }, + Action { + name: qsTr("Wallpaper") + desc: qsTr("Change the current wallpaper") + icon: "image" + + function onClicked(list: AppList): void { + root.autocomplete(list, "wallpaper"); + } + }, + Action { + name: qsTr("Variant") + desc: qsTr("Change the current scheme variant") + icon: "colors" + + function onClicked(list: AppList): void { + root.autocomplete(list, "variant"); + } + }, + Action { + name: qsTr("Transparency") + desc: qsTr("Change shell transparency") + icon: "opacity" + + function onClicked(list: AppList): void { + root.autocomplete(list, "transparency"); + } + }, + Action { + name: qsTr("Light") + desc: qsTr("Change the scheme to light mode") + icon: "light_mode" + + function onClicked(list: AppList): void { + list.launcher.launcherVisible = false; + // TODO + } + }, + Action { + name: qsTr("Dark") + desc: qsTr("Change the scheme to dark mode") + icon: "dark_mode" + + function onClicked(list: AppList): void { + list.launcher.launcherVisible = false; + // TODO + } + }, + Action { + name: qsTr("Lock") + desc: qsTr("Lock the current session") + icon: "lock" + + function onClicked(list: AppList): void { + list.launcher.launcherVisible = false; + lock.running = true; + } + }, + Action { + name: qsTr("Sleep") + desc: qsTr("Suspend then hibernate") + icon: "bedtime" + + function onClicked(list: AppList): void { + list.launcher.launcherVisible = false; + sleep.running = true; + } + } + ] + + readonly property list<var> preppedNames: list.map(a => ({ + name: Fuzzy.prepare(a.name), + action: a + })) + + function fuzzyQuery(search: string): var { + return Fuzzy.go(search.slice(LauncherConfig.actionPrefix.length), preppedNames, { + all: true, + key: "name" + }).map(r => r.obj.action); + } + + function autocomplete(list: AppList, text: string): void { + list.search.text = `${LauncherConfig.actionPrefix}${text} `; + } + + Process { + id: lock + + command: ["loginctl", "lock-session"] + } + + Process { + id: sleep + + command: ["systemctl", "suspend-then-hibernate"] + } + + component Action: QtObject { + required property string name + required property string desc + required property string icon + + function onClicked(list: AppList): void { + } + } +} diff --git a/modules/launcher/AppItem.qml b/modules/launcher/AppItem.qml index ca1b611..744c2d0 100644 --- a/modules/launcher/AppItem.qml +++ b/modules/launcher/AppItem.qml @@ -1,5 +1,4 @@ import "root:/widgets" -import "root:/services" import "root:/config" import Quickshell import Quickshell.Widgets @@ -12,6 +11,7 @@ PaddedRect { required property Scope launcher implicitWidth: ListView.view.width + implicitHeight: LauncherConfig.sizes.itemHeight padding: [Appearance.padding.smaller, Appearance.padding.normal] StateLayer { diff --git a/modules/launcher/AppList.qml b/modules/launcher/AppList.qml index 3175402..ab08db7 100644 --- a/modules/launcher/AppList.qml +++ b/modules/launcher/AppList.qml @@ -1,3 +1,5 @@ +pragma ComponentBehavior: Bound + import "root:/widgets" import "root:/services" import "root:/config" @@ -9,18 +11,29 @@ ListView { id: root required property int padding - required property string search + required property TextField search required property Scope launcher + property bool isAction: search.text.startsWith(LauncherConfig.actionPrefix) + + function getModelValues() { + let text = search.text; + if (isAction) + return Actions.fuzzyQuery(text); + if (text.startsWith(LauncherConfig.actionPrefix)) + text = search.text.slice(LauncherConfig.actionPrefix.length); + return Apps.fuzzyQuery(text); + } + model: ScriptModel { - values: Apps.fuzzyQuery(root.search) + values: root.getModelValues() onValuesChanged: root.currentIndex = 0 } clip: true spacing: Appearance.spacing.small orientation: Qt.Vertical - implicitHeight: ((currentItem?.height ?? 1) + spacing) * Math.min(LauncherConfig.maxShown, count) - spacing + implicitHeight: (LauncherConfig.sizes.itemHeight + spacing) * Math.min(LauncherConfig.maxShown, count) - spacing anchors.left: parent.left anchors.right: parent.right @@ -34,9 +47,7 @@ ListView { color: Appearance.alpha(Appearance.colours.m3surfaceContainerHighest, true) } - delegate: AppItem { - launcher: root.launcher - } + delegate: isAction ? actionItem : appItem ScrollBar.vertical: StyledScrollBar { // Move half out @@ -84,8 +95,69 @@ ListView { } } + Component { + id: appItem + + AppItem { + launcher: root.launcher + } + } + + Component { + id: actionItem + + ActionItem { + list: root + } + } + Behavior on implicitHeight { - Anim {} + Anim { + duration: Appearance.anim.durations.large + easing.bezierCurve: Appearance.anim.curves.emphasizedDecel + } + } + + Behavior on isAction { + SequentialAnimation { + ParallelAnimation { + Anim { + target: root + property: "opacity" + from: 1 + to: 0 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + Anim { + target: root + property: "scale" + from: 1 + to: 0.9 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardAccel + } + } + PropertyAction {} + ParallelAnimation { + Anim { + target: root + property: "opacity" + from: 0 + to: 1 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + Anim { + target: root + property: "scale" + from: 0.9 + to: 1 + duration: Appearance.anim.durations.small + easing.bezierCurve: Appearance.anim.curves.standardDecel + } + } + } } component Anim: NumberAnimation { diff --git a/modules/launcher/Content.qml b/modules/launcher/Content.qml index 6784b0e..3f9fbe2 100644 --- a/modules/launcher/Content.qml +++ b/modules/launcher/Content.qml @@ -36,7 +36,7 @@ Item { id: list padding: root.padding - search: search.text + search: search launcher: root.launcher } @@ -60,7 +60,7 @@ Item { leftPadding: root.padding rightPadding: root.padding - placeholderText: qsTr("Type \">\" for commands") + placeholderText: qsTr(`Type "${LauncherConfig.actionPrefix}" for commands`) background: StyledRect { color: Appearance.alpha(Appearance.colours.m3surfaceContainerHigh, true) @@ -69,8 +69,12 @@ Item { onAccepted: { if (list.currentItem) { - Apps.launch(list.currentItem?.modelData); - root.launcher.launcherVisible = false; + if (list.isAction) + list.currentItem.modelData.onClicked(list); + else { + Apps.launch(list.currentItem?.modelData); + root.launcher.launcherVisible = false; + } } } |