init: working version
This commit is contained in:
commit
7d8d7dacae
109 changed files with 15066 additions and 0 deletions
59
modules/launcher/Background.qml
Normal file
59
modules/launcher/Background.qml
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import qs.config
|
||||
import QtQuick
|
||||
import QtQuick.Shapes
|
||||
|
||||
Shape {
|
||||
id: root
|
||||
|
||||
required property Item wrapper
|
||||
readonly property real rounding: Config.border.rounding
|
||||
readonly property bool flatten: wrapper.height < rounding * 2
|
||||
readonly property real roundingY: flatten ? wrapper.height / 2 : rounding
|
||||
|
||||
ShapePath {
|
||||
startX: (root.parent.width - root.wrapper.width) / 2 - rounding
|
||||
startY: root.parent.height + 0.5
|
||||
strokeWidth: -1
|
||||
fillColor: Config.colors.bg
|
||||
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
direction: PathArc.Counterclockwise
|
||||
}
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: -(root.wrapper.height - root.roundingY * 2)
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: -root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
}
|
||||
PathLine {
|
||||
relativeX: root.wrapper.width - root.rounding * 2
|
||||
relativeY: 0
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
}
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: root.wrapper.height - root.roundingY * 2
|
||||
}
|
||||
PathArc {
|
||||
relativeX: root.rounding
|
||||
relativeY: root.roundingY
|
||||
radiusX: root.rounding
|
||||
radiusY: Math.min(root.rounding, root.wrapper.height)
|
||||
direction: PathArc.Counterclockwise
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
167
modules/launcher/Content.qml
Normal file
167
modules/launcher/Content.qml
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
|
||||
import "services"
|
||||
import qs.services
|
||||
import qs.config
|
||||
import qs.custom
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property PersistentProperties uiState
|
||||
required property var wrapper
|
||||
required property var panels
|
||||
|
||||
readonly property color color: list.color
|
||||
readonly property int padding: 15
|
||||
readonly property int rounding: 25
|
||||
|
||||
implicitWidth: listWrapper.width + padding * 2
|
||||
implicitHeight: searchWrapper.height + listWrapper.height + padding * 2
|
||||
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Item {
|
||||
id: listWrapper
|
||||
|
||||
implicitWidth: list.width
|
||||
implicitHeight: list.height + root.padding
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.bottom: searchWrapper.top
|
||||
anchors.bottomMargin: root.padding
|
||||
|
||||
ContentList {
|
||||
id: list
|
||||
|
||||
uiState: root.uiState
|
||||
wrapper: root.wrapper
|
||||
panels: root.panels
|
||||
search: search
|
||||
padding: root.padding
|
||||
rounding: root.rounding
|
||||
}
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
id: searchWrapper
|
||||
|
||||
color: Config.colors.container
|
||||
radius: 1000
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: root.padding
|
||||
|
||||
implicitHeight: Math.max(searchIcon.implicitHeight, search.implicitHeight, clearIcon.implicitHeight)
|
||||
|
||||
MaterialIcon {
|
||||
id: searchIcon
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: root.padding
|
||||
|
||||
text: "search"
|
||||
color: Config.colors.tertiary
|
||||
}
|
||||
|
||||
CustomTextField {
|
||||
id: search
|
||||
|
||||
anchors.left: searchIcon.right
|
||||
anchors.right: clearBtn.left
|
||||
anchors.leftMargin: 7
|
||||
anchors.rightMargin: 7
|
||||
|
||||
topPadding: 12
|
||||
bottomPadding: 12
|
||||
|
||||
placeholderText: qsTr("Type \"%1\" for commands").arg(Config.launcher.actionPrefix)
|
||||
|
||||
onAccepted: {
|
||||
const currentItem = list.list?.currentItem;
|
||||
if (currentItem) {
|
||||
if (text.startsWith(Config.launcher.actionPrefix)) {
|
||||
currentItem.modelData.onClicked(root.uiState);
|
||||
} else {
|
||||
Apps.launch(currentItem.modelData);
|
||||
root.uiState.launcher = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onUpPressed: list.list?.decrementCurrentIndex()
|
||||
Keys.onDownPressed: list.list?.incrementCurrentIndex()
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
if (event.key === Qt.Key_J) {
|
||||
list.list?.incrementCurrentIndex();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_K) {
|
||||
list.list?.decrementCurrentIndex();
|
||||
event.accepted = true;
|
||||
}
|
||||
} else if (event.key === Qt.Key_Tab) {
|
||||
list.list?.incrementCurrentIndex();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && (event.modifiers & Qt.ShiftModifier))) {
|
||||
list.list?.decrementCurrentIndex();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.uiState
|
||||
|
||||
function onLauncherChanged(): void {
|
||||
if (root.uiState.launcher)
|
||||
search.focus = true;
|
||||
else {
|
||||
search.text = "";
|
||||
list.list.currentIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StateLayer {
|
||||
id: clearBtn
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: root.padding
|
||||
|
||||
implicitWidth: 24
|
||||
implicitHeight: 24
|
||||
|
||||
disabled: search.text === ""
|
||||
onClicked: search.text = ""
|
||||
opacity: disabled ? 0 : 1
|
||||
|
||||
MaterialIcon {
|
||||
id: clearIcon
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: search.text ? implicitWidth : implicitWidth / 2
|
||||
|
||||
text: "close"
|
||||
color: Config.colors.tertiary
|
||||
|
||||
Behavior on width {
|
||||
Anim { duration: Config.anim.durations.small }
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim { duration: Config.anim.durations.small }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
293
modules/launcher/ContentList.qml
Normal file
293
modules/launcher/ContentList.qml
Normal file
|
|
@ -0,0 +1,293 @@
|
|||
pragma ComponentBehavior: Bound
|
||||
|
||||
import "items"
|
||||
import "services"
|
||||
import qs.config
|
||||
import qs.custom
|
||||
import qs.services
|
||||
import qs.util
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property PersistentProperties uiState
|
||||
required property var wrapper
|
||||
required property var panels
|
||||
required property TextField search
|
||||
required property int padding
|
||||
required property int rounding
|
||||
|
||||
readonly property Item list: list
|
||||
readonly property color color: list.color
|
||||
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
implicitWidth: Config.launcher.itemWidth
|
||||
implicitHeight: list.implicitHeight > 0 ? list.implicitHeight : empty.implicitHeight
|
||||
|
||||
clip: true
|
||||
|
||||
CustomListView {
|
||||
id: list
|
||||
|
||||
model: ScriptModel {
|
||||
id: model
|
||||
|
||||
onValuesChanged: list.currentIndex = 0
|
||||
}
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
spacing: 7
|
||||
orientation: Qt.Vertical
|
||||
implicitHeight: (Config.launcher.itemHeight + spacing) * Math.min(Config.launcher.maxItemCount, count) - spacing
|
||||
|
||||
highlightMoveDuration: Config.anim.durations.normal
|
||||
highlightResizeDuration: 0
|
||||
keyNavigationWraps: true
|
||||
|
||||
property color color
|
||||
highlight: CustomRect {
|
||||
radius: 1000
|
||||
color: list.color
|
||||
opacity: 0.1
|
||||
}
|
||||
|
||||
state: {
|
||||
const text = root.search.text;
|
||||
const prefix = Config.launcher.actionPrefix;
|
||||
if (text.startsWith(prefix)) {
|
||||
return "actions";
|
||||
}
|
||||
|
||||
return "apps";
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "apps"
|
||||
|
||||
PropertyChanges {
|
||||
model.values: Apps.search(root.search.text)
|
||||
list.delegate: appItem
|
||||
list.color: Config.colors.launcherApps
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "actions"
|
||||
|
||||
PropertyChanges {
|
||||
model.values: Actions.query(root.search.text)
|
||||
list.delegate: actionItem
|
||||
list.color: Config.colors.launcherActions
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
// Disable animations before transition starts
|
||||
onStateChanged: {
|
||||
// NOTE: uiState check is necessary because this handler runs on startup
|
||||
if (root.uiState.launcher) {
|
||||
list.add.enabled = false;
|
||||
list.remove.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
transitions: Transition {
|
||||
SequentialAnimation {
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
target: list
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
duration: Config.anim.durations.small
|
||||
easing.bezierCurve: Config.anim.curves.standardAccel
|
||||
}
|
||||
Anim {
|
||||
target: list
|
||||
property: "scale"
|
||||
from: 1
|
||||
to: 0.9
|
||||
duration: Config.anim.durations.small
|
||||
easing.bezierCurve: Config.anim.curves.standardAccel
|
||||
}
|
||||
}
|
||||
PropertyAction {
|
||||
targets: [model, list]
|
||||
properties: "values,delegate,color"
|
||||
}
|
||||
ParallelAnimation {
|
||||
Anim {
|
||||
target: list
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
duration: Config.anim.durations.small
|
||||
easing.bezierCurve: Config.anim.curves.standardDecel
|
||||
}
|
||||
Anim {
|
||||
target: list
|
||||
property: "scale"
|
||||
from: 0.9
|
||||
to: 1
|
||||
duration: Config.anim.durations.small
|
||||
easing.bezierCurve: Config.anim.curves.standardDecel
|
||||
}
|
||||
}
|
||||
PropertyAction {
|
||||
targets: [list.add, list.remove]
|
||||
property: "enabled"
|
||||
value: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomScrollBar.vertical: CustomScrollBar {
|
||||
flickable: list
|
||||
}
|
||||
|
||||
add: Transition {
|
||||
Anim {
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
}
|
||||
Anim {
|
||||
property: "scale"
|
||||
from: 0.8
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
remove: Transition {
|
||||
Anim {
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
}
|
||||
Anim {
|
||||
property: "scale"
|
||||
from: 1
|
||||
to: 0.8
|
||||
}
|
||||
}
|
||||
|
||||
move: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
}
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
addDisplaced: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
duration: Config.anim.durations.small
|
||||
}
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
displaced: Transition {
|
||||
Anim {
|
||||
property: "y"
|
||||
}
|
||||
Anim {
|
||||
properties: "opacity,scale"
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: appItem
|
||||
|
||||
AppItem {
|
||||
uiState: root.uiState
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: actionItem
|
||||
|
||||
ActionItem {
|
||||
uiState: root.uiState
|
||||
list: list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: empty
|
||||
|
||||
opacity: root.list?.count === 0 ? 1 : 0
|
||||
scale: root.list?.count === 0 ? 1 : 0.5
|
||||
|
||||
spacing: 12
|
||||
padding: 15
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MaterialIcon {
|
||||
text: "manage_search"
|
||||
color: Config.colors.tertiary
|
||||
font.pointSize: Config.font.size.largest
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
CustomText {
|
||||
text: qsTr("No results")
|
||||
color: Config.colors.tertiary
|
||||
font.pointSize: Config.font.size.larger
|
||||
font.weight: 500
|
||||
}
|
||||
|
||||
CustomText {
|
||||
text: qsTr("Try searching for something else")
|
||||
color: Config.colors.tertiary
|
||||
font.pointSize: Config.font.size.normal
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
Anim {}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
Anim {}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitWidth {
|
||||
enabled: root.uiState.launcher
|
||||
|
||||
Anim {
|
||||
duration: Config.anim.durations.large
|
||||
easing.bezierCurve: Config.anim.curves.emphasizedDecel
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on implicitHeight {
|
||||
enabled: root.uiState.launcher
|
||||
|
||||
Anim {
|
||||
duration: Config.anim.durations.large
|
||||
easing.bezierCurve: Config.anim.curves.emphasizedDecel
|
||||
}
|
||||
}
|
||||
}
|
||||
75
modules/launcher/Wrapper.qml
Normal file
75
modules/launcher/Wrapper.qml
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
import qs.config
|
||||
import qs.custom
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property PersistentProperties uiState
|
||||
required property Item panels
|
||||
|
||||
visible: height > 0
|
||||
implicitHeight: 0
|
||||
implicitWidth: content.implicitWidth
|
||||
|
||||
states: State {
|
||||
name: "visible"
|
||||
when: root.uiState.launcher
|
||||
|
||||
PropertyChanges {
|
||||
root.implicitHeight: content.implicitHeight
|
||||
}
|
||||
}
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: ""
|
||||
to: "visible"
|
||||
|
||||
Anim {
|
||||
target: root
|
||||
property: "implicitHeight"
|
||||
duration: Config.anim.durations.expressiveDefaultSpatial
|
||||
easing.bezierCurve: Config.anim.curves.expressiveDefaultSpatial
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "visible"
|
||||
to: ""
|
||||
|
||||
Anim {
|
||||
target: root
|
||||
property: "implicitHeight"
|
||||
duration: Config.anim.durations.normal
|
||||
easing.bezierCurve: Config.anim.curves.emphasized
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
HyprlandFocusGrab {
|
||||
active: root.uiState.launcher
|
||||
windows: [QsWindow.window]
|
||||
onCleared: root.uiState.launcher = false
|
||||
}
|
||||
|
||||
Background {
|
||||
id: background
|
||||
visible: false
|
||||
wrapper: root
|
||||
}
|
||||
|
||||
GlowEffect {
|
||||
source: background
|
||||
glowColor: content.color
|
||||
}
|
||||
|
||||
Content {
|
||||
id: content
|
||||
|
||||
uiState: root.uiState
|
||||
wrapper: root
|
||||
panels: root.panels
|
||||
}
|
||||
}
|
||||
80
modules/launcher/items/ActionItem.qml
Normal file
80
modules/launcher/items/ActionItem.qml
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import "../services"
|
||||
import qs.config
|
||||
import qs.custom
|
||||
import qs.services
|
||||
import qs.util
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property Actions.Action modelData
|
||||
required property PersistentProperties uiState
|
||||
required property var list
|
||||
|
||||
implicitHeight: Config.launcher.itemHeight
|
||||
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
|
||||
StateLayer {
|
||||
radius: 1000
|
||||
anchors.fill: parent
|
||||
|
||||
function onClicked(): void {
|
||||
root.uiState.launcher = false;
|
||||
root.modelData?.onClicked(root.uiState);
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 12
|
||||
anchors.rightMargin: 12
|
||||
anchors.margins: 7
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
text: root.modelData?.icon ?? ""
|
||||
font.pointSize: Config.font.size.largest
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.left: icon.right
|
||||
anchors.leftMargin: 12
|
||||
anchors.verticalCenter: icon.verticalCenter
|
||||
|
||||
implicitWidth: parent.width - icon.width
|
||||
implicitHeight: name.implicitHeight + desc.implicitHeight
|
||||
|
||||
CustomText {
|
||||
id: name
|
||||
|
||||
text: root.modelData?.name ?? ""
|
||||
font.pointSize: Config.font.size.normal
|
||||
color: root.ListView.isCurrentItem ? Color.mute(Config.colors.launcherActions, 1.1) : Config.colors.primary
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: desc
|
||||
|
||||
text: root.modelData?.desc ?? ""
|
||||
font.pointSize: Config.font.size.small
|
||||
color: Config.colors.tertiary
|
||||
|
||||
elide: Text.ElideRight
|
||||
width: root.width - icon.width - 34
|
||||
|
||||
anchors.top: name.bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
modules/launcher/items/AppItem.qml
Normal file
80
modules/launcher/items/AppItem.qml
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
import "../services"
|
||||
import qs.config
|
||||
import qs.custom
|
||||
import qs.services
|
||||
import qs.util
|
||||
import Quickshell
|
||||
import Quickshell.Widgets
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property DesktopEntry modelData
|
||||
required property PersistentProperties uiState
|
||||
|
||||
implicitHeight: Config.launcher.itemHeight
|
||||
|
||||
anchors.left: parent?.left
|
||||
anchors.right: parent?.right
|
||||
|
||||
StateLayer {
|
||||
radius: 1000
|
||||
anchors.fill: parent
|
||||
|
||||
function onClicked(): void {
|
||||
Apps.launch(root.modelData);
|
||||
root.uiState.launcher = false;
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: 12
|
||||
anchors.rightMargin: 12
|
||||
anchors.margins: 7
|
||||
|
||||
IconImage {
|
||||
id: icon
|
||||
|
||||
source: Quickshell.iconPath(root.modelData?.icon, "image-missing")
|
||||
implicitSize: parent.height * 0.9
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Item {
|
||||
anchors.left: icon.right
|
||||
anchors.leftMargin: 12
|
||||
anchors.verticalCenter: icon.verticalCenter
|
||||
|
||||
implicitWidth: parent.width - icon.width
|
||||
implicitHeight: name.implicitHeight + comment.implicitHeight
|
||||
|
||||
CustomText {
|
||||
id: name
|
||||
|
||||
text: root.modelData?.name ?? ""
|
||||
font.pointSize: Config.font.size.normal
|
||||
color: root.ListView.isCurrentItem ? Color.mute(Config.colors.launcherApps) : Config.colors.primary
|
||||
|
||||
Behavior on color {
|
||||
CAnim {}
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
id: comment
|
||||
|
||||
text: (root.modelData?.comment || root.modelData?.genericName || root.modelData?.name) ?? ""
|
||||
font.pointSize: Config.font.size.small
|
||||
color: Config.colors.tertiary
|
||||
|
||||
elide: Text.ElideRight
|
||||
width: root.width - icon.width - 34
|
||||
|
||||
anchors.top: name.bottom
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
86
modules/launcher/services/Actions.qml
Normal file
86
modules/launcher/services/Actions.qml
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
pragma Singleton
|
||||
|
||||
import ".."
|
||||
import qs.config
|
||||
import qs.services
|
||||
import qs.util
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Searcher {
|
||||
id: root
|
||||
|
||||
readonly property list<Action> actions: [
|
||||
Action {
|
||||
name: qsTr("Shutdown")
|
||||
desc: qsTr("Shutdown the system")
|
||||
icon: "power_settings_new"
|
||||
|
||||
function onClicked(uiState: PersistentProperties): void {
|
||||
Quickshell.execDetached(Config.session.shutdown);
|
||||
}
|
||||
},
|
||||
Action {
|
||||
name: qsTr("Reboot")
|
||||
desc: qsTr("Reboot the system")
|
||||
icon: "cached"
|
||||
|
||||
function onClicked(uiState: PersistentProperties): void {
|
||||
Quickshell.execDetached(Config.session.reboot);
|
||||
}
|
||||
},
|
||||
Action {
|
||||
name: qsTr("Logout")
|
||||
desc: qsTr("Log out of the session and go back to the startup screen")
|
||||
icon: "logout"
|
||||
|
||||
function onClicked(uiState: PersistentProperties): void {
|
||||
Quickshell.execDetached(Config.session.logout);
|
||||
}
|
||||
},
|
||||
Action {
|
||||
name: qsTr("Lock")
|
||||
desc: qsTr("Activate the lock screen (hyprlock)")
|
||||
icon: "lock"
|
||||
|
||||
function onClicked(uiState: PersistentProperties): void {
|
||||
Quickshell.execDetached(Config.session.lock);
|
||||
}
|
||||
},
|
||||
Action {
|
||||
name: qsTr("Suspend")
|
||||
desc: qsTr("Suspend the system")
|
||||
icon: "bedtime"
|
||||
|
||||
function onClicked(uiState: PersistentProperties): void {
|
||||
Quickshell.execDetached(Config.session.suspend);
|
||||
}
|
||||
},
|
||||
Action {
|
||||
name: qsTr("Hibernate")
|
||||
desc: qsTr("Suspend, then hibernate the system")
|
||||
icon: "downloading"
|
||||
|
||||
function onClicked(uiState: PersistentProperties): void {
|
||||
Quickshell.execDetached(Config.session.hibernate);
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
function transformSearch(search: string): string {
|
||||
return search.slice(Config.launcher.actionPrefix.length);
|
||||
}
|
||||
|
||||
list: actions.filter(a => !a.disabled)
|
||||
useFuzzy: true
|
||||
|
||||
component Action: QtObject {
|
||||
required property string name
|
||||
required property string desc
|
||||
required property string icon
|
||||
property bool disabled
|
||||
|
||||
function onClicked(uiState: PersistentProperties): void {
|
||||
}
|
||||
}
|
||||
}
|
||||
86
modules/launcher/services/Apps.qml
Normal file
86
modules/launcher/services/Apps.qml
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
pragma Singleton
|
||||
|
||||
import qs.config
|
||||
import qs.util
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
|
||||
Searcher {
|
||||
id: root
|
||||
|
||||
function launch(entry: DesktopEntry): void {
|
||||
if (entry.runInTerminal)
|
||||
Quickshell.execDetached({
|
||||
command: [...Config.terminalCommand, ...entry.command],
|
||||
workingDirectory: entry.workingDirectory
|
||||
});
|
||||
else
|
||||
Quickshell.execDetached({
|
||||
command: entry.command,
|
||||
workingDirectory: entry.workingDirectory
|
||||
});
|
||||
}
|
||||
|
||||
function search(search: string): list<var> {
|
||||
const prefix = Config.launcher.specialPrefix;
|
||||
|
||||
if (search.startsWith(`${prefix}i `)) {
|
||||
keys = ["id", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}c `)) {
|
||||
keys = ["categories", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}d `)) {
|
||||
keys = ["desc", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}e `)) {
|
||||
keys = ["execString", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}w `)) {
|
||||
keys = ["wmClass", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}g `)) {
|
||||
keys = ["genericName", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else if (search.startsWith(`${prefix}k `)) {
|
||||
keys = ["keywords", "name"];
|
||||
weights = [0.9, 0.1];
|
||||
} else {
|
||||
keys = ["name"];
|
||||
weights = [1];
|
||||
|
||||
if (!search.startsWith(`${prefix}t `))
|
||||
return query(search).map(e => e.modelData);
|
||||
}
|
||||
|
||||
const results = query(search.slice(prefix.length + 2)).map(e => e.modelData);
|
||||
if (search.startsWith(`${prefix}t `))
|
||||
return results.filter(a => a.runInTerminal);
|
||||
return results;
|
||||
}
|
||||
|
||||
function selector(item: var): string {
|
||||
return keys.map(k => item[k]).join(" ");
|
||||
}
|
||||
|
||||
list: variants.instances
|
||||
useFuzzy: true
|
||||
|
||||
Variants {
|
||||
id: variants
|
||||
|
||||
model: [...DesktopEntries.applications.values].sort((a, b) => a.name.localeCompare(b.name))
|
||||
|
||||
QtObject {
|
||||
required property DesktopEntry modelData
|
||||
readonly property string id: modelData.id
|
||||
readonly property string name: modelData.name
|
||||
readonly property string desc: modelData.comment
|
||||
readonly property string execString: modelData.execString
|
||||
readonly property string wmClass: modelData.startupClass
|
||||
readonly property string genericName: modelData.genericName
|
||||
readonly property string categories: modelData.categories.join(" ")
|
||||
readonly property string keywords: modelData.keywords.join(" ")
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue