pragma ComponentBehavior: Bound import Quickshell import QtQuick import qs.Modules.Launcher.Services import qs.Modules.Launcher.Items import qs.Components import qs.Helpers import qs.Config import qs.Modules as Modules CustomListView { id: root required property CustomTextField search required property PersistentProperties visibilities model: ScriptModel { id: model onValuesChanged: root.currentIndex = 0 } verticalLayoutDirection: ListView.BottomToTop spacing: Appearance.spacing.small orientation: Qt.Vertical implicitHeight: (Config.launcher.sizes.itemHeight + spacing) * Math.min(Config.launcher.maxAppsShown, count) - spacing preferredHighlightBegin: 0 preferredHighlightEnd: height highlightRangeMode: ListView.ApplyRange highlightFollowsCurrentItem: false highlight: CustomRect { radius: 8 color: DynamicColors.palette.m3onSurface opacity: 0.08 y: root.currentItem?.y ?? 0 implicitWidth: root.width implicitHeight: root.currentItem?.implicitHeight ?? 0 Behavior on y { Modules.Anim { duration: Appearance.anim.durations.small easing.bezierCurve: Appearance.anim.curves.expressiveEffects } } } state: { const text = search.text; const prefix = Config.launcher.actionPrefix; if (text.startsWith(prefix)) { for (const action of ["calc", "scheme", "variant"]) if (text.startsWith(`${prefix}${action} `)) return action; return "actions"; } return "apps"; } states: [ State { name: "apps" PropertyChanges { model.values: Apps.search(search.text) root.delegate: appItem } }, State { name: "actions" PropertyChanges { model.values: Actions.query(search.text) root.delegate: actionItem } }, State { name: "calc" PropertyChanges { model.values: [0] root.delegate: calcItem } }, ] transitions: Transition { SequentialAnimation { ParallelAnimation { Modules.Anim { target: root property: "opacity" from: 1 to: 0 duration: Appearance.anim.durations.small easing.bezierCurve: Appearance.anim.curves.expressiveEffects } Modules.Anim { target: root property: "scale" from: 1 to: 0.9 duration: Appearance.anim.durations.small easing.bezierCurve: Appearance.anim.curves.expressiveEffects } } PropertyAction { targets: [model, root] properties: "values,delegate" } ParallelAnimation { Modules.Anim { target: root property: "opacity" from: 0 to: 1 duration: Appearance.anim.durations.small easing.bezierCurve: Appearance.anim.curves.expressiveEffects } Modules.Anim { target: root property: "scale" from: 0.9 to: 1 duration: Appearance.anim.durations.small easing.bezierCurve: Appearance.anim.curves.expressiveEffects } } PropertyAction { targets: [root.add, root.remove] property: "enabled" value: true } } } CustomScrollBar.vertical: CustomScrollBar { flickable: root } add: Transition { enabled: !root.state Modules.Anim { properties: "opacity,scale" from: 0 to: 1 } } remove: Transition { enabled: !root.state Modules.Anim { properties: "opacity,scale" from: 1 to: 0 } } move: Transition { Modules.Anim { property: "y" } Modules.Anim { properties: "opacity,scale" to: 1 } } addDisplaced: Transition { Modules.Anim { property: "y" duration: Appearance.anim.durations.small } Modules.Anim { properties: "opacity,scale" to: 1 } } displaced: Transition { Modules.Anim { property: "y" } Modules.Anim { properties: "opacity,scale" to: 1 } } Component { id: appItem AppItem { visibilities: root.visibilities } } Component { id: actionItem ActionItem { list: root } } Component { id: calcItem CalcItem { list: root } } }