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 } } }