diff --git a/components/mobileshell/qml/widgets/krunner/KRunnerWidget.qml b/components/mobileshell/qml/widgets/krunner/KRunnerWidget.qml deleted file mode 100644 index c5be3f8d..00000000 --- a/components/mobileshell/qml/widgets/krunner/KRunnerWidget.qml +++ /dev/null @@ -1,324 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2014 Aaron Seigo - * SPDX-FileCopyrightText: 2015 Marco Martin - * SPDX-FileCopyrightText: 2021 Devin Lin - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -import QtQuick -import QtQuick.Effects -import QtQuick.Controls as Controls -import QtQuick.Layouts - -import org.kde.plasma.core as PlasmaCore -import org.kde.plasma.components 3.0 as PlasmaComponents -import org.kde.plasma.extras 2.0 as PlasmaExtras - -import org.kde.milou as Milou -import org.kde.kirigami 2.19 as Kirigami - -/** - * Search widget that is embedded into the homescreen. The dimensions of - * the root item is assumed to be the available screen area for applications. - */ -Item { - id: root - - // content margins (background ignores this) - property real topMargin: 0 - property real bottomMargin: 0 - property real leftMargin: 0 - property real rightMargin: 0 - - function startGesture() { - queryField.text = ""; - flickable.contentY = closedContentY; - } - - function updateGestureOffset(yOffset) { - flickable.contentY = Math.max(0, Math.min(closedContentY, flickable.contentY + yOffset)); - } - - // call when the touch gesture has let go - function endGesture() { - flickable.opening ? open() : close(); - } - - // open the search widget (animated) - function open() { - anim.to = openedContentY; - anim.restart(); - } - - // close the search widget (animated) - function close() { - anim.to = closedContentY; - anim.restart(); - } - - // emitted when an item on the ListView is triggered - signal actionTriggered() - - readonly property real closedContentY: Kirigami.Units.gridUnit * 5 - readonly property real openedContentY: 0 - readonly property real openFactor: Math.max(0, Math.min(1, 1 - flickable.contentY / closedContentY)) - readonly property bool isOpen: openFactor != 0 - - Rectangle { - anchors.fill: parent - color: Qt.rgba(0, 0, 0, 0.3) - opacity: root.openFactor - } - - onOpacityChanged: { - if (opacity === 0) { - close(); - } - } - - Keys.onPressed: event => { - if (event.key === Qt.Key_Down) { - listView.forceActiveFocus(); - } - } - - Flickable { - id: flickable - - anchors.fill: parent - anchors.topMargin: root.topMargin - anchors.bottomMargin: root.bottomMargin - anchors.leftMargin: root.leftMargin - anchors.rightMargin: root.rightMargin - - contentHeight: flickable.height + root.closedContentY - contentY: root.closedContentY - property real oldContentY: contentY - property bool opening: false - - onContentYChanged: { - opening = contentY < oldContentY; - oldContentY = contentY; - - if (contentY !== root.openedContentY) { - queryField.focus = false; - } - } - - onMovementEnded: root.endGesture() - - onDraggingChanged: { - if (!dragging) { - root.endGesture(); - } - } - - NumberAnimation on contentY { - id: anim - duration: Kirigami.Units.longDuration * 2 - easing.type: Easing.OutQuad - running: false - onFinished: { - if (anim.to === root.openedContentY) { - queryField.forceActiveFocus(); - } - } - } - - ColumnLayout { - id: column - height: flickable.height - width: flickable.width - - Controls.Control { - opacity: root.openFactor - Layout.fillWidth: true - Layout.maximumWidth: Kirigami.Units.gridUnit * 30 - Layout.alignment: Qt.AlignHCenter - Layout.topMargin: Kirigami.Units.gridUnit - Layout.leftMargin: Kirigami.Units.gridUnit - Layout.rightMargin: Kirigami.Units.gridUnit - - leftPadding: Kirigami.Units.smallSpacing - rightPadding: Kirigami.Units.smallSpacing - topPadding: Kirigami.Units.smallSpacing - bottomPadding: Kirigami.Units.smallSpacing - - background: Item { - - // shadow for search window - MultiEffect { - anchors.fill: parent - source: rectBackground - blurMax: 16 - shadowEnabled: true - shadowVerticalOffset: 1 - shadowOpacity: 0.15 - } - - Rectangle { - id: rectBackground - anchors.fill: parent - color: Kirigami.Theme.backgroundColor - radius: Kirigami.Units.cornerRadius - } - } - - contentItem: RowLayout { - Item { - implicitHeight: queryField.height - implicitWidth: height - Kirigami.Icon { - anchors.fill: parent - anchors.margins: Math.round(Kirigami.Units.smallSpacing) - source: "start-here-symbolic" - } - } - PlasmaComponents.TextField { - id: queryField - Layout.fillWidth: true - placeholderText: i18n("Search…") - inputMethodHints: Qt.ImhNoPredictiveText // don't need to press "enter" to update text - } - } - } - - Controls.ScrollView { - opacity: root.openFactor === 1 ? 1 : 0 - Behavior on opacity { - NumberAnimation { duration: Kirigami.Units.shortDuration } - } - - Layout.fillWidth: true - Layout.fillHeight: listView.contentHeight > availableHeight - - Milou.ResultsListView { - id: listView - queryString: queryField.text - clip: true - Kirigami.Theme.colorSet: Kirigami.Theme.Window - - highlight: activeFocus ? highlightComponent : null - Component { - id: highlightComponent - - PlasmaExtras.Highlight {} - } - - onActivated: { - root.close(); - } - onUpdateQueryString: { - queryField.text = text - queryField.cursorPosition = cursorPosition - } - - delegate: MouseArea { - id: delegate - height: rowLayout.height - width: listView.width - - onClicked: { - listView.currentIndex = model.index; - listView.runCurrentIndex(); - - root.actionTriggered(); - } - hoverEnabled: true - - function activateNextAction() { - queryField.forceActiveFocus(); - queryField.selectAll(); - listView.currentIndex = -1; - } - - Rectangle { - anchors.fill: parent - color: delegate.pressed ? Qt.rgba(255, 255, 255, 0.2) : (delegate.containsMouse ? Qt.rgba(255, 255, 255, 0.05) : "transparent") - Behavior on color { - ColorAnimation { duration: Kirigami.Units.shortDuration } - } - } - - RowLayout { - id: rowLayout - height: Kirigami.Units.gridUnit * 3 - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: Kirigami.Units.gridUnit - anchors.rightMargin: Kirigami.Units.gridUnit - - Kirigami.Icon { - Layout.alignment: Qt.AlignVCenter - source: model.decoration - implicitWidth: Kirigami.Units.iconSizes.medium - implicitHeight: Kirigami.Units.iconSizes.medium - } - - ColumnLayout { - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - spacing: Kirigami.Units.smallSpacing - - PlasmaComponents.Label { - id: title - Layout.fillWidth: true - Layout.leftMargin: Kirigami.Units.smallSpacing * 2 - Layout.rightMargin: Kirigami.Units.gridUnit - - maximumLineCount: 1 - elide: Text.ElideRight - text: typeof modelData !== "undefined" ? modelData : model.display - color: "white" - - font.pointSize: Kirigami.Theme.defaultFont.pointSize - } - PlasmaComponents.Label { - id: subtitle - Layout.fillWidth: true - Layout.leftMargin: Kirigami.Units.smallSpacing * 2 - Layout.rightMargin: Kirigami.Units.gridUnit - - maximumLineCount: 1 - elide: Text.ElideRight - text: model.subtext || "" - color: "white" - opacity: 0.8 - - font.pointSize: Math.round(Kirigami.Theme.defaultFont.pointSize * 0.8) - } - } - - Repeater { - id: actionsRepeater - model: typeof actions !== "undefined" ? actions : [] - - Controls.ToolButton { - icon: modelData.icon || "" - visible: modelData.visible || true - enabled: modelData.enabled || true - - Accessible.role: Accessible.Button - Accessible.name: modelData.text - checkable: checked - checked: delegate.activeAction === index - focus: delegate.activeAction === index - onClicked: delegate.ListView.view.runAction(index) - } - } - } - } - } - } - - MouseArea { - Layout.fillWidth: true - Layout.fillHeight: true - - onClicked: close() - } - } - } -} diff --git a/containments/homescreens/halcyon/package/contents/ui/HomeScreen.qml b/containments/homescreens/halcyon/package/contents/ui/HomeScreen.qml index 173baffb..16ef3a33 100644 --- a/containments/homescreens/halcyon/package/contents/ui/HomeScreen.qml +++ b/containments/homescreens/halcyon/package/contents/ui/HomeScreen.qml @@ -57,6 +57,13 @@ Item { Plasmoid.editMode = false; } + // Pass focus to swipe view child + onFocusChanged: { + if (focus) { + swipeView.focusChild(); + } + } + WindowPlugin.WindowMaximizedTracker { id: windowMaximizedTracker screenGeometry: Plasmoid.containment.screenGeometry diff --git a/containments/homescreens/halcyon/package/contents/ui/SearchWidget.qml b/containments/homescreens/halcyon/package/contents/ui/SearchWidget.qml new file mode 100644 index 00000000..b8569108 --- /dev/null +++ b/containments/homescreens/halcyon/package/contents/ui/SearchWidget.qml @@ -0,0 +1,136 @@ +/* + * SPDX-FileCopyrightText: 2014 Aaron Seigo + * SPDX-FileCopyrightText: 2015 Marco Martin + * SPDX-FileCopyrightText: 2021-2025 Devin Lin + * + * SPDX-License-Identifier: LGPL-2.0-or-later + */ + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls as Controls + +import org.kde.plasma.private.mobileshell as MobileShell +import org.kde.kirigami as Kirigami + +Item { + id: root + + // Content margins + property real topPadding: 0 + property real bottomPadding: 0 + property real leftPadding: 0 + property real rightPadding: 0 + + // Call when the gesture has started + function startGesture() { + krunnerScreen.clearField(); + flickable.contentY = flickable.closedContentY; + } + + // Call when the touch gesture has been updated + function updateGestureOffset(yOffset) { + flickable.contentY = Math.max(0, Math.min(flickable.closedContentY, flickable.contentY + yOffset)); + } + + // Call when the touch gesture has let go + function endGesture() { + flickable.opening ? open() : close(); + } + + // Open the search widget (animated) + function open() { + anim.to = flickable.openedContentY; + anim.restart(); + } + + // Close the search widget (animated) + function close() { + anim.to = flickable.closedContentY; + anim.restart(); + } + + // Emitted when it is requested to force active focus on the parent and release focus on the widget + signal releaseFocusRequested() + + readonly property real openFactor: Math.max(0, Math.min(1, 1 - flickable.contentY / flickable.closedContentY)) + readonly property bool isOpen: openFactor != 0 + + // Pass focus to search screen + onFocusChanged: { + if (focus) { + krunnerScreen.requestFocus(); + } + } + + Rectangle { + id: background + anchors.fill: parent + color: Qt.rgba(0, 0, 0, 0.3) + opacity: root.openFactor + } + + Flickable { + id: flickable + + anchors.fill: parent + anchors.topMargin: root.topPadding + anchors.bottomMargin: root.bottomPadding + anchors.leftMargin: root.leftPadding + anchors.rightMargin: root.rightPadding + + opacity: root.openFactor + + contentHeight: flickable.height + flickable.closedContentY + contentY: flickable.closedContentY + + property real oldContentY: contentY + property bool opening: false + + // The y at which the flickable is fully open + readonly property real closedContentY: Kirigami.Units.gridUnit * 5 + + // The y at which the flickable is fully closed + readonly property real openedContentY: 0 + + onContentYChanged: { + opening = contentY < oldContentY; + oldContentY = contentY; + + if (krunnerScreen.focus) { + // Unfocus from search + root.releaseFocusRequested(); + } + } + + onMovementEnded: root.endGesture() + onDraggingChanged: { + if (!dragging) { + root.endGesture(); + } + } + + NumberAnimation on contentY { + id: anim + duration: Kirigami.Units.longDuration * 2 + easing.type: Easing.OutQuad + running: false + onFinished: { + if (anim.to === flickable.openedContentY) { + krunnerScreen.requestFocus(); + } else { + // Unfocus from search + root.releaseFocusRequested(); + } + } + } + + MobileShell.KRunnerScreen { + id: krunnerScreen + width: parent.width + height: parent.height + + onRequestedClose: root.close(); + } + } +} diff --git a/containments/homescreens/halcyon/package/contents/ui/main.qml b/containments/homescreens/halcyon/package/contents/ui/main.qml index 5dddb3d8..e3c025a0 100644 --- a/containments/homescreens/halcyon/package/contents/ui/main.qml +++ b/containments/homescreens/halcyon/package/contents/ui/main.qml @@ -136,17 +136,17 @@ ContainmentItem { } // search component - MobileShell.KRunnerWidget { + SearchWidget { id: search anchors.fill: parent visible: openFactor > 0 - onActionTriggered: search.close() + topPadding: homeScreen.topMargin + bottomPadding: homeScreen.bottomMargin + leftPadding: homeScreen.leftMargin + rightPadding: homeScreen.rightMargin - topMargin: homeScreen.topMargin - bottomMargin: homeScreen.bottomMargin - leftMargin: homeScreen.leftMargin - rightMargin: homeScreen.rightMargin + onReleaseFocusRequested: halcyonHomeScreen.forceActiveFocus() } } }