import QtQuick import QtQuick.Controls import QtQuick.Layouts import QtQuick.LocalStorage import Quickshell import Quickshell.Widgets import Quickshell.Io import Qt.labs.folderlistmodel Window { id: launcher title: "qs-pass" visible: true flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint color: Qt.rgba(0.117, 0.118, 0.180, 0.5) width: 560 height: 360 property string query: "" property string passLocation: "" Process { id: passCopy running: false command: ["pass", "-c", passLocation] stdout: StdioCollector { onStreamFinished: Qt.quit() } } Process { id: userCopy running: false command: ["pass", "-c2", passLocation] } function copyPass() { if(list.currentItem.fileIsDir==true) { folderModel.folder = folderModel.folder+"/"+list.currentItem.fileBaseName } else { passLocation = list.currentItem.filePath passLocation = passLocation.replace("/home/ceres/.password-store/", "") passLocation = passLocation.replace(".gpg", "") passCopy.running = true } } function copyUser() { if(list.currentItem.fileIsDir==true) { folderModel.folder = folderModel.folder+"/"+list.currentItem.fileBaseName } else { passLocation = list.currentItem.filePath passLocation = passLocation.replace("/home/ceres/.password-store/", "") passLocation = passLocation.replace(".gpg", "") userCopy.running = true } } ColumnLayout { anchors.fill: parent spacing: 8 RowLayout { IconImage { Layout.leftMargin: 10 source: Quickshell.iconPath("password-copy", true) Layout.preferredWidth: 25 Layout.preferredHeight: 25 } TextField { id: input Layout.fillWidth: true font.pixelSize: 18 color: "white" focus: true padding: 15 onTextChanged: { launcher.query = text; // reset selection to first item of the filtered list list.currentIndex = folderModel.length > 0 ? 0 : -1; } background: Rectangle { border.width: 0 color: "transparent" } // Quit Keys.onEscapePressed: Qt.quit() Keys.onPressed: event => { const ctrl = event.modifiers & Qt.ControlModifier; if (event.key == Qt.Key_Up || event.key == Qt.Key_P && ctrl) { event.accepted = true; if (list.currentIndex > 0) list.currentIndex--; } else if (event.key == Qt.Key_Down || event.key == Qt.Key_N && ctrl) { event.accepted = true; if (list.currentIndex < list.count - 1) list.currentIndex++; } else if (event.key == Qt.Key_U && ctrl) { event.accepted = true; launcher.copyUser(); } else if ([Qt.Key_Return, Qt.Key_Enter].includes(event.key)) { event.accepted = true; launcher.copyPass(); } else if (event.key == Qt.Key_C && ctrl) { event.accepted = true; Qt.quit(); } } } } FolderListModel { function getQuery() { return "*"+launcher.query+"*" } id: folderModel folder: "file:///home/ceres/.password-store/" showDirsFirst: true caseSensitive: false showDirs: launcher.query === "" ? true : false nameFilters: [ getQuery() ] } ListView { id: list Layout.fillWidth: true Layout.fillHeight: true clip: true model: folderModel currentIndex: folderModel.length > 0 ? 0 : -1 keyNavigationWraps: true preferredHighlightBegin: 0 preferredHighlightEnd: height highlightRangeMode: ListView.ApplyRange highlightMoveDuration: 80 highlight: Rectangle { radius: 4 opacity: 0.45 color: input.palette.highlight } delegate: Item { id: entry required property string fileBaseName required property string filePath required property int index required property bool fileIsDir width: ListView.view.width height: 36 MouseArea { anchors.fill: parent onClicked: list.currentIndex = entry.index onDoubleClicked: launcher.launchSelected() } Row { anchors.fill: parent anchors.margins: 8 spacing: 10 // IconImage { // source: Quickshell.iconPath(modelData.icon, true) // width: 23 // height: 23 // } Text { function genText() { if(fileIsDir==true) { return fileBaseName+"/" } else { return fileBaseName } } id: label color: "white" text: genText() font.pointSize: 13 elide: Text.ElideRight verticalAlignment: Text.AlignVCenter } } } // Enter also works while ListView has focus Keys.onReturnPressed: launcher.copyUser() } } }