diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2026-08-05 23:10:20 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2026-08-05 23:10:20 +0800 |
| commit | fe014347317db230d1d6aaaf11e7efe25fe214b6 (patch) | |
| tree | 702e62d2be29b3f1c09cd638fbac94c0dd322461 | |
| parent | 75019da618ecaa04bfb7f6a4dda62c4c79f6924b (diff) | |
new(launcher): DuckDuckGo
| -rw-r--r-- | config/Launcher.qml | 2 | ||||
| -rw-r--r-- | popups/launcher/components/DuckDuckGo.qml | 138 |
2 files changed, 140 insertions, 0 deletions
diff --git a/config/Launcher.qml b/config/Launcher.qml index efb5dc8..3d8c607 100644 --- a/config/Launcher.qml +++ b/config/Launcher.qml @@ -32,6 +32,8 @@ Singleton { readonly property int maxPreviewLen: 20 + readonly property int duckduckgoSpacing: 25 + readonly property list<Component> widgets: [ // recommanded order: // 1. components with .startswith diff --git a/popups/launcher/components/DuckDuckGo.qml b/popups/launcher/components/DuckDuckGo.qml new file mode 100644 index 0000000..1f3248c --- /dev/null +++ b/popups/launcher/components/DuckDuckGo.qml @@ -0,0 +1,138 @@ +import Quickshell +import QtQuick +import QtQuick.Layouts + +import qs.components +import qs.services +import qs.config + +import core + +IComponent { + property int cursorPosition: SelectionState.cursorPosition + property bool expand: false + + height: valid ? expand ? layout.implicitHeight + (Launcher.duckduckgoSpacing * 2) : Launcher.widgetHeight : 0 + + name: "DuckDuckGo" // subclass of WebSearch in the future + preview: Component { + Icon { + text: "🌐" + } + } + + onInputChanged: { + // TODO: think of this should be part of rs backend .query fn + DuckDuckGo.reset(); + } + + // TODO: decouple all query logic from process -> onInputCleanedChanged and resetting / temp state on speciifc input -> onInputChanged + onInputCleanedChanged: { + if (inputCleaned) + DuckDuckGo.query(inputCleaned); + } + + process: function () { + const valid = DuckDuckGo.ok; + const answer = DuckDuckGo.title || DuckDuckGo.description_html; + return { + valid, + priority: valid, + answer, + predictiveCompletion: valid ? ' is ' + answer : '' + }; + } + exec: function () { + // TODO + // Clip.copy(answer); + } + + IInnerComponent { + anchors.margins: Launcher.duckduckgoSpacing + RowLayout { + id: layout + spacing: Launcher.duckduckgoSpacing + Layout.fillWidth: true + Layout.fillHeight: true + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.preferredWidth: 0 + Layout.maximumWidth: image.maxWidth + Layout.minimumWidth: 0 + + visible: image.status === Image.Ready + + Image { + property real maxWidth: status === Image.Ready ? implicitWidth : 0 + + id: image + anchors.fill: parent + + fillMode: Image.PreserveAspectCrop + + opacity: status === Image.Ready ? 1 : 0 + + source: DuckDuckGo.image + asynchronous: true + + Behavior on opacity { + NumberAnimation { + duration: General.animationDuration / 4 + } + } + + Behavior on maxWidth { + ISpringAnimation {} + } + } + } + + ColumnLayout { + Layout.preferredWidth: 3 + Layout.minimumWidth: 0 + Layout.fillHeight: true + Layout.fillWidth: true + + spacing: Launcher.duckduckgoImageSpacing / 4 + + ITextEdit { + animate: true + + Layout.alignment: Qt.AlignTop + Layout.fillWidth: true + + readOnly: true + renderType: Text.CurveRendering + visible: valid + text: answer + font { + pixelSize: Launcher.widgetFontSize * 1.1 + bold: true + } + } + + ITextEdit { + animate: true + + Layout.fillWidth: true + Layout.fillHeight: true + + readOnly: true + renderType: Text.CurveRendering + visible: valid && DuckDuckGo.title + text: DuckDuckGo.title ? DuckDuckGo.description_html : '' + font { + pixelSize: Launcher.widgetFontSize + } + + TapHandler { + gesturePolicy: TapHandler.DragThreshold + onTapped: expand = !expand + } + } + } + } + } +} |
